diff --git a/weed-fs/src/cmd/weedmaster/weedmaster.go b/weed-fs/src/cmd/weedmaster/weedmaster.go index b41a5d437..13733f2ca 100644 --- a/weed-fs/src/cmd/weedmaster/weedmaster.go +++ b/weed-fs/src/cmd/weedmaster/weedmaster.go @@ -74,7 +74,8 @@ func writeJson(w http.ResponseWriter, r *http.Request, obj interface{}) { func main() { flag.Parse() - mapper = directory.NewMapper(*metaFolder, "directory", uint32(*volumeSizeLimitMB*1024*1024)) + log.Println("Volume Size Limit is", *volumeSizeLimitMB, "MB") + mapper = directory.NewMapper(*metaFolder, "directory", uint64(*volumeSizeLimitMB)*1024*1024) http.HandleFunc("/dir/assign", dirAssignHandler) http.HandleFunc("/dir/lookup", dirLookupHandler) http.HandleFunc("/dir/join", dirJoinHandler) diff --git a/weed-fs/src/cmd/weedvolume/weedvolume.go b/weed-fs/src/cmd/weedvolume/weedvolume.go index 88ad01c0d..b026189c0 100644 --- a/weed-fs/src/cmd/weedvolume/weedvolume.go +++ b/weed-fs/src/cmd/weedvolume/weedvolume.go @@ -1,157 +1,168 @@ package main import ( - "storage" - "flag" - "fmt" - "http" - "json" - "log" - "mime" - "rand" - "strconv" - "strings" - "time" + "storage" + "flag" + "fmt" + "http" + "json" + "log" + "mime" + "rand" + "strconv" + "strings" + "time" ) var ( - port = flag.Int("port", 8080, "http listen port") - chunkFolder = flag.String("dir", "/tmp", "data directory to store files") - volumes = flag.String("volumes", "0,1-3,4", "comma-separated list of volume ids or range of ids") - publicUrl = flag.String("publicUrl", "localhost:8080", "public url to serve data read") - metaServer = flag.String("mserver", "localhost:9333", "master directory server to store mappings") - IsDebug = flag.Bool("debug", false, "enable debug mode") - pulse = flag.Int("pulseSeconds", 5, "number of seconds between heartbeats") + port = flag.Int("port", 8080, "http listen port") + chunkFolder = flag.String("dir", "/tmp", "data directory to store files") + volumes = flag.String("volumes", "0,1-3,4", "comma-separated list of volume ids or range of ids") + publicUrl = flag.String("publicUrl", "localhost:8080", "public url to serve data read") + metaServer = flag.String("mserver", "localhost:9333", "master directory server to store mappings") + IsDebug = flag.Bool("debug", false, "enable debug mode") + pulse = flag.Int("pulseSeconds", 5, "number of seconds between heartbeats") - store *storage.Store + store *storage.Store ) func statusHandler(w http.ResponseWriter, r *http.Request) { - writeJson(w, r, store.Status()) + writeJson(w, r, store.Status()) } func addVolumeHandler(w http.ResponseWriter, r *http.Request) { - store.AddVolume(r.FormValue("volume")) - writeJson(w, r, store.Status()) + store.AddVolume(r.FormValue("volume")) + writeJson(w, r, store.Status()) } func storeHandler(w http.ResponseWriter, r *http.Request) { - switch r.Method { - case "GET": - GetHandler(w, r) - case "DELETE": - DeleteHandler(w, r) - case "POST": - PostHandler(w, r) - } + switch r.Method { + case "GET": + GetHandler(w, r) + case "DELETE": + DeleteHandler(w, r) + case "POST": + PostHandler(w, r) + } } func GetHandler(w http.ResponseWriter, r *http.Request) { - n := new(storage.Needle) - vid, fid, ext := parseURLPath(r.URL.Path) - volumeId, _ := strconv.Atoui64(vid) - n.ParsePath(fid) + n := new(storage.Needle) + vid, fid, ext := parseURLPath(r.URL.Path) + volumeId, _ := strconv.Atoui64(vid) + n.ParsePath(fid) - if *IsDebug { - log.Println("volume", volumeId, "reading", n) - } - cookie := n.Cookie - count, e := store.Read(volumeId, n) - if *IsDebug { - log.Println("read bytes", count, "error", e) - } - if n.Cookie != cookie { - log.Println("request with unmaching cookie from ", r.RemoteAddr, "agent", r.UserAgent()) - return - } - if ext != "" { - w.Header().Set("Content-Type", mime.TypeByExtension(ext)) - } - w.Write(n.Data) + if *IsDebug { + log.Println("volume", volumeId, "reading", n) + } + cookie := n.Cookie + count, e := store.Read(volumeId, n) + if *IsDebug { + log.Println("read bytes", count, "error", e) + } + if n.Cookie != cookie { + log.Println("request with unmaching cookie from ", r.RemoteAddr, "agent", r.UserAgent()) + return + } + if ext != "" { + w.Header().Set("Content-Type", mime.TypeByExtension(ext)) + } + w.Write(n.Data) } func PostHandler(w http.ResponseWriter, r *http.Request) { - vid, _, _ := parseURLPath(r.URL.Path) - volumeId, e := strconv.Atoui64(vid) - if e != nil { - writeJson(w, r, e) - } else { - ret := store.Write(volumeId, storage.NewNeedle(r)) - m := make(map[string]uint32) - m["size"] = ret - writeJson(w, r, m) - } + vid, _, _ := parseURLPath(r.URL.Path) + volumeId, e := strconv.Atoui64(vid) + if e != nil { + writeJson(w, r, e) + } else { + ret := store.Write(volumeId, storage.NewNeedle(r)) + m := make(map[string]uint32) + m["size"] = ret + writeJson(w, r, m) + } } func DeleteHandler(w http.ResponseWriter, r *http.Request) { - n := new(storage.Needle) - vid, fid, _ := parseURLPath(r.URL.Path) - volumeId, _ := strconv.Atoui64(vid) - n.ParsePath(fid) + n := new(storage.Needle) + vid, fid, _ := parseURLPath(r.URL.Path) + volumeId, _ := strconv.Atoui64(vid) + n.ParsePath(fid) - cookie := n.Cookie - count, _ := store.Read(volumeId, n) + if *IsDebug { + log.Println("deleting", n) + } - if n.Cookie != cookie { - log.Println("delete with unmaching cookie from ", r.RemoteAddr, "agent", r.UserAgent()) - return - } + cookie := n.Cookie + count, ok := store.Read(volumeId, n) - n.Size = 0 - store.Write(volumeId, n) - m := make(map[string]uint32) - m["size"] = uint32(count) - writeJson(w, r, m) + if ok!=nil { + m := make(map[string]uint32) + m["size"] = 0 + writeJson(w, r, m) + return + } + + if n.Cookie != cookie { + log.Println("delete with unmaching cookie from ", r.RemoteAddr, "agent", r.UserAgent()) + return + } + + n.Size = 0 + store.Delete(volumeId, n) + m := make(map[string]uint32) + m["size"] = uint32(count) + writeJson(w, r, m) } func writeJson(w http.ResponseWriter, r *http.Request, obj interface{}) { - w.Header().Set("Content-Type", "application/javascript") - bytes, _ := json.Marshal(obj) - callback := r.FormValue("callback") - if callback == "" { - w.Write(bytes) - } else { - w.Write([]uint8(callback)) - w.Write([]uint8("(")) - fmt.Fprint(w, string(bytes)) - w.Write([]uint8(")")) - } - //log.Println("JSON Response", string(bytes)) + w.Header().Set("Content-Type", "application/javascript") + bytes, _ := json.Marshal(obj) + callback := r.FormValue("callback") + if callback == "" { + w.Write(bytes) + } else { + w.Write([]uint8(callback)) + w.Write([]uint8("(")) + fmt.Fprint(w, string(bytes)) + w.Write([]uint8(")")) + } + //log.Println("JSON Response", string(bytes)) } func parseURLPath(path string) (vid, fid, ext string) { - sepIndex := strings.LastIndex(path, "/") - commaIndex := strings.LastIndex(path[sepIndex:], ",") - if commaIndex <= 0 { - log.Println("unknown file id", path[sepIndex+1:]) - return - } - dotIndex := strings.LastIndex(path[sepIndex:], ".") - vid = path[sepIndex+1 : commaIndex] - fid = path[commaIndex+1:] - ext = "" - if dotIndex > 0 { - fid = path[commaIndex+1 : dotIndex] - ext = path[dotIndex+1:] - } - return + sepIndex := strings.LastIndex(path, "/") + commaIndex := strings.LastIndex(path[sepIndex:], ",") + if commaIndex <= 0 { + log.Println("unknown file id", path[sepIndex+1:]) + return + } + dotIndex := strings.LastIndex(path[sepIndex:], ".") + vid = path[sepIndex+1 : commaIndex] + fid = path[commaIndex+1:] + ext = "" + if dotIndex > 0 { + fid = path[commaIndex+1 : dotIndex] + ext = path[dotIndex+1:] + } + return } func main() { - flag.Parse() - //TODO: now default to 1G, this value should come from server? - store = storage.NewStore(*port, *publicUrl, *chunkFolder, *volumes) - defer store.Close() - http.HandleFunc("/", storeHandler) - http.HandleFunc("/status", statusHandler) - http.HandleFunc("/add_volume", addVolumeHandler) + flag.Parse() + //TODO: now default to 1G, this value should come from server? + store = storage.NewStore(*port, *publicUrl, *chunkFolder, *volumes) + defer store.Close() + http.HandleFunc("/", storeHandler) + http.HandleFunc("/status", statusHandler) + http.HandleFunc("/add_volume", addVolumeHandler) - go func() { - for { - store.Join(*metaServer) - ns := int64(*pulse) * 1e9 - time.Sleep(ns + rand.Int63()%ns) - } - }() - log.Println("store joined at", *metaServer) + go func() { + for { + store.Join(*metaServer) + ns := int64(*pulse) * 1e9 + time.Sleep(ns + rand.Int63()%ns) + } + }() + log.Println("store joined at", *metaServer) - log.Println("Start storage service at http://127.0.0.1:" + strconv.Itoa(*port), "public url", *publicUrl) - e := http.ListenAndServe(":"+strconv.Itoa(*port), nil) - if e != nil { - log.Fatalf("Fail to start:", e.String()) - } + log.Println("Start storage service at http://127.0.0.1:"+strconv.Itoa(*port), "public url", *publicUrl) + e := http.ListenAndServe(":"+strconv.Itoa(*port), nil) + if e != nil { + log.Fatalf("Fail to start:", e.String()) + } } diff --git a/weed-fs/src/pkg/directory/volume_mapping.go b/weed-fs/src/pkg/directory/volume_mapping.go index b4862d70f..0db282d5c 100644 --- a/weed-fs/src/pkg/directory/volume_mapping.go +++ b/weed-fs/src/pkg/directory/volume_mapping.go @@ -36,14 +36,14 @@ type Mapper struct { FileIdSequence uint64 fileIdCounter uint64 - volumeSizeLimit uint32 + volumeSizeLimit uint64 } func NewMachine(server, publicUrl string, volumes []storage.VolumeInfo) *Machine { return &Machine{Server: MachineInfo{Url: server, PublicUrl: publicUrl}, Volumes: volumes} } -func NewMapper(dirname string, filename string, volumeSizeLimit uint32) (m *Mapper) { +func NewMapper(dirname string, filename string, volumeSizeLimit uint64) (m *Mapper) { m = &Mapper{dir: dirname, fileName: filename} m.vid2machineId = make(map[uint32]int) m.volumeSizeLimit = volumeSizeLimit @@ -96,6 +96,7 @@ func (m *Mapper) Get(vid uint32) (*Machine, os.Error) { } func (m *Mapper) Add(machine Machine) { //check existing machine, linearly + log.Println("Adding machine", machine.Server.Url) m.lock.Lock() foundExistingMachineId := -1 for index, entry := range m.Machines { @@ -115,14 +116,13 @@ func (m *Mapper) Add(machine Machine) { //add to vid2machineId map, and Writers array for _, v := range machine.Volumes { - //log.Println("Setting volume", v.Id, "to", machine.Server.Url) m.vid2machineId[v.Id] = machineId + 1 //use base 1 indexed, to detect not found cases } - //setting Writers, copy-on-write because of possible updating + //setting Writers, copy-on-write because of possible updating, this needs some future work! var writers []uint32 for _, machine_entry := range m.Machines { for _, v := range machine_entry.Volumes { - if v.Size < int64(m.volumeSizeLimit) { + if uint64(v.Size) < m.volumeSizeLimit { writers = append(writers, v.Id) } } diff --git a/weed-fs/src/pkg/storage/store.go b/weed-fs/src/pkg/storage/store.go index 221e9f565..f70321ab1 100644 --- a/weed-fs/src/pkg/storage/store.go +++ b/weed-fs/src/pkg/storage/store.go @@ -92,7 +92,10 @@ func (s *Store) Close() { } } func (s *Store) Write(i uint64, n *Needle) uint32 { - return s.volumes[i].write(n) + return s.volumes[i].write(n) +} +func (s *Store) Delete(i uint64, n *Needle) uint32 { + return s.volumes[i].delete(n) } func (s *Store) Read(i uint64, n *Needle) (int, os.Error) { return s.volumes[i].read(n) diff --git a/weed-fs/src/pkg/storage/volume.go b/weed-fs/src/pkg/storage/volume.go index 438a0f56e..08c97af9d 100644 --- a/weed-fs/src/pkg/storage/volume.go +++ b/weed-fs/src/pkg/storage/volume.go @@ -9,7 +9,7 @@ import ( ) const ( - SuperBlockSize = 8 + SuperBlockSize = 8 ) type Volume struct { @@ -69,6 +69,19 @@ func (v *Volume) write(n *Needle) uint32 { } return ret } +func (v *Volume) delete(n *Needle) uint32 { + v.accessLock.Lock() + defer v.accessLock.Unlock() + nv, ok := v.nm.Get(n.Key) + //log.Println("key", n.Key, "volume offset", nv.Offset, "data_size", n.Size, "cached size", nv.Size) + if ok { + v.nm.Delete(n.Key) + v.dataFile.Seek(int64(nv.Offset*8), 0) + n.Append(v.dataFile) + return nv.Size + } + return 0 +} func (v *Volume) read(n *Needle) (int, os.Error) { v.accessLock.Lock() defer v.accessLock.Unlock() @@ -79,8 +92,3 @@ func (v *Volume) read(n *Needle) (int, os.Error) { } return -1, os.EOF } -func (v *Volume) delete(n *Needle) { - v.accessLock.Lock() - defer v.accessLock.Unlock() - v.nm.Delete(n.Key) -}