aboutsummaryrefslogtreecommitdiff
path: root/weed/command
diff options
context:
space:
mode:
authorhilimd <68371223+hilimd@users.noreply.github.com>2021-06-06 10:13:14 +0800
committerGitHub <noreply@github.com>2021-06-06 10:13:14 +0800
commit97ad3e9d027216d74132652d4d899c7fc7c33ab1 (patch)
tree1301bc441fa12b327c73085ae013219f298e2f39 /weed/command
parentff26e646481a832ff6b75b5efa084935ed1a739b (diff)
parente6ba2f9c372f8f160003dac63d51b6dde0a512de (diff)
downloadseaweedfs-97ad3e9d027216d74132652d4d899c7fc7c33ab1.tar.xz
seaweedfs-97ad3e9d027216d74132652d4d899c7fc7c33ab1.zip
Merge pull request #79 from chrislusf/master
sync
Diffstat (limited to 'weed/command')
-rw-r--r--weed/command/filer_sync.go23
-rw-r--r--weed/command/filer_sync_std.go7
-rw-r--r--weed/command/filer_sync_windows.go12
-rw-r--r--weed/command/fuse.go277
-rw-r--r--weed/command/mount_std.go29
-rw-r--r--weed/command/scaffold.go5
-rw-r--r--weed/command/server.go2
7 files changed, 230 insertions, 125 deletions
diff --git a/weed/command/filer_sync.go b/weed/command/filer_sync.go
index 0f34e5701..52fc0b477 100644
--- a/weed/command/filer_sync.go
+++ b/weed/command/filer_sync.go
@@ -359,16 +359,19 @@ func genProcessFunction(sourcePath string, targetPath string, dataSink sink.Repl
return processEventFn
}
-func buildKey(dataSink sink.ReplicationSink, message *filer_pb.EventNotification, targetPath string, sourceKey util.FullPath, sourcePath string) string {
+func buildKey(dataSink sink.ReplicationSink, message *filer_pb.EventNotification, targetPath string, sourceKey util.FullPath, sourcePath string) (key string) {
if !dataSink.IsIncremental() {
- return util.Join(targetPath, string(sourceKey)[len(sourcePath):])
- }
- var mTime int64
- if message.NewEntry != nil {
- mTime = message.NewEntry.Attributes.Mtime
- } else if message.OldEntry != nil {
- mTime = message.OldEntry.Attributes.Mtime
+ key = util.Join(targetPath, string(sourceKey)[len(sourcePath):])
+ } else {
+ var mTime int64
+ if message.NewEntry != nil {
+ mTime = message.NewEntry.Attributes.Mtime
+ } else if message.OldEntry != nil {
+ mTime = message.OldEntry.Attributes.Mtime
+ }
+ dateKey := time.Unix(mTime, 0).Format("2006-01-02")
+ key = util.Join(targetPath, dateKey, string(sourceKey)[len(sourcePath):])
}
- dateKey := time.Unix(mTime, 0).Format("2006-01-02")
- return util.Join(targetPath, dateKey, string(sourceKey)[len(sourcePath):])
+
+ return escapeKey(key)
}
diff --git a/weed/command/filer_sync_std.go b/weed/command/filer_sync_std.go
new file mode 100644
index 000000000..63851eaf8
--- /dev/null
+++ b/weed/command/filer_sync_std.go
@@ -0,0 +1,7 @@
+// +build !windows
+
+package command
+
+func escapeKey(key string) string {
+ return key
+}
diff --git a/weed/command/filer_sync_windows.go b/weed/command/filer_sync_windows.go
new file mode 100644
index 000000000..3d0c9146e
--- /dev/null
+++ b/weed/command/filer_sync_windows.go
@@ -0,0 +1,12 @@
+package command
+
+import (
+ "strings"
+)
+
+func escapeKey(key string) string {
+ if strings.Contains(key, ":") {
+ return strings.ReplaceAll(key, ":", "")
+ }
+ return key
+}
diff --git a/weed/command/fuse.go b/weed/command/fuse.go
index 0a55e509c..74cf2bb70 100644
--- a/weed/command/fuse.go
+++ b/weed/command/fuse.go
@@ -12,124 +12,178 @@ func init() {
cmdFuse.Run = runFuse // break init cycle
}
-func runFuse(cmd *Command, args []string) bool {
- argsLen := len(args)
- options := []string{}
+type parameter struct {
+ name string
+ value string
+}
- // at least target mount path should be passed
- if argsLen < 1 {
- return false
+func runFuse(cmd *Command, args []string) bool {
+ rawArgs := strings.Join(args, " ")
+ rawArgsLen := len(rawArgs)
+ option := strings.Builder{}
+ options := []parameter{}
+
+ // first parameter
+ i := 0
+ for i = 0; i < rawArgsLen && rawArgs[i] != ' '; i++ {
+ option.WriteByte(rawArgs[i])
}
+ options = append(options, parameter{"arg0", option.String()})
+ option.Reset()
+
+ for i++; i < rawArgsLen; i++ {
+
+ // space separator check for filled option
+ if rawArgs[i] == ' ' {
+ if option.Len() > 0 {
+ options = append(options, parameter{option.String(), "true"})
+ option.Reset()
+ }
+
+ // dash separator read option until next space
+ } else if rawArgs[i] == '-' {
+ for i++; i < rawArgsLen && rawArgs[i] != ' '; i++ {
+ option.WriteByte(rawArgs[i])
+ }
+ options = append(options, parameter{option.String(), "true"})
+ option.Reset()
+
+ // equal separator start option with pending value
+ } else if rawArgs[i] == '=' {
+ name := option.String()
+ option.Reset()
+
+ for i++; i < rawArgsLen && rawArgs[i] != ','; i++ {
+ // double quote separator read option until next double quote
+ if rawArgs[i] == '"' {
+ for i++; i < rawArgsLen && rawArgs[i] != '"'; i++ {
+ option.WriteByte(rawArgs[i])
+ }
+
+ // single quote separator read option until next single quote
+ } else if rawArgs[i] == '\'' {
+ for i++; i < rawArgsLen && rawArgs[i] != '\''; i++ {
+ option.WriteByte(rawArgs[i])
+ }
+
+ // add chars before comma
+ } else if rawArgs[i] != ' ' {
+ option.WriteByte(rawArgs[i])
+ }
+ }
- // first option is always target mount path
- mountOptions.dir = &args[0]
+ options = append(options, parameter{name, option.String()})
+ option.Reset()
- // scan parameters looking for one or more -o options
- // -o options receive parameters on format key=value[,key=value]...
- for i := 0; i < argsLen; i++ {
- if args[i] == "-o" && i+1 <= argsLen {
- options = strings.Split(args[i+1], ",")
- i++
+ // comma separator just read current option
+ } else if rawArgs[i] == ',' {
+ options = append(options, parameter{option.String(), "true"})
+ option.Reset()
+
+ // what is not a separator fill option buffer
+ } else {
+ option.WriteByte(rawArgs[i])
}
}
- // for each option passed with -o
- for _, option := range options {
- // split just first = character
- parts := strings.SplitN(option, "=", 2)
-
- // if doesn't key and value skip
- if len(parts) != 2 {
- continue
- }
+ // get residual option data
+ if option.Len() > 0 {
+ // add value to pending option
+ options = append(options, parameter{option.String(), "true"})
+ option.Reset()
+ }
- key, value := parts[0], parts[1]
-
- // switch key keeping "weed mount" parameters
- switch key {
- case "filer":
- mountOptions.filer = &value
- case "filer.path":
- mountOptions.filerMountRootPath = &value
- case "dirAutoCreate":
- if parsed, err := strconv.ParseBool(value); err != nil {
- mountOptions.dirAutoCreate = &parsed
- } else {
- panic(fmt.Errorf("dirAutoCreate: %s", err))
- }
- case "collection":
- mountOptions.collection = &value
- case "replication":
- mountOptions.replication = &value
- case "disk":
- mountOptions.diskType = &value
- case "ttl":
- if parsed, err := strconv.ParseInt(value, 0, 32); err != nil {
- intValue := int(parsed)
- mountOptions.ttlSec = &intValue
- } else {
- panic(fmt.Errorf("ttl: %s", err))
- }
- case "chunkSizeLimitMB":
- if parsed, err := strconv.ParseInt(value, 0, 32); err != nil {
- intValue := int(parsed)
- mountOptions.chunkSizeLimitMB = &intValue
- } else {
- panic(fmt.Errorf("chunkSizeLimitMB: %s", err))
- }
- case "concurrentWriters":
- if parsed, err := strconv.ParseInt(value, 0, 32); err != nil {
- intValue := int(parsed)
- mountOptions.concurrentWriters = &intValue
- } else {
- panic(fmt.Errorf("concurrentWriters: %s", err))
- }
- case "cacheDir":
- mountOptions.cacheDir = &value
- case "cacheCapacityMB":
- if parsed, err := strconv.ParseInt(value, 0, 64); err != nil {
- mountOptions.cacheSizeMB = &parsed
- } else {
- panic(fmt.Errorf("cacheCapacityMB: %s", err))
- }
- case "dataCenter":
- mountOptions.dataCenter = &value
- case "allowOthers":
- if parsed, err := strconv.ParseBool(value); err != nil {
- mountOptions.allowOthers = &parsed
- } else {
- panic(fmt.Errorf("allowOthers: %s", err))
- }
- case "umask":
- mountOptions.umaskString = &value
- case "nonempty":
- if parsed, err := strconv.ParseBool(value); err != nil {
- mountOptions.nonempty = &parsed
- } else {
- panic(fmt.Errorf("nonempty: %s", err))
- }
- case "volumeServerAccess":
- mountOptions.volumeServerAccess = &value
- case "map.uid":
- mountOptions.uidMap = &value
- case "map.gid":
- mountOptions.gidMap = &value
- case "readOnly":
- if parsed, err := strconv.ParseBool(value); err != nil {
- mountOptions.readOnly = &parsed
- } else {
- panic(fmt.Errorf("readOnly: %s", err))
- }
- case "cpuprofile":
- mountCpuProfile = &value
- case "memprofile":
- mountMemProfile = &value
- case "readRetryTime":
- if parsed, err := time.ParseDuration(value); err != nil {
- mountReadRetryTime = &parsed
- } else {
- panic(fmt.Errorf("readRetryTime: %s", err))
- }
+ // scan each parameter
+ for i := 0; i < len(options); i++ {
+ parameter := options[i]
+
+ switch parameter.name {
+ case "arg0":
+ mountOptions.dir = &parameter.value
+ case "filer":
+ mountOptions.filer = &parameter.value
+ case "filer.path":
+ mountOptions.filerMountRootPath = &parameter.value
+ case "dirAutoCreate":
+ if parsed, err := strconv.ParseBool(parameter.value); err != nil {
+ mountOptions.dirAutoCreate = &parsed
+ } else {
+ panic(fmt.Errorf("dirAutoCreate: %s", err))
+ }
+ case "collection":
+ mountOptions.collection = &parameter.value
+ case "replication":
+ mountOptions.replication = &parameter.value
+ case "disk":
+ mountOptions.diskType = &parameter.value
+ case "ttl":
+ if parsed, err := strconv.ParseInt(parameter.value, 0, 32); err != nil {
+ intValue := int(parsed)
+ mountOptions.ttlSec = &intValue
+ } else {
+ panic(fmt.Errorf("ttl: %s", err))
+ }
+ case "chunkSizeLimitMB":
+ if parsed, err := strconv.ParseInt(parameter.value, 0, 32); err != nil {
+ intValue := int(parsed)
+ mountOptions.chunkSizeLimitMB = &intValue
+ } else {
+ panic(fmt.Errorf("chunkSizeLimitMB: %s", err))
+ }
+ case "concurrentWriters":
+ i++
+ if parsed, err := strconv.ParseInt(parameter.value, 0, 32); err != nil {
+ intValue := int(parsed)
+ mountOptions.concurrentWriters = &intValue
+ } else {
+ panic(fmt.Errorf("concurrentWriters: %s", err))
+ }
+ case "cacheDir":
+ mountOptions.cacheDir = &parameter.value
+ case "cacheCapacityMB":
+ if parsed, err := strconv.ParseInt(parameter.value, 0, 64); err != nil {
+ mountOptions.cacheSizeMB = &parsed
+ } else {
+ panic(fmt.Errorf("cacheCapacityMB: %s", err))
+ }
+ case "dataCenter":
+ mountOptions.dataCenter = &parameter.value
+ case "allowOthers":
+ if parsed, err := strconv.ParseBool(parameter.value); err != nil {
+ mountOptions.allowOthers = &parsed
+ } else {
+ panic(fmt.Errorf("allowOthers: %s", err))
+ }
+ case "umask":
+ mountOptions.umaskString = &parameter.value
+ case "nonempty":
+ if parsed, err := strconv.ParseBool(parameter.value); err != nil {
+ mountOptions.nonempty = &parsed
+ } else {
+ panic(fmt.Errorf("nonempty: %s", err))
+ }
+ case "volumeServerAccess":
+ mountOptions.volumeServerAccess = &parameter.value
+ case "map.uid":
+ mountOptions.uidMap = &parameter.value
+ case "map.gid":
+ mountOptions.gidMap = &parameter.value
+ case "readOnly":
+ if parsed, err := strconv.ParseBool(parameter.value); err != nil {
+ mountOptions.readOnly = &parsed
+ } else {
+ panic(fmt.Errorf("readOnly: %s", err))
+ }
+ case "cpuprofile":
+ mountCpuProfile = &parameter.value
+ case "memprofile":
+ mountMemProfile = &parameter.value
+ case "readRetryTime":
+ if parsed, err := time.ParseDuration(parameter.value); err != nil {
+ mountReadRetryTime = &parsed
+ } else {
+ panic(fmt.Errorf("readRetryTime: %s", err))
+ }
}
}
@@ -160,6 +214,9 @@ var cmdFuse = &Command{
mount -t fuse./home/user/bin/weed fuse /mnt -o "filer=localhost:8888,filer.path=/"
mount -t fuse "/home/user/bin/weed#fuse" /mnt -o "filer=localhost:8888,filer.path=/"
+ To pass more than one parameter use quotes, example:
+ mount -t weed fuse /mnt -o "filer='192.168.0.1:8888,192.168.0.2:8888',filer.path=/"
+
To check valid options look "weed mount --help"
`,
}
diff --git a/weed/command/mount_std.go b/weed/command/mount_std.go
index e72a2f2cf..dce2197d6 100644
--- a/weed/command/mount_std.go
+++ b/weed/command/mount_std.go
@@ -5,15 +5,18 @@ package command
import (
"context"
"fmt"
- "github.com/chrislusf/seaweedfs/weed/storage/types"
"os"
"os/user"
"path"
+ "path/filepath"
"runtime"
"strconv"
"strings"
+ "syscall"
"time"
+ "github.com/chrislusf/seaweedfs/weed/storage/types"
+
"github.com/chrislusf/seaweedfs/weed/filesys/meta_cache"
"github.com/seaweedfs/fuse"
@@ -49,6 +52,21 @@ func runMount(cmd *Command, args []string) bool {
return RunMount(&mountOptions, os.FileMode(umask))
}
+func getParentInode(mountDir string) (uint64, error) {
+ parentDir := filepath.Clean(filepath.Join(mountDir, ".."))
+ fi, err := os.Stat(parentDir)
+ if err != nil {
+ return 0, err
+ }
+
+ stat, ok := fi.Sys().(*syscall.Stat_t)
+ if !ok {
+ return 0, nil
+ }
+
+ return stat.Ino, nil
+}
+
func RunMount(option *MountOptions, umask os.FileMode) bool {
filers := strings.Split(*option.filer, ",")
@@ -85,13 +103,19 @@ func RunMount(option *MountOptions, umask os.FileMode) bool {
filerMountRootPath := *option.filerMountRootPath
dir := util.ResolvePath(*option.dir)
- chunkSizeLimitMB := *mountOptions.chunkSizeLimitMB
+ parentInode, err := getParentInode(dir)
+ if err != nil {
+ glog.Errorf("failed to retrieve inode for parent directory of %s: %v", dir, err)
+ return true
+ }
fmt.Printf("This is SeaweedFS version %s %s %s\n", util.Version(), runtime.GOOS, runtime.GOARCH)
if dir == "" {
fmt.Printf("Please specify the mount directory via \"-dir\"")
return false
}
+
+ chunkSizeLimitMB := *mountOptions.chunkSizeLimitMB
if chunkSizeLimitMB <= 0 {
fmt.Printf("Please specify a reasonable buffer size.")
return false
@@ -199,6 +223,7 @@ func RunMount(option *MountOptions, umask os.FileMode) bool {
MountMode: mountMode,
MountCtime: fileInfo.ModTime(),
MountMtime: time.Now(),
+ MountParentInode: parentInode,
Umask: umask,
VolumeServerAccess: *mountOptions.volumeServerAccess,
Cipher: cipher,
diff --git a/weed/command/scaffold.go b/weed/command/scaffold.go
index 806e18fbc..2d6729bd3 100644
--- a/weed/command/scaffold.go
+++ b/weed/command/scaffold.go
@@ -356,13 +356,14 @@ sub_url = "rabbit://myqueue"
REPLICATION_TOML_EXAMPLE = `
# A sample TOML config file for replicating SeaweedFS filer
-# Used with "weed filer.replicate"
+# Used with "weed filer.backup"
+# Using with "weed filer.replicate" is deprecated.
# Put this file to one of the location, with descending priority
# ./replication.toml
# $HOME/.seaweedfs/replication.toml
# /etc/seaweedfs/replication.toml
-[source.filer]
+[source.filer] # deprecated. Only useful with "weed filer.replicate"
enabled = true
grpcAddress = "localhost:18888"
# all files under this directory tree are replicated.
diff --git a/weed/command/server.go b/weed/command/server.go
index d0020d33b..d2bd6466e 100644
--- a/weed/command/server.go
+++ b/weed/command/server.go
@@ -245,7 +245,7 @@ func runServer(cmd *Command, args []string) bool {
// start volume server
if *isStartingVolumeServer {
- minFreeSpaces := util.MustParseMinFreeSpace(*minFreeSpace, *minFreeSpacePercent)
+ minFreeSpaces := util.MustParseMinFreeSpace(*volumeMinFreeSpace, *volumeMinFreeSpacePercent)
go serverOptions.v.startVolumeServer(*volumeDataFolders, *volumeMaxDataVolumeCounts, *serverWhiteListOption, minFreeSpaces)
}