From 03d76479a57a4e28a56d89b14d78300756992007 Mon Sep 17 00:00:00 2001 From: Chris Lu Date: Sun, 27 May 2018 11:14:29 -0700 Subject: [PATCH] add reds --- weed/filer2/configuration.go | 6 ++ weed/filer2/redis/redis_store.go | 172 +++++++++++++++++++++++++++++++ weed/server/filer_server.go | 1 + 3 files changed, 179 insertions(+) create mode 100644 weed/filer2/redis/redis_store.go diff --git a/weed/filer2/configuration.go b/weed/filer2/configuration.go index 0112a883b..16c0f3fd0 100644 --- a/weed/filer2/configuration.go +++ b/weed/filer2/configuration.go @@ -74,6 +74,12 @@ hosts=[ "localhost:9042", ] +[redis] +enabled = true +address = "localhost:6379" +password = "" +db = 0 + ` ) diff --git a/weed/filer2/redis/redis_store.go b/weed/filer2/redis/redis_store.go new file mode 100644 index 000000000..cb8381bf5 --- /dev/null +++ b/weed/filer2/redis/redis_store.go @@ -0,0 +1,172 @@ +package redis + +import ( + "fmt" + "github.com/chrislusf/seaweedfs/weed/filer2" + "github.com/chrislusf/seaweedfs/weed/glog" + "github.com/spf13/viper" + "github.com/go-redis/redis" + "sort" + "strings" +) + +const ( + DIR_LIST_MARKER = "\x00" +) + +func init() { + filer2.Stores = append(filer2.Stores, &RedisStore{}) +} + +type RedisStore struct { + Client *redis.Client +} + +func (store *RedisStore) GetName() string { + return "redis" +} + +func (store *RedisStore) Initialize(viper *viper.Viper) (err error) { + return store.initialize( + viper.GetString("address"), + viper.GetString("password"), + viper.GetInt("database"), + ) +} + +func (store *RedisStore) initialize(hostPort string, password string, database int) (err error) { + store.Client = redis.NewClient(&redis.Options{ + Addr: hostPort, + Password: password, + DB: database, + }) + return +} + +func (store *RedisStore) InsertEntry(entry *filer2.Entry) (err error) { + + value, err := entry.EncodeAttributesAndChunks() + if err != nil { + return fmt.Errorf("encoding %s %+v: %v", entry.FullPath, entry.Attr, err) + } + + _, err = store.Client.Set(string(entry.FullPath), value, 0).Result() + + if err != nil { + return fmt.Errorf("persisting %s : %v", entry.FullPath, err) + } + + dir, name := entry.FullPath.DirAndName() + if name != "" { + _, err = store.Client.SAdd(genDirectoryListKey(dir), name).Result() + if err != nil { + return fmt.Errorf("persisting %s in parent dir: %v", entry.FullPath, err) + } + } + + return nil +} + +func (store *RedisStore) UpdateEntry(entry *filer2.Entry) (err error) { + + return store.InsertEntry(entry) +} + +func (store *RedisStore) FindEntry(fullpath filer2.FullPath) (entry *filer2.Entry, err error) { + + data, err := store.Client.Get(string(fullpath)).Result() + if err == redis.Nil { + return nil, filer2.ErrNotFound + } + + if err != nil { + return nil, fmt.Errorf("get %s : %v", entry.FullPath, err) + } + + entry = &filer2.Entry{ + FullPath: fullpath, + } + err = entry.DecodeAttributesAndChunks([]byte(data)) + if err != nil { + return entry, fmt.Errorf("decode %s : %v", entry.FullPath, err) + } + + return entry, nil +} + +func (store *RedisStore) DeleteEntry(fullpath filer2.FullPath) (entry *filer2.Entry, err error) { + + entry, err = store.FindEntry(fullpath) + if err != nil { + return nil, nil + } + + _, err = store.Client.Del(string(fullpath)).Result() + + if err != nil { + return entry, fmt.Errorf("delete %s : %v", entry.FullPath, err) + } + + dir, name := fullpath.DirAndName() + if name != "" { + _, err = store.Client.SRem(genDirectoryListKey(dir), name).Result() + if err != nil { + return nil, fmt.Errorf("delete %s in parent dir: %v", entry.FullPath, err) + } + } + + return entry, nil +} + +func (store *RedisStore) ListDirectoryEntries(fullpath filer2.FullPath, startFileName string, inclusive bool, + limit int) (entries []*filer2.Entry, err error) { + + members, err := store.Client.SMembers(genDirectoryListKey(string(fullpath))).Result() + if err != nil { + return nil, fmt.Errorf("list %s : %v", fullpath, err) + } + + // skip + if startFileName != "" { + var t []string + for _, m := range members { + if strings.Compare(m, startFileName) >= 0 { + if m == startFileName { + if inclusive { + t = append(t, m) + } + } else { + t = append(t, m) + } + } + } + members = t + } + + // sort + sort.Slice(members, func(i, j int) bool { + return strings.Compare(members[i], members[j]) < 0 + }) + + // limit + if limit < len(members) { + members = members[:limit] + } + + // fetch entry meta + for _, fileName := range members { + path := filer2.NewFullPath(string(fullpath), fileName) + entry, err := store.FindEntry(path) + if err != nil { + glog.V(0).Infof("list %s : %v", path, err) + } else { + entries = append(entries, entry) + } + } + + return entries, err +} + +func genDirectoryListKey(dir string) (dirList string) { + return dir + DIR_LIST_MARKER +} diff --git a/weed/server/filer_server.go b/weed/server/filer_server.go index 6c8a2c079..012b0afbf 100644 --- a/weed/server/filer_server.go +++ b/weed/server/filer_server.go @@ -17,6 +17,7 @@ import ( _ "github.com/chrislusf/seaweedfs/weed/filer2/memdb" _ "github.com/chrislusf/seaweedfs/weed/filer2/mysql" _ "github.com/chrislusf/seaweedfs/weed/filer2/postgres" + _ "github.com/chrislusf/seaweedfs/weed/filer2/redis" ) type FilerServer struct {