You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

186 lines
4.5 KiB

6 years ago
6 years ago
6 years ago
  1. package redis
  2. import (
  3. "context"
  4. "fmt"
  5. "sort"
  6. "strings"
  7. "time"
  8. "github.com/go-redis/redis"
  9. "github.com/chrislusf/seaweedfs/weed/filer2"
  10. "github.com/chrislusf/seaweedfs/weed/glog"
  11. "github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
  12. )
  13. const (
  14. DIR_LIST_MARKER = "\x00"
  15. )
  16. type UniversalRedisStore struct {
  17. Client redis.UniversalClient
  18. }
  19. func (store *UniversalRedisStore) BeginTransaction(ctx context.Context) (context.Context, error) {
  20. return ctx, nil
  21. }
  22. func (store *UniversalRedisStore) CommitTransaction(ctx context.Context) error {
  23. return nil
  24. }
  25. func (store *UniversalRedisStore) RollbackTransaction(ctx context.Context) error {
  26. return nil
  27. }
  28. func (store *UniversalRedisStore) InsertEntry(ctx context.Context, entry *filer2.Entry) (err error) {
  29. value, err := entry.EncodeAttributesAndChunks()
  30. if err != nil {
  31. return fmt.Errorf("encoding %s %+v: %v", entry.FullPath, entry.Attr, err)
  32. }
  33. _, err = store.Client.Set(string(entry.FullPath), value, time.Duration(entry.TtlSec)*time.Second).Result()
  34. if err != nil {
  35. return fmt.Errorf("persisting %s : %v", entry.FullPath, err)
  36. }
  37. dir, name := entry.FullPath.DirAndName()
  38. if name != "" {
  39. _, err = store.Client.SAdd(genDirectoryListKey(dir), name).Result()
  40. if err != nil {
  41. return fmt.Errorf("persisting %s in parent dir: %v", entry.FullPath, err)
  42. }
  43. }
  44. return nil
  45. }
  46. func (store *UniversalRedisStore) UpdateEntry(ctx context.Context, entry *filer2.Entry) (err error) {
  47. return store.InsertEntry(ctx, entry)
  48. }
  49. func (store *UniversalRedisStore) FindEntry(ctx context.Context, fullpath filer2.FullPath) (entry *filer2.Entry, err error) {
  50. data, err := store.Client.Get(string(fullpath)).Result()
  51. if err == redis.Nil {
  52. return nil, filer_pb.ErrNotFound
  53. }
  54. if err != nil {
  55. return nil, fmt.Errorf("get %s : %v", fullpath, err)
  56. }
  57. entry = &filer2.Entry{
  58. FullPath: fullpath,
  59. }
  60. err = entry.DecodeAttributesAndChunks([]byte(data))
  61. if err != nil {
  62. return entry, fmt.Errorf("decode %s : %v", entry.FullPath, err)
  63. }
  64. return entry, nil
  65. }
  66. func (store *UniversalRedisStore) DeleteEntry(ctx context.Context, fullpath filer2.FullPath) (err error) {
  67. _, err = store.Client.Del(string(fullpath)).Result()
  68. if err != nil {
  69. return fmt.Errorf("delete %s : %v", fullpath, err)
  70. }
  71. dir, name := fullpath.DirAndName()
  72. if name != "" {
  73. _, err = store.Client.SRem(genDirectoryListKey(dir), name).Result()
  74. if err != nil {
  75. return fmt.Errorf("delete %s in parent dir: %v", fullpath, err)
  76. }
  77. }
  78. return nil
  79. }
  80. func (store *UniversalRedisStore) DeleteFolderChildren(ctx context.Context, fullpath filer2.FullPath) (err error) {
  81. members, err := store.Client.SMembers(genDirectoryListKey(string(fullpath))).Result()
  82. if err != nil {
  83. return fmt.Errorf("delete folder %s : %v", fullpath, err)
  84. }
  85. for _, fileName := range members {
  86. path := filer2.NewFullPath(string(fullpath), fileName)
  87. _, err = store.Client.Del(string(path)).Result()
  88. if err != nil {
  89. return fmt.Errorf("delete %s in parent dir: %v", fullpath, err)
  90. }
  91. }
  92. return nil
  93. }
  94. func (store *UniversalRedisStore) ListDirectoryEntries(ctx context.Context, fullpath filer2.FullPath, startFileName string, inclusive bool,
  95. limit int) (entries []*filer2.Entry, err error) {
  96. dirListKey := genDirectoryListKey(string(fullpath))
  97. members, err := store.Client.SMembers(dirListKey).Result()
  98. if err != nil {
  99. return nil, fmt.Errorf("list %s : %v", fullpath, err)
  100. }
  101. // skip
  102. if startFileName != "" {
  103. var t []string
  104. for _, m := range members {
  105. if strings.Compare(m, startFileName) >= 0 {
  106. if m == startFileName {
  107. if inclusive {
  108. t = append(t, m)
  109. }
  110. } else {
  111. t = append(t, m)
  112. }
  113. }
  114. }
  115. members = t
  116. }
  117. // sort
  118. sort.Slice(members, func(i, j int) bool {
  119. return strings.Compare(members[i], members[j]) < 0
  120. })
  121. // limit
  122. if limit < len(members) {
  123. members = members[:limit]
  124. }
  125. // fetch entry meta
  126. for _, fileName := range members {
  127. path := filer2.NewFullPath(string(fullpath), fileName)
  128. entry, err := store.FindEntry(ctx, path)
  129. if err != nil {
  130. glog.V(0).Infof("list %s : %v", path, err)
  131. } else {
  132. if entry.TtlSec > 0 {
  133. if entry.Attr.Crtime.Add(time.Duration(entry.TtlSec) * time.Second).Before(time.Now()) {
  134. store.Client.Del(string(path)).Result()
  135. store.Client.SRem(dirListKey, fileName).Result()
  136. continue
  137. }
  138. }
  139. entries = append(entries, entry)
  140. }
  141. }
  142. return entries, err
  143. }
  144. func genDirectoryListKey(dir string) (dirList string) {
  145. return dir + DIR_LIST_MARKER
  146. }
  147. func (store *UniversalRedisStore) Shutdown() {
  148. store.Client.Close()
  149. }