2020-09-01 15:21:19 +08:00
|
|
|
package filer
|
2019-12-13 16:23:05 +08:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"github.com/chrislusf/seaweedfs/weed/glog"
|
|
|
|
"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
|
2020-02-25 14:28:45 +08:00
|
|
|
"github.com/chrislusf/seaweedfs/weed/pb/master_pb"
|
2020-03-23 15:01:34 +08:00
|
|
|
"github.com/chrislusf/seaweedfs/weed/util"
|
2019-12-13 16:23:05 +08:00
|
|
|
)
|
|
|
|
|
2020-09-25 02:11:42 +08:00
|
|
|
type HardLinkId []byte
|
2020-09-24 18:06:44 +08:00
|
|
|
|
2021-03-10 22:41:35 +08:00
|
|
|
const (
|
|
|
|
MsgFailDelNonEmptyFolder = "fail to delete non-empty folder"
|
|
|
|
)
|
|
|
|
|
2020-08-29 14:48:48 +08:00
|
|
|
func (f *Filer) DeleteEntryMetaAndData(ctx context.Context, p util.FullPath, isRecursive, ignoreRecursiveError, shouldDeleteChunks, isFromOtherCluster bool, signatures []int32) (err error) {
|
2019-12-13 16:23:05 +08:00
|
|
|
if p == "/" {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
entry, findErr := f.FindEntry(ctx, p)
|
|
|
|
if findErr != nil {
|
|
|
|
return findErr
|
|
|
|
}
|
|
|
|
|
2020-11-27 04:21:58 +08:00
|
|
|
isDeleteCollection := f.isBucket(entry)
|
2020-02-25 14:28:45 +08:00
|
|
|
|
2019-12-13 16:23:05 +08:00
|
|
|
var chunks []*filer_pb.FileChunk
|
2020-09-24 18:06:44 +08:00
|
|
|
var hardLinkIds []HardLinkId
|
2019-12-13 16:23:05 +08:00
|
|
|
chunks = append(chunks, entry.Chunks...)
|
|
|
|
if entry.IsDirectory() {
|
|
|
|
// delete the folder children, not including the folder itself
|
|
|
|
var dirChunks []*filer_pb.FileChunk
|
2020-09-24 18:06:44 +08:00
|
|
|
var dirHardLinkIds []HardLinkId
|
2021-01-14 05:49:04 +08:00
|
|
|
dirChunks, dirHardLinkIds, err = f.doBatchDeleteFolderMetaAndData(ctx, entry, isRecursive, ignoreRecursiveError, shouldDeleteChunks && !isDeleteCollection, isDeleteCollection, isFromOtherCluster, signatures)
|
2019-12-13 16:23:05 +08:00
|
|
|
if err != nil {
|
2020-02-25 14:28:45 +08:00
|
|
|
glog.V(0).Infof("delete directory %s: %v", p, err)
|
2019-12-13 16:23:05 +08:00
|
|
|
return fmt.Errorf("delete directory %s: %v", p, err)
|
|
|
|
}
|
|
|
|
chunks = append(chunks, dirChunks...)
|
2020-09-24 18:06:44 +08:00
|
|
|
hardLinkIds = append(hardLinkIds, dirHardLinkIds...)
|
2019-12-13 16:23:05 +08:00
|
|
|
}
|
2020-02-25 14:28:45 +08:00
|
|
|
|
2019-12-13 16:23:05 +08:00
|
|
|
// delete the file or folder
|
2020-08-29 14:48:48 +08:00
|
|
|
err = f.doDeleteEntryMetaAndData(ctx, entry, shouldDeleteChunks, isFromOtherCluster, signatures)
|
2019-12-13 16:23:05 +08:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("delete file %s: %v", p, err)
|
|
|
|
}
|
|
|
|
|
2020-11-27 04:21:58 +08:00
|
|
|
if shouldDeleteChunks && !isDeleteCollection {
|
2020-11-18 09:20:21 +08:00
|
|
|
f.DirectDeleteChunks(chunks)
|
2019-12-13 16:23:05 +08:00
|
|
|
}
|
2020-09-24 18:06:44 +08:00
|
|
|
// A case not handled:
|
|
|
|
// what if the chunk is in a different collection?
|
|
|
|
if shouldDeleteChunks {
|
|
|
|
f.maybeDeleteHardLinks(hardLinkIds)
|
|
|
|
}
|
|
|
|
|
2020-11-27 04:21:58 +08:00
|
|
|
if isDeleteCollection {
|
2020-02-25 14:28:45 +08:00
|
|
|
collectionName := entry.Name()
|
2020-02-26 13:50:12 +08:00
|
|
|
f.doDeleteCollection(collectionName)
|
2020-02-25 14:28:45 +08:00
|
|
|
f.deleteBucket(collectionName)
|
|
|
|
}
|
2019-12-13 16:23:05 +08:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-01-14 05:49:04 +08:00
|
|
|
func (f *Filer) doBatchDeleteFolderMetaAndData(ctx context.Context, entry *Entry, isRecursive, ignoreRecursiveError, shouldDeleteChunks, isDeletingBucket, isFromOtherCluster bool, signatures []int32) (chunks []*filer_pb.FileChunk, hardlinkIds []HardLinkId, err error) {
|
2019-12-13 16:23:05 +08:00
|
|
|
|
|
|
|
lastFileName := ""
|
|
|
|
includeLastFile := false
|
2021-06-11 14:37:54 +08:00
|
|
|
if !isDeletingBucket || !f.Store.CanDropWholeBucket() {
|
2021-01-14 05:49:04 +08:00
|
|
|
for {
|
2021-04-25 02:49:03 +08:00
|
|
|
entries, _, err := f.ListDirectoryEntries(ctx, entry.FullPath, lastFileName, includeLastFile, PaginationSize, "", "", "")
|
2021-01-14 05:49:04 +08:00
|
|
|
if err != nil {
|
|
|
|
glog.Errorf("list folder %s: %v", entry.FullPath, err)
|
|
|
|
return nil, nil, fmt.Errorf("list folder %s: %v", entry.FullPath, err)
|
|
|
|
}
|
|
|
|
if lastFileName == "" && !isRecursive && len(entries) > 0 {
|
|
|
|
// only for first iteration in the loop
|
|
|
|
glog.Errorf("deleting a folder %s has children: %+v ...", entry.FullPath, entries[0].Name())
|
2021-03-10 22:41:35 +08:00
|
|
|
return nil, nil, fmt.Errorf("%s: %s", MsgFailDelNonEmptyFolder, entry.FullPath)
|
2021-01-14 05:49:04 +08:00
|
|
|
}
|
2019-12-13 16:23:05 +08:00
|
|
|
|
2021-01-14 05:49:04 +08:00
|
|
|
for _, sub := range entries {
|
|
|
|
lastFileName = sub.Name()
|
|
|
|
var dirChunks []*filer_pb.FileChunk
|
|
|
|
var dirHardLinkIds []HardLinkId
|
|
|
|
if sub.IsDirectory() {
|
|
|
|
subIsDeletingBucket := f.isBucket(sub)
|
|
|
|
dirChunks, dirHardLinkIds, err = f.doBatchDeleteFolderMetaAndData(ctx, sub, isRecursive, ignoreRecursiveError, shouldDeleteChunks, subIsDeletingBucket, false, nil)
|
|
|
|
chunks = append(chunks, dirChunks...)
|
|
|
|
hardlinkIds = append(hardlinkIds, dirHardLinkIds...)
|
2020-09-24 18:06:44 +08:00
|
|
|
} else {
|
2021-01-14 05:49:04 +08:00
|
|
|
f.NotifyUpdateEvent(ctx, sub, nil, shouldDeleteChunks, isFromOtherCluster, nil)
|
|
|
|
if len(sub.HardLinkId) != 0 {
|
|
|
|
// hard link chunk data are deleted separately
|
|
|
|
hardlinkIds = append(hardlinkIds, sub.HardLinkId)
|
|
|
|
} else {
|
|
|
|
chunks = append(chunks, sub.Chunks...)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if err != nil && !ignoreRecursiveError {
|
|
|
|
return nil, nil, err
|
2020-09-24 18:06:44 +08:00
|
|
|
}
|
2019-12-13 16:23:05 +08:00
|
|
|
}
|
|
|
|
|
2021-01-14 05:49:04 +08:00
|
|
|
if len(entries) < PaginationSize {
|
|
|
|
break
|
|
|
|
}
|
2019-12-13 16:23:05 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-12 14:54:10 +08:00
|
|
|
glog.V(3).Infof("deleting directory %v delete %d chunks: %v", entry.FullPath, len(chunks), shouldDeleteChunks)
|
2019-12-13 16:23:05 +08:00
|
|
|
|
2021-06-15 21:12:39 +08:00
|
|
|
if storeDeletionErr := f.Store.DeleteFolderChildren(ctx, entry.FullPath, DeleteMaxRows); storeDeletionErr != nil {
|
2020-09-24 18:06:44 +08:00
|
|
|
return nil, nil, fmt.Errorf("filer store delete: %v", storeDeletionErr)
|
2019-12-13 16:23:05 +08:00
|
|
|
}
|
|
|
|
|
2020-09-10 02:21:23 +08:00
|
|
|
f.NotifyUpdateEvent(ctx, entry, nil, shouldDeleteChunks, isFromOtherCluster, signatures)
|
2020-07-13 08:32:19 +08:00
|
|
|
|
2020-09-24 18:06:44 +08:00
|
|
|
return chunks, hardlinkIds, nil
|
2019-12-13 16:23:05 +08:00
|
|
|
}
|
|
|
|
|
2020-08-29 14:48:48 +08:00
|
|
|
func (f *Filer) doDeleteEntryMetaAndData(ctx context.Context, entry *Entry, shouldDeleteChunks bool, isFromOtherCluster bool, signatures []int32) (err error) {
|
2019-12-13 16:23:05 +08:00
|
|
|
|
2020-02-12 14:54:10 +08:00
|
|
|
glog.V(3).Infof("deleting entry %v, delete chunks: %v", entry.FullPath, shouldDeleteChunks)
|
2019-12-13 16:23:05 +08:00
|
|
|
|
2020-11-27 03:14:56 +08:00
|
|
|
if storeDeletionErr := f.Store.DeleteOneEntry(ctx, entry); storeDeletionErr != nil {
|
2019-12-13 16:23:05 +08:00
|
|
|
return fmt.Errorf("filer store delete: %v", storeDeletionErr)
|
|
|
|
}
|
2020-08-13 04:11:04 +08:00
|
|
|
if !entry.IsDirectory() {
|
2020-08-29 14:48:48 +08:00
|
|
|
f.NotifyUpdateEvent(ctx, entry, nil, shouldDeleteChunks, isFromOtherCluster, signatures)
|
2020-04-06 06:03:25 +08:00
|
|
|
}
|
2019-12-13 16:23:05 +08:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2020-02-25 14:28:45 +08:00
|
|
|
|
2020-02-26 13:50:12 +08:00
|
|
|
func (f *Filer) doDeleteCollection(collectionName string) (err error) {
|
2020-02-25 14:28:45 +08:00
|
|
|
|
2020-02-26 13:50:12 +08:00
|
|
|
return f.MasterClient.WithClient(func(client master_pb.SeaweedClient) error {
|
|
|
|
_, err := client.CollectionDelete(context.Background(), &master_pb.CollectionDeleteRequest{
|
2020-02-25 14:28:45 +08:00
|
|
|
Name: collectionName,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
glog.Infof("delete collection %s: %v", collectionName, err)
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
})
|
|
|
|
|
|
|
|
}
|
2020-11-27 03:25:56 +08:00
|
|
|
|
|
|
|
func (f *Filer) maybeDeleteHardLinks(hardLinkIds []HardLinkId) {
|
|
|
|
for _, hardLinkId := range hardLinkIds {
|
|
|
|
if err := f.Store.DeleteHardLink(context.Background(), hardLinkId); err != nil {
|
|
|
|
glog.Errorf("delete hard link id %d : %v", hardLinkId, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|