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.

177 lines
4.9 KiB

  1. package meta_cache
  2. import (
  3. "context"
  4. "os"
  5. "sync"
  6. "time"
  7. "github.com/seaweedfs/seaweedfs/weed/filer"
  8. "github.com/seaweedfs/seaweedfs/weed/filer/leveldb"
  9. "github.com/seaweedfs/seaweedfs/weed/glog"
  10. "github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
  11. "github.com/seaweedfs/seaweedfs/weed/util"
  12. )
  13. // need to have logic similar to FilerStoreWrapper
  14. // e.g. fill fileId field for chunks
  15. type MetaCache struct {
  16. root util.FullPath
  17. localStore filer.VirtualFilerStore
  18. sync.RWMutex
  19. uidGidMapper *UidGidMapper
  20. markCachedFn func(fullpath util.FullPath)
  21. isCachedFn func(fullpath util.FullPath) bool
  22. invalidateFunc func(fullpath util.FullPath, entry *filer_pb.Entry)
  23. }
  24. func NewMetaCache(dbFolder string, uidGidMapper *UidGidMapper, root util.FullPath,
  25. markCachedFn func(path util.FullPath), isCachedFn func(path util.FullPath) bool, invalidateFunc func(util.FullPath, *filer_pb.Entry)) *MetaCache {
  26. return &MetaCache{
  27. root: root,
  28. localStore: openMetaStore(dbFolder),
  29. markCachedFn: markCachedFn,
  30. isCachedFn: isCachedFn,
  31. uidGidMapper: uidGidMapper,
  32. invalidateFunc: func(fullpath util.FullPath, entry *filer_pb.Entry) {
  33. invalidateFunc(fullpath, entry)
  34. },
  35. }
  36. }
  37. func openMetaStore(dbFolder string) filer.VirtualFilerStore {
  38. os.RemoveAll(dbFolder)
  39. os.MkdirAll(dbFolder, 0755)
  40. store := &leveldb.LevelDBStore{}
  41. config := &cacheConfig{
  42. dir: dbFolder,
  43. }
  44. if err := store.Initialize(config, ""); err != nil {
  45. glog.Fatalf("Failed to initialize metadata cache store for %s: %+v", store.GetName(), err)
  46. }
  47. return filer.NewFilerStoreWrapper(store)
  48. }
  49. func (mc *MetaCache) InsertEntry(ctx context.Context, entry *filer.Entry) error {
  50. mc.Lock()
  51. defer mc.Unlock()
  52. return mc.doInsertEntry(ctx, entry)
  53. }
  54. func (mc *MetaCache) doInsertEntry(ctx context.Context, entry *filer.Entry) error {
  55. return mc.localStore.InsertEntry(ctx, entry)
  56. }
  57. func (mc *MetaCache) AtomicUpdateEntryFromFiler(ctx context.Context, oldPath util.FullPath, newEntry *filer.Entry) error {
  58. mc.Lock()
  59. defer mc.Unlock()
  60. entry, err := mc.localStore.FindEntry(ctx, oldPath)
  61. if err != nil && err != filer_pb.ErrNotFound {
  62. glog.Errorf("Metacache: find entry error: %v", err)
  63. return err
  64. }
  65. if entry != nil {
  66. if oldPath != "" {
  67. if newEntry != nil && oldPath == newEntry.FullPath {
  68. // skip the unnecessary deletion
  69. // leave the update to the following InsertEntry operation
  70. } else {
  71. ctx = context.WithValue(ctx, "OP", "MV")
  72. glog.V(3).Infof("DeleteEntry %s", oldPath)
  73. if err := mc.localStore.DeleteEntry(ctx, oldPath); err != nil {
  74. return err
  75. }
  76. }
  77. }
  78. } else {
  79. // println("unknown old directory:", oldDir)
  80. }
  81. if newEntry != nil {
  82. newDir, _ := newEntry.DirAndName()
  83. if mc.isCachedFn(util.FullPath(newDir)) {
  84. glog.V(3).Infof("InsertEntry %s/%s", newDir, newEntry.Name())
  85. if err := mc.localStore.InsertEntry(ctx, newEntry); err != nil {
  86. return err
  87. }
  88. }
  89. }
  90. return nil
  91. }
  92. func (mc *MetaCache) UpdateEntry(ctx context.Context, entry *filer.Entry) error {
  93. mc.Lock()
  94. defer mc.Unlock()
  95. return mc.localStore.UpdateEntry(ctx, entry)
  96. }
  97. func (mc *MetaCache) FindEntry(ctx context.Context, fp util.FullPath) (entry *filer.Entry, err error) {
  98. mc.RLock()
  99. defer mc.RUnlock()
  100. entry, err = mc.localStore.FindEntry(ctx, fp)
  101. if err != nil {
  102. return nil, err
  103. }
  104. if entry.TtlSec > 0 && entry.Crtime.Add(time.Duration(entry.TtlSec)).Before(time.Now()) {
  105. return nil, filer_pb.ErrNotFound
  106. }
  107. mc.mapIdFromFilerToLocal(entry)
  108. return
  109. }
  110. func (mc *MetaCache) DeleteEntry(ctx context.Context, fp util.FullPath) (err error) {
  111. mc.Lock()
  112. defer mc.Unlock()
  113. return mc.localStore.DeleteEntry(ctx, fp)
  114. }
  115. func (mc *MetaCache) DeleteFolderChildren(ctx context.Context, fp util.FullPath) (err error) {
  116. mc.Lock()
  117. defer mc.Unlock()
  118. return mc.localStore.DeleteFolderChildren(ctx, fp)
  119. }
  120. func (mc *MetaCache) ListDirectoryEntries(ctx context.Context, dirPath util.FullPath, startFileName string, includeStartFile bool, limit int64, eachEntryFunc filer.ListEachEntryFunc) error {
  121. mc.RLock()
  122. defer mc.RUnlock()
  123. if !mc.isCachedFn(dirPath) {
  124. // if this request comes after renaming, it should be fine
  125. glog.Warningf("unsynchronized dir: %v", dirPath)
  126. }
  127. _, err := mc.localStore.ListDirectoryEntries(ctx, dirPath, startFileName, includeStartFile, limit, func(entry *filer.Entry) bool {
  128. if entry.TtlSec > 0 && entry.Crtime.Add(time.Duration(entry.TtlSec)).Before(time.Now()) {
  129. return true
  130. }
  131. mc.mapIdFromFilerToLocal(entry)
  132. return eachEntryFunc(entry)
  133. })
  134. if err != nil {
  135. return err
  136. }
  137. return err
  138. }
  139. func (mc *MetaCache) Shutdown() {
  140. mc.Lock()
  141. defer mc.Unlock()
  142. mc.localStore.Shutdown()
  143. }
  144. func (mc *MetaCache) mapIdFromFilerToLocal(entry *filer.Entry) {
  145. entry.Attr.Uid, entry.Attr.Gid = mc.uidGidMapper.FilerToLocal(entry.Attr.Uid, entry.Attr.Gid)
  146. }
  147. func (mc *MetaCache) Debug() {
  148. if debuggable, ok := mc.localStore.(filer.Debuggable); ok {
  149. println("start debugging")
  150. debuggable.Debug(os.Stderr)
  151. }
  152. }