filerstore_wrapper.go 12 KB

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