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.5 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 int) ([]*Entry, 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. entries, err := actualStore.ListDirectoryEntries(ctx, dirPath, startFileName, includeStartFile, limit)
  174. if err != nil {
  175. return nil, err
  176. }
  177. for _, entry := range entries {
  178. fsw.maybeReadHardLink(ctx, entry)
  179. filer_pb.AfterEntryDeserialization(entry.Chunks)
  180. }
  181. return entries, err
  182. }
  183. func (fsw *FilerStoreWrapper) ListDirectoryPrefixedEntries(ctx context.Context, dirPath util.FullPath, startFileName string, includeStartFile bool, limit int, prefix string) ([]*Entry, error) {
  184. actualStore := fsw.getActualStore(dirPath + "/")
  185. stats.FilerStoreCounter.WithLabelValues(actualStore.GetName(), "prefixList").Inc()
  186. start := time.Now()
  187. defer func() {
  188. stats.FilerStoreHistogram.WithLabelValues(actualStore.GetName(), "prefixList").Observe(time.Since(start).Seconds())
  189. }()
  190. glog.V(4).Infof("ListDirectoryPrefixedEntries %s from %s prefix %s limit %d", dirPath, startFileName, prefix, limit)
  191. entries, err := actualStore.ListDirectoryPrefixedEntries(ctx, dirPath, startFileName, includeStartFile, limit, prefix)
  192. if err == ErrUnsupportedListDirectoryPrefixed {
  193. entries, err = fsw.prefixFilterEntries(ctx, dirPath, startFileName, includeStartFile, limit, prefix)
  194. }
  195. if err != nil {
  196. return nil, err
  197. }
  198. for _, entry := range entries {
  199. fsw.maybeReadHardLink(ctx, entry)
  200. filer_pb.AfterEntryDeserialization(entry.Chunks)
  201. }
  202. return entries, nil
  203. }
  204. func (fsw *FilerStoreWrapper) prefixFilterEntries(ctx context.Context, dirPath util.FullPath, startFileName string, includeStartFile bool, limit int, prefix string) (entries []*Entry, err error) {
  205. actualStore := fsw.getActualStore(dirPath + "/")
  206. entries, err = actualStore.ListDirectoryEntries(ctx, dirPath, startFileName, includeStartFile, limit)
  207. if err != nil {
  208. return nil, err
  209. }
  210. if prefix == "" {
  211. return
  212. }
  213. count := 0
  214. var lastFileName string
  215. notPrefixed := entries
  216. entries = nil
  217. for count < limit && len(notPrefixed) > 0 {
  218. for _, entry := range notPrefixed {
  219. lastFileName = entry.Name()
  220. if strings.HasPrefix(entry.Name(), prefix) {
  221. count++
  222. entries = append(entries, entry)
  223. if count >= limit {
  224. break
  225. }
  226. }
  227. }
  228. if count < limit {
  229. notPrefixed, err = actualStore.ListDirectoryEntries(ctx, dirPath, lastFileName, false, limit)
  230. if err != nil {
  231. return
  232. }
  233. }
  234. }
  235. return
  236. }
  237. func (fsw *FilerStoreWrapper) BeginTransaction(ctx context.Context) (context.Context, error) {
  238. return fsw.getDefaultStore().BeginTransaction(ctx)
  239. }
  240. func (fsw *FilerStoreWrapper) CommitTransaction(ctx context.Context) error {
  241. return fsw.getDefaultStore().CommitTransaction(ctx)
  242. }
  243. func (fsw *FilerStoreWrapper) RollbackTransaction(ctx context.Context) error {
  244. return fsw.getDefaultStore().RollbackTransaction(ctx)
  245. }
  246. func (fsw *FilerStoreWrapper) Shutdown() {
  247. fsw.getDefaultStore().Shutdown()
  248. }
  249. func (fsw *FilerStoreWrapper) KvPut(ctx context.Context, key []byte, value []byte) (err error) {
  250. return fsw.getDefaultStore().KvPut(ctx, key, value)
  251. }
  252. func (fsw *FilerStoreWrapper) KvGet(ctx context.Context, key []byte) (value []byte, err error) {
  253. return fsw.getDefaultStore().KvGet(ctx, key)
  254. }
  255. func (fsw *FilerStoreWrapper) KvDelete(ctx context.Context, key []byte) (err error) {
  256. return fsw.getDefaultStore().KvDelete(ctx, key)
  257. }