diff --git a/go/weed/filer.go b/go/weed/filer.go new file mode 100644 index 000000000..d7d028d50 --- /dev/null +++ b/go/weed/filer.go @@ -0,0 +1,79 @@ +package main + +import ( + "code.google.com/p/weed-fs/go/glog" + "code.google.com/p/weed-fs/go/util" + "code.google.com/p/weed-fs/go/weed/weed_server" + "net/http" + "os" + "strconv" + "time" +) + +var ( + f FilerOptions +) + +type FilerOptions struct { + master *string + port *int + collection *string + defaultReplicaPlacement *string + dir *string +} + +func init() { + cmdFiler.Run = runFiler // break init cycle + f.master = cmdFiler.Flag.String("master", "localhost:9333", "master server location") + f.collection = cmdFiler.Flag.String("collection", "", "all data will be stored in this collection") + f.port = cmdFiler.Flag.Int("port", 8888, "filer server http listen port") + f.dir = cmdFiler.Flag.String("dir", os.TempDir(), "directory to store meta data") + f.defaultReplicaPlacement = cmdFiler.Flag.String("defaultReplicaPlacement", "000", "Default replication type if not specified.") +} + +var cmdFiler = &Command{ + UsageLine: "filer -port=8888 -dir=/tmp -master=", + Short: "start a file server that points to a master server", + Long: `start a file server which accepts REST operation for any files. + + //create or overwrite the file, the directories /path/to will be automatically created + POST /path/to/file + //get the file content + GET /path/to/file + //create or overwrite the file, the filename in the multipart request will be used + POST /path/to/ + //return a json format subdirectory and files listing + GET /path/to/ + + Current mapping metadata store is local embedded leveldb. + It should be highly scalable to hundreds of millions of files on a modest machine. + + Future we will ensure it can avoid of being SPOF. + + `, +} + +func runFiler(cmd *Command, args []string) bool { + if err := util.TestFolderWritable(*f.dir); err != nil { + glog.Fatalf("Check Meta Folder (-dir) Writable %s : %s", *f.dir, err) + } + + r := http.NewServeMux() + _, nfs_err := weed_server.NewFilerServer(r, *f.port, *f.master, *f.dir, *f.collection) + if nfs_err != nil { + glog.Fatalf(nfs_err.Error()) + } + glog.V(0).Infoln("Start Weed Filer", util.VERSION, "at port", strconv.Itoa(*f.port)) + filerListener, e := util.NewListener( + ":"+strconv.Itoa(*f.port), + time.Duration(10)*time.Second, + ) + if e != nil { + glog.Fatalf(e.Error()) + } + if e := http.Serve(filerListener, r); e != nil { + glog.Fatalf("Filer Fail to serve:%s", e.Error()) + } + + return true +} diff --git a/go/weed/server.go b/go/weed/server.go index c3dca3f4b..87b541fd3 100644 --- a/go/weed/server.go +++ b/go/weed/server.go @@ -14,6 +14,10 @@ import ( "time" ) +var ( + filer FilerOptions +) + func init() { cmdServer.Run = runServer // break init cycle } @@ -28,10 +32,6 @@ var cmdServer = &Command{ The servers are the same as starting them separately. So other volume servers can use this embedded master server also. - However, this may change very soon. - The target is to start both volume server and embedded master server on all instances, - and use a leader election process to auto choose a master server. - `, } @@ -53,23 +53,32 @@ var ( volumeDataFolders = cmdServer.Flag.String("dir", os.TempDir(), "directories to store data files. dir[,dir]...") volumeMaxDataVolumeCounts = cmdServer.Flag.String("max", "7", "maximum numbers of volumes, count[,count]...") volumePulse = cmdServer.Flag.Int("pulseSeconds", 5, "number of seconds between heartbeats") + isStartingFiler = cmdServer.Flag.Bool("filer", false, "whether to start filer") serverWhiteList []string ) +func init() { + filer.master = cmdServer.Flag.String("filer.master", "", "default to current master server") + filer.collection = cmdServer.Flag.String("filer.collection", "", "all data will be stored in this collection") + filer.port = cmdServer.Flag.Int("filer.port", 8888, "filer server http listen port") + filer.dir = cmdServer.Flag.String("filer.dir", "", "directory to store meta data, default to a 'filer' sub directory of what -mdir is specified") + filer.defaultReplicaPlacement = cmdServer.Flag.String("filer.defaultReplicaPlacement", "", "Default replication type if not specified during runtime.") +} + func runServer(cmd *Command, args []string) bool { + + *filer.master = *serverIp + ":" + strconv.Itoa(*masterPort) + + if *filer.defaultReplicaPlacement == "" { + *filer.defaultReplicaPlacement = *masterDefaultReplicaPlacement + } + if *serverMaxCpu < 1 { *serverMaxCpu = runtime.NumCPU() } runtime.GOMAXPROCS(*serverMaxCpu) - if *masterMetaFolder == "" { - *masterMetaFolder = *volumeDataFolders - } - if err := util.TestFolderWritable(*masterMetaFolder); err != nil { - glog.Fatalf("Check Meta Folder (-mdir) Writable %s : %s", *masterMetaFolder, err) - } - folders := strings.Split(*volumeDataFolders, ",") maxCountStrings := strings.Split(*volumeMaxDataVolumeCounts, ",") maxCounts := make([]int, 0) @@ -89,6 +98,20 @@ func runServer(cmd *Command, args []string) bool { } } + if *masterMetaFolder == "" { + *masterMetaFolder = folders[0] + } + if *filer.dir == "" { + *filer.dir = *masterMetaFolder + "/filer" + os.MkdirAll(*filer.dir, 0700) + } + if err := util.TestFolderWritable(*masterMetaFolder); err != nil { + glog.Fatalf("Check Meta Folder (-mdir=\"%s\") Writable: %s", *masterMetaFolder, err) + } + if err := util.TestFolderWritable(*filer.dir); err != nil { + glog.Fatalf("Check Mapping Meta Folder (-filer.dir=\"%s\") Writable: %s", *filer.dir, err) + } + if *volumePublicUrl == "" { *volumePublicUrl = *serverIp + ":" + strconv.Itoa(*volumePort) } @@ -96,24 +119,26 @@ func runServer(cmd *Command, args []string) bool { serverWhiteList = strings.Split(*serverWhiteListOption, ",") } - go func() { - r := http.NewServeMux() - _, nfs_err := weed_server.NewFilerServer(r, *serverIp+":"+strconv.Itoa(*masterPort), *volumeDataFolders) - if nfs_err != nil { - glog.Fatalf(nfs_err.Error()) - } - glog.V(0).Infoln("Start Weed Filer", util.VERSION, "at port", *serverIp+":"+strconv.Itoa(8888)) - filerListener, e := util.NewListener( - *serverIp+":"+strconv.Itoa(8888), - time.Duration(*serverTimeout)*time.Second, - ) - if e != nil { - glog.Fatalf(e.Error()) - } - if e := http.Serve(filerListener, r); e != nil { - glog.Fatalf("Master Fail to serve:%s", e.Error()) - } - }() + if *isStartingFiler { + go func() { + r := http.NewServeMux() + _, nfs_err := weed_server.NewFilerServer(r, *filer.port, *filer.master, *filer.dir, *filer.collection) + if nfs_err != nil { + glog.Fatalf(nfs_err.Error()) + } + glog.V(0).Infoln("Start Weed Filer", util.VERSION, "at port", strconv.Itoa(*filer.port)) + filerListener, e := util.NewListener( + ":"+strconv.Itoa(*filer.port), + time.Duration(10)*time.Second, + ) + if e != nil { + glog.Fatalf(e.Error()) + } + if e := http.Serve(filerListener, r); e != nil { + glog.Fatalf("Filer Fail to serve:%s", e.Error()) + } + }() + } var raftWaitForMaster sync.WaitGroup var volumeWait sync.WaitGroup diff --git a/go/weed/weed.go b/go/weed/weed.go index 2a5a040c1..441ac9e61 100644 --- a/go/weed/weed.go +++ b/go/weed/weed.go @@ -21,6 +21,7 @@ var server *string var commands = []*Command{ cmdBenchmark, cmdCompact, + cmdFiler, cmdFix, cmdServer, cmdMaster, diff --git a/go/weed/weed_server/filer_server.go b/go/weed/weed_server/filer_server.go index c80b3b56f..7e9c644dd 100644 --- a/go/weed/weed_server/filer_server.go +++ b/go/weed/weed_server/filer_server.go @@ -1,11 +1,11 @@ package weed_server import ( - "code.google.com/p/weed-fs/go/glog" "errors" "github.com/syndtr/goleveldb/leveldb" "github.com/syndtr/goleveldb/leveldb/util" "net/http" + "strconv" "strings" ) @@ -25,11 +25,11 @@ type FilerServer struct { db *leveldb.DB } -func NewFilerServer(r *http.ServeMux, master string, dir string) (fs *FilerServer, err error) { +func NewFilerServer(r *http.ServeMux, port int, master string, dir string, collection string) (fs *FilerServer, err error) { fs = &FilerServer{ master: master, - collection: "", - port: ":8888", + collection: collection, + port: ":" + strconv.Itoa(port), } if fs.db, err = leveldb.OpenFile(dir, nil); err != nil { @@ -38,8 +38,6 @@ func NewFilerServer(r *http.ServeMux, master string, dir string) (fs *FilerServe r.HandleFunc("/", fs.filerHandler) - glog.V(0).Infoln("file server started on port ", fs.port) - return fs, nil }