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.

299 lines
9.8 KiB

4 years ago
4 years ago
4 years ago
4 years ago
  1. package filer
  2. import (
  3. "context"
  4. "github.com/chrislusf/seaweedfs/weed/glog"
  5. "github.com/viant/ptrie"
  6. "strings"
  7. "time"
  8. "github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
  9. "github.com/chrislusf/seaweedfs/weed/stats"
  10. "github.com/chrislusf/seaweedfs/weed/util"
  11. )
  12. var (
  13. _ = VirtualFilerStore(&FilerStoreWrapper{})
  14. )
  15. type VirtualFilerStore interface {
  16. FilerStore
  17. DeleteHardLink(ctx context.Context, hardLinkId HardLinkId) error
  18. DeleteOneEntry(ctx context.Context, entry *Entry) error
  19. AddPathSpecificStore(path string, storeId string, store FilerStore)
  20. }
  21. type FilerStoreWrapper struct {
  22. defaultStore FilerStore
  23. pathToStore ptrie.Trie
  24. storeIdToStore map[string]FilerStore
  25. }
  26. func NewFilerStoreWrapper(store FilerStore) *FilerStoreWrapper {
  27. if innerStore, ok := store.(*FilerStoreWrapper); ok {
  28. return innerStore
  29. }
  30. return &FilerStoreWrapper{
  31. defaultStore: store,
  32. pathToStore: ptrie.New(),
  33. storeIdToStore: make(map[string]FilerStore),
  34. }
  35. }
  36. func (fsw *FilerStoreWrapper) AddPathSpecificStore(path string, storeId string, store FilerStore) {
  37. fsw.storeIdToStore[storeId] = NewFilerStorePathTranlator(path, store)
  38. err := fsw.pathToStore.Put([]byte(path), storeId)
  39. if err != nil {
  40. glog.Fatalf("put path specific store: %v", err)
  41. }
  42. }
  43. func (fsw *FilerStoreWrapper) getActualStore(path util.FullPath) (store FilerStore) {
  44. store = fsw.defaultStore
  45. if path == "/" {
  46. return
  47. }
  48. var storeId string
  49. fsw.pathToStore.MatchPrefix([]byte(path), func(key []byte, value interface{}) bool {
  50. storeId = value.(string)
  51. return false
  52. })
  53. if storeId != "" {
  54. store = fsw.storeIdToStore[storeId]
  55. }
  56. return
  57. }
  58. func (fsw *FilerStoreWrapper) getDefaultStore() (store FilerStore) {
  59. return fsw.defaultStore
  60. }
  61. func (fsw *FilerStoreWrapper) GetName() string {
  62. return fsw.getDefaultStore().GetName()
  63. }
  64. func (fsw *FilerStoreWrapper) Initialize(configuration util.Configuration, prefix string) error {
  65. return fsw.getDefaultStore().Initialize(configuration, prefix)
  66. }
  67. func (fsw *FilerStoreWrapper) InsertEntry(ctx context.Context, entry *Entry) error {
  68. actualStore := fsw.getActualStore(entry.FullPath)
  69. stats.FilerStoreCounter.WithLabelValues(actualStore.GetName(), "insert").Inc()
  70. start := time.Now()
  71. defer func() {
  72. stats.FilerStoreHistogram.WithLabelValues(actualStore.GetName(), "insert").Observe(time.Since(start).Seconds())
  73. }()
  74. filer_pb.BeforeEntrySerialization(entry.Chunks)
  75. if entry.Mime == "application/octet-stream" {
  76. entry.Mime = ""
  77. }
  78. if err := fsw.handleUpdateToHardLinks(ctx, entry); err != nil {
  79. return err
  80. }
  81. glog.V(4).Infof("InsertEntry %s", entry.FullPath)
  82. return actualStore.InsertEntry(ctx, entry)
  83. }
  84. func (fsw *FilerStoreWrapper) UpdateEntry(ctx context.Context, entry *Entry) error {
  85. actualStore := fsw.getActualStore(entry.FullPath)
  86. stats.FilerStoreCounter.WithLabelValues(actualStore.GetName(), "update").Inc()
  87. start := time.Now()
  88. defer func() {
  89. stats.FilerStoreHistogram.WithLabelValues(actualStore.GetName(), "update").Observe(time.Since(start).Seconds())
  90. }()
  91. filer_pb.BeforeEntrySerialization(entry.Chunks)
  92. if entry.Mime == "application/octet-stream" {
  93. entry.Mime = ""
  94. }
  95. if err := fsw.handleUpdateToHardLinks(ctx, entry); err != nil {
  96. return err
  97. }
  98. glog.V(4).Infof("UpdateEntry %s", entry.FullPath)
  99. return actualStore.UpdateEntry(ctx, entry)
  100. }
  101. func (fsw *FilerStoreWrapper) FindEntry(ctx context.Context, fp util.FullPath) (entry *Entry, err error) {
  102. actualStore := fsw.getActualStore(fp)
  103. stats.FilerStoreCounter.WithLabelValues(actualStore.GetName(), "find").Inc()
  104. start := time.Now()
  105. defer func() {
  106. stats.FilerStoreHistogram.WithLabelValues(actualStore.GetName(), "find").Observe(time.Since(start).Seconds())
  107. }()
  108. glog.V(4).Infof("FindEntry %s", fp)
  109. entry, err = actualStore.FindEntry(ctx, fp)
  110. if err != nil {
  111. return nil, err
  112. }
  113. fsw.maybeReadHardLink(ctx, entry)
  114. filer_pb.AfterEntryDeserialization(entry.Chunks)
  115. return
  116. }
  117. func (fsw *FilerStoreWrapper) DeleteEntry(ctx context.Context, fp util.FullPath) (err error) {
  118. actualStore := fsw.getActualStore(fp)
  119. stats.FilerStoreCounter.WithLabelValues(actualStore.GetName(), "delete").Inc()
  120. start := time.Now()
  121. defer func() {
  122. stats.FilerStoreHistogram.WithLabelValues(actualStore.GetName(), "delete").Observe(time.Since(start).Seconds())
  123. }()
  124. existingEntry, findErr := fsw.FindEntry(ctx, fp)
  125. if findErr == filer_pb.ErrNotFound {
  126. return nil
  127. }
  128. if len(existingEntry.HardLinkId) != 0 {
  129. // remove hard link
  130. glog.V(4).Infof("DeleteHardLink %s", existingEntry.FullPath)
  131. if err = fsw.DeleteHardLink(ctx, existingEntry.HardLinkId); err != nil {
  132. return err
  133. }
  134. }
  135. glog.V(4).Infof("DeleteEntry %s", fp)
  136. return actualStore.DeleteEntry(ctx, fp)
  137. }
  138. func (fsw *FilerStoreWrapper) DeleteOneEntry(ctx context.Context, existingEntry *Entry) (err error) {
  139. actualStore := fsw.getActualStore(existingEntry.FullPath)
  140. stats.FilerStoreCounter.WithLabelValues(actualStore.GetName(), "delete").Inc()
  141. start := time.Now()
  142. defer func() {
  143. stats.FilerStoreHistogram.WithLabelValues(actualStore.GetName(), "delete").Observe(time.Since(start).Seconds())
  144. }()
  145. if len(existingEntry.HardLinkId) != 0 {
  146. // remove hard link
  147. glog.V(4).Infof("DeleteHardLink %s", existingEntry.FullPath)
  148. if err = fsw.DeleteHardLink(ctx, existingEntry.HardLinkId); err != nil {
  149. return err
  150. }
  151. }
  152. glog.V(4).Infof("DeleteOneEntry %s", existingEntry.FullPath)
  153. return actualStore.DeleteEntry(ctx, existingEntry.FullPath)
  154. }
  155. func (fsw *FilerStoreWrapper) DeleteFolderChildren(ctx context.Context, fp util.FullPath) (err error) {
  156. actualStore := fsw.getActualStore(fp + "/")
  157. stats.FilerStoreCounter.WithLabelValues(actualStore.GetName(), "deleteFolderChildren").Inc()
  158. start := time.Now()
  159. defer func() {
  160. stats.FilerStoreHistogram.WithLabelValues(actualStore.GetName(), "deleteFolderChildren").Observe(time.Since(start).Seconds())
  161. }()
  162. glog.V(4).Infof("DeleteFolderChildren %s", fp)
  163. return actualStore.DeleteFolderChildren(ctx, fp)
  164. }
  165. func (fsw *FilerStoreWrapper) ListDirectoryEntries(ctx context.Context, dirPath util.FullPath, startFileName string, includeStartFile bool, limit int64, eachEntryFunc ListEachEntryFunc) (string, error) {
  166. actualStore := fsw.getActualStore(dirPath + "/")
  167. stats.FilerStoreCounter.WithLabelValues(actualStore.GetName(), "list").Inc()
  168. start := time.Now()
  169. defer func() {
  170. stats.FilerStoreHistogram.WithLabelValues(actualStore.GetName(), "list").Observe(time.Since(start).Seconds())
  171. }()
  172. glog.V(4).Infof("ListDirectoryEntries %s from %s limit %d", dirPath, startFileName, limit)
  173. return actualStore.ListDirectoryEntries(ctx, dirPath, startFileName, includeStartFile, limit, func(entry *Entry) bool {
  174. fsw.maybeReadHardLink(ctx, entry)
  175. filer_pb.AfterEntryDeserialization(entry.Chunks)
  176. return eachEntryFunc(entry)
  177. })
  178. }
  179. func (fsw *FilerStoreWrapper) ListDirectoryPrefixedEntries(ctx context.Context, dirPath util.FullPath, startFileName string, includeStartFile bool, limit int64, prefix string, eachEntryFunc ListEachEntryFunc) (lastFileName string, err error) {
  180. actualStore := fsw.getActualStore(dirPath + "/")
  181. stats.FilerStoreCounter.WithLabelValues(actualStore.GetName(), "prefixList").Inc()
  182. start := time.Now()
  183. defer func() {
  184. stats.FilerStoreHistogram.WithLabelValues(actualStore.GetName(), "prefixList").Observe(time.Since(start).Seconds())
  185. }()
  186. glog.V(4).Infof("ListDirectoryPrefixedEntries %s from %s prefix %s limit %d", dirPath, startFileName, prefix, limit)
  187. lastFileName, err = actualStore.ListDirectoryPrefixedEntries(ctx, dirPath, startFileName, includeStartFile, limit, prefix, eachEntryFunc)
  188. if err == ErrUnsupportedListDirectoryPrefixed {
  189. lastFileName, err = fsw.prefixFilterEntries(ctx, dirPath, startFileName, includeStartFile, limit, prefix, func(entry *Entry) bool {
  190. fsw.maybeReadHardLink(ctx, entry)
  191. filer_pb.AfterEntryDeserialization(entry.Chunks)
  192. return eachEntryFunc(entry)
  193. })
  194. }
  195. return lastFileName, err
  196. }
  197. func (fsw *FilerStoreWrapper) prefixFilterEntries(ctx context.Context, dirPath util.FullPath, startFileName string, includeStartFile bool, limit int64, prefix string, eachEntryFunc ListEachEntryFunc) (lastFileName string, err error) {
  198. actualStore := fsw.getActualStore(dirPath + "/")
  199. if prefix == "" {
  200. return actualStore.ListDirectoryEntries(ctx, dirPath, startFileName, includeStartFile, limit, eachEntryFunc)
  201. }
  202. var notPrefixed []*Entry
  203. lastFileName, err = actualStore.ListDirectoryEntries(ctx, dirPath, startFileName, includeStartFile, limit, func(entry *Entry) bool {
  204. notPrefixed = append(notPrefixed, entry)
  205. return true
  206. })
  207. if err != nil {
  208. return
  209. }
  210. count := int64(0)
  211. for count < limit && len(notPrefixed) > 0 {
  212. for _, entry := range notPrefixed {
  213. if strings.HasPrefix(entry.Name(), prefix) {
  214. count++
  215. if !eachEntryFunc(entry) {
  216. return
  217. }
  218. if count >= limit {
  219. break
  220. }
  221. }
  222. }
  223. if count < limit {
  224. notPrefixed = notPrefixed[:0]
  225. _, err = actualStore.ListDirectoryEntries(ctx, dirPath, lastFileName, false, limit, func(entry *Entry) bool {
  226. notPrefixed = append(notPrefixed, entry)
  227. return true
  228. })
  229. if err != nil {
  230. return
  231. }
  232. }
  233. }
  234. return
  235. }
  236. func (fsw *FilerStoreWrapper) BeginTransaction(ctx context.Context) (context.Context, error) {
  237. return fsw.getDefaultStore().BeginTransaction(ctx)
  238. }
  239. func (fsw *FilerStoreWrapper) CommitTransaction(ctx context.Context) error {
  240. return fsw.getDefaultStore().CommitTransaction(ctx)
  241. }
  242. func (fsw *FilerStoreWrapper) RollbackTransaction(ctx context.Context) error {
  243. return fsw.getDefaultStore().RollbackTransaction(ctx)
  244. }
  245. func (fsw *FilerStoreWrapper) Shutdown() {
  246. fsw.getDefaultStore().Shutdown()
  247. }
  248. func (fsw *FilerStoreWrapper) KvPut(ctx context.Context, key []byte, value []byte) (err error) {
  249. return fsw.getDefaultStore().KvPut(ctx, key, value)
  250. }
  251. func (fsw *FilerStoreWrapper) KvGet(ctx context.Context, key []byte) (value []byte, err error) {
  252. return fsw.getDefaultStore().KvGet(ctx, key)
  253. }
  254. func (fsw *FilerStoreWrapper) KvDelete(ctx context.Context, key []byte) (err error) {
  255. return fsw.getDefaultStore().KvDelete(ctx, key)
  256. }