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.

152 lines
4.9 KiB

5 years ago
  1. package filer
  2. import (
  3. "context"
  4. "fmt"
  5. "github.com/chrislusf/seaweedfs/weed/glog"
  6. "github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
  7. "github.com/chrislusf/seaweedfs/weed/pb/master_pb"
  8. "github.com/chrislusf/seaweedfs/weed/util"
  9. )
  10. type HardLinkId int64
  11. func (hardLinkId HardLinkId) Key() []byte{
  12. bytes := make([]byte, 8)
  13. util.Uint64toBytes(bytes, uint64(hardLinkId))
  14. return bytes
  15. }
  16. func (f *Filer) DeleteEntryMetaAndData(ctx context.Context, p util.FullPath, isRecursive, ignoreRecursiveError, shouldDeleteChunks, isFromOtherCluster bool, signatures []int32) (err error) {
  17. if p == "/" {
  18. return nil
  19. }
  20. entry, findErr := f.FindEntry(ctx, p)
  21. if findErr != nil {
  22. return findErr
  23. }
  24. isCollection := f.isBucket(entry)
  25. var chunks []*filer_pb.FileChunk
  26. var hardLinkIds []HardLinkId
  27. chunks = append(chunks, entry.Chunks...)
  28. if entry.IsDirectory() {
  29. // delete the folder children, not including the folder itself
  30. var dirChunks []*filer_pb.FileChunk
  31. var dirHardLinkIds []HardLinkId
  32. dirChunks, dirHardLinkIds, err = f.doBatchDeleteFolderMetaAndData(ctx, entry, isRecursive, ignoreRecursiveError, shouldDeleteChunks && !isCollection, isFromOtherCluster, signatures)
  33. if err != nil {
  34. glog.V(0).Infof("delete directory %s: %v", p, err)
  35. return fmt.Errorf("delete directory %s: %v", p, err)
  36. }
  37. chunks = append(chunks, dirChunks...)
  38. hardLinkIds = append(hardLinkIds, dirHardLinkIds...)
  39. }
  40. // delete the file or folder
  41. err = f.doDeleteEntryMetaAndData(ctx, entry, shouldDeleteChunks, isFromOtherCluster, signatures)
  42. if err != nil {
  43. return fmt.Errorf("delete file %s: %v", p, err)
  44. }
  45. if shouldDeleteChunks && !isCollection {
  46. go f.DeleteChunks(chunks)
  47. }
  48. // A case not handled:
  49. // what if the chunk is in a different collection?
  50. if shouldDeleteChunks {
  51. f.maybeDeleteHardLinks(hardLinkIds)
  52. }
  53. if isCollection {
  54. collectionName := entry.Name()
  55. f.doDeleteCollection(collectionName)
  56. f.deleteBucket(collectionName)
  57. }
  58. return nil
  59. }
  60. func (f *Filer) doBatchDeleteFolderMetaAndData(ctx context.Context, entry *Entry, isRecursive, ignoreRecursiveError, shouldDeleteChunks, isFromOtherCluster bool, signatures []int32) (chunks []*filer_pb.FileChunk, hardlinkIds []HardLinkId, err error) {
  61. lastFileName := ""
  62. includeLastFile := false
  63. for {
  64. entries, err := f.ListDirectoryEntries(ctx, entry.FullPath, lastFileName, includeLastFile, PaginationSize, "")
  65. if err != nil {
  66. glog.Errorf("list folder %s: %v", entry.FullPath, err)
  67. return nil, nil, fmt.Errorf("list folder %s: %v", entry.FullPath, err)
  68. }
  69. if lastFileName == "" && !isRecursive && len(entries) > 0 {
  70. // only for first iteration in the loop
  71. glog.Errorf("deleting a folder %s has children: %+v ...", entry.FullPath, entries[0].Name())
  72. return nil, nil,fmt.Errorf("fail to delete non-empty folder: %s", entry.FullPath)
  73. }
  74. for _, sub := range entries {
  75. lastFileName = sub.Name()
  76. var dirChunks []*filer_pb.FileChunk
  77. var dirHardLinkIds []HardLinkId
  78. if sub.IsDirectory() {
  79. dirChunks, dirHardLinkIds, err = f.doBatchDeleteFolderMetaAndData(ctx, sub, isRecursive, ignoreRecursiveError, shouldDeleteChunks, false, nil)
  80. chunks = append(chunks, dirChunks...)
  81. hardlinkIds = append(hardlinkIds, dirHardLinkIds...)
  82. } else {
  83. f.NotifyUpdateEvent(ctx, sub, nil, shouldDeleteChunks, isFromOtherCluster, nil)
  84. if sub.HardLinkId != 0 {
  85. // hard link chunk data are deleted separately
  86. hardlinkIds = append(hardlinkIds, sub.HardLinkId)
  87. } else {
  88. chunks = append(chunks, sub.Chunks...)
  89. }
  90. }
  91. if err != nil && !ignoreRecursiveError {
  92. return nil, nil, err
  93. }
  94. }
  95. if len(entries) < PaginationSize {
  96. break
  97. }
  98. }
  99. glog.V(3).Infof("deleting directory %v delete %d chunks: %v", entry.FullPath, len(chunks), shouldDeleteChunks)
  100. if storeDeletionErr := f.Store.DeleteFolderChildren(ctx, entry.FullPath); storeDeletionErr != nil {
  101. return nil, nil, fmt.Errorf("filer store delete: %v", storeDeletionErr)
  102. }
  103. f.NotifyUpdateEvent(ctx, entry, nil, shouldDeleteChunks, isFromOtherCluster, signatures)
  104. return chunks, hardlinkIds, nil
  105. }
  106. func (f *Filer) doDeleteEntryMetaAndData(ctx context.Context, entry *Entry, shouldDeleteChunks bool, isFromOtherCluster bool, signatures []int32) (err error) {
  107. glog.V(3).Infof("deleting entry %v, delete chunks: %v", entry.FullPath, shouldDeleteChunks)
  108. if storeDeletionErr := f.Store.DeleteEntry(ctx, entry.FullPath); storeDeletionErr != nil {
  109. return fmt.Errorf("filer store delete: %v", storeDeletionErr)
  110. }
  111. if !entry.IsDirectory() {
  112. f.NotifyUpdateEvent(ctx, entry, nil, shouldDeleteChunks, isFromOtherCluster, signatures)
  113. }
  114. return nil
  115. }
  116. func (f *Filer) doDeleteCollection(collectionName string) (err error) {
  117. return f.MasterClient.WithClient(func(client master_pb.SeaweedClient) error {
  118. _, err := client.CollectionDelete(context.Background(), &master_pb.CollectionDeleteRequest{
  119. Name: collectionName,
  120. })
  121. if err != nil {
  122. glog.Infof("delete collection %s: %v", collectionName, err)
  123. }
  124. return err
  125. })
  126. }