History

purge objects immediately with `x-minio-force-delete` in DeleteObject and DeleteBucket API (#15148)

Praveen raj Mani committed 4 years ago

Commit b49fc331 parent 00e235a20 files · +220 −79Browse files

Unified · Split

20 files
  1. cmd/background-newdisks-heal-ops.go +5 −1
  2. cmd/erasure-encode_test.go +4 −1
  3. cmd/erasure-healing-common_test.go +8 −2
  4. cmd/erasure-healing.go +4 −1
  5. cmd/erasure-healing_test.go +44 −11
  6. cmd/erasure-multipart.go +8 −2
  7. cmd/erasure-object.go +8 −2
  8. cmd/erasure-object_test.go +8 −2
  9. cmd/erasure-single-drive.go +16 −4
  10. cmd/format-erasure.go +4 −1
  11. cmd/naughty-disk_test.go +2 −2
  12. cmd/storage-datatypes.go +7 −0
  13. cmd/storage-interface.go +2 −2
  14. cmd/storage-rest-client.go +3 −2
  15. cmd/storage-rest-server.go +9 −2
  16. cmd/storage-rest_test.go +4 −1
  17. cmd/xl-storage-disk-id-check.go +6 −3
  18. cmd/xl-storage.go +50 −33
  19. cmd/xl-storage_test.go +24 −6
  20. cmd/xl-storage_windows_test.go +4 −1
cmd/background-newdisks-heal-ops.go+5−1
@@ -163,7 +163,11 @@ func (h *healingTracker) save(ctx context.Context) error { · 162 unmodified lines
163163 func (h *healingTracker) delete(ctx context.Context) error {
164164 return h.disk.Delete(ctx, minioMetaBucket,
165165 pathJoin(bucketMetaPrefix, slashSeparator, healingTrackerFilename),
166− false)
166+ DeleteOptions{
167+ Recursive: false,
168+ Force: false,
169+ },
170+ )
167171 }
168172
169173 func (h *healingTracker) isHealed(bucket string) bool {
cmd/erasure-encode_test.go+4−1
@@ -196,7 +196,10 @@ func benchmarkErasureEncode(data, parity, dataDown, parityDown int, size int64, · 195 unmodified lines
196196 if disk == OfflineDisk {
197197 continue
198198 }
199− disk.Delete(context.Background(), "testbucket", "object", false)
199+ disk.Delete(context.Background(), "testbucket", "object", DeleteOptions{
200+ Recursive: false,
201+ Force: false,
202+ })
200203 writers[i] = newBitrotWriter(disk, "testbucket", "object", erasure.ShardFileSize(size), DefaultBitrotAlgorithm, erasure.ShardSize())
201204 }
202205 _, err := erasure.Encode(context.Background(), bytes.NewReader(content), writers, buffer, erasure.dataBlocks+1)
cmd/erasure-healing-common_test.go+8−2
@@ -218,7 +218,10 @@ func TestListOnlineDisks(t *testing.T) { · 217 unmodified lines
218218 // and check if that disk
219219 // appears in outDatedDisks.
220220 tamperedIndex = index
221− dErr := erasureDisks[index].Delete(context.Background(), bucket, pathJoin(object, fi.DataDir, "part.1"), false)
221+ dErr := erasureDisks[index].Delete(context.Background(), bucket, pathJoin(object, fi.DataDir, "part.1"), DeleteOptions{
222+ Recursive: false,
223+ Force: false,
224+ })
222225 if dErr != nil {
223226 t.Fatalf("Failed to delete %s - %v", filepath.Join(object, "part.1"), dErr)
224227 }
@@ -395,7 +398,10 @@ func TestListOnlineDisksSmallObjects(t *testing.T) { · 170 unmodified lines
395398 // and check if that disk
396399 // appears in outDatedDisks.
397400 tamperedIndex = index
398− dErr := erasureDisks[index].Delete(context.Background(), bucket, pathJoin(object, xlStorageFormatFile), false)
401+ dErr := erasureDisks[index].Delete(context.Background(), bucket, pathJoin(object, xlStorageFormatFile), DeleteOptions{
402+ Recursive: false,
403+ Force: false,
404+ })
399405 if dErr != nil {
400406 t.Fatalf("Failed to delete %s - %v", pathJoin(object, xlStorageFormatFile), dErr)
401407 }
cmd/erasure-healing.go+4−1
@@ -655,7 +655,10 @@ func (er erasureObjects) healObjectDir(ctx context.Context, bucket, object strin · 654 unmodified lines
655655 wg.Add(1)
656656 go func(index int, disk StorageAPI) {
657657 defer wg.Done()
658− _ = disk.Delete(ctx, bucket, object, false)
658+ _ = disk.Delete(ctx, bucket, object, DeleteOptions{
659+ Recursive: false,
660+ Force: false,
661+ })
659662 }(index, disk)
660663 }
661664 wg.Wait()
cmd/erasure-healing_test.go+44−11
@@ -610,7 +610,10 @@ func TestHealCorrectQuorum(t *testing.T) { · 609 unmodified lines
610610 }
611611
612612 for i := 0; i < nfi.Erasure.ParityBlocks; i++ {
613− erasureDisks[i].Delete(context.Background(), bucket, pathJoin(object, xlStorageFormatFile), false)
613+ erasureDisks[i].Delete(context.Background(), bucket, pathJoin(object, xlStorageFormatFile), DeleteOptions{
614+ Recursive: false,
615+ Force: false,
616+ })
614617 }
615618
616619 // Try healing now, it should heal the content properly.
@@ -634,7 +637,10 @@ func TestHealCorrectQuorum(t *testing.T) { · 17 unmodified lines
634637 }
635638
636639 for i := 0; i < nfi.Erasure.ParityBlocks; i++ {
637− erasureDisks[i].Delete(context.Background(), minioMetaBucket, pathJoin(cfgFile, xlStorageFormatFile), false)
640+ erasureDisks[i].Delete(context.Background(), minioMetaBucket, pathJoin(cfgFile, xlStorageFormatFile), DeleteOptions{
641+ Recursive: false,
642+ Force: false,
643+ })
638644 }
639645
640646 // Try healing now, it should heal the content properly.
@@ -714,7 +720,10 @@ func TestHealObjectCorruptedPools(t *testing.T) { · 73 unmodified lines
714720 er := set.sets[0]
715721 erasureDisks := er.getDisks()
716722 firstDisk := erasureDisks[0]
717− err = firstDisk.Delete(context.Background(), bucket, pathJoin(object, xlStorageFormatFile), false)
723+ err = firstDisk.Delete(context.Background(), bucket, pathJoin(object, xlStorageFormatFile), DeleteOptions{
724+ Recursive: false,
725+ Force: false,
726+ })
718727 if err != nil {
719728 t.Fatalf("Failed to delete a file - %v", err)
720729 }
@@ -734,7 +743,10 @@ func TestHealObjectCorruptedPools(t *testing.T) { · 13 unmodified lines
734743 t.Errorf("Expected xl.meta file to be present but stat failed - %v", err)
735744 }
736745
737− err = firstDisk.Delete(context.Background(), bucket, pathJoin(object, fi.DataDir, "part.1"), false)
746+ err = firstDisk.Delete(context.Background(), bucket, pathJoin(object, fi.DataDir, "part.1"), DeleteOptions{
747+ Recursive: false,
748+ Force: false,
749+ })
738750 if err != nil {
739751 t.Errorf("Failure during deleting part.1 - %v", err)
740752 }
@@ -761,7 +773,10 @@ func TestHealObjectCorruptedPools(t *testing.T) { · 20 unmodified lines
761773 t.Fatalf("FileInfo not equal after healing: %v != %v", fi, nfi)
762774 }
763775
764− err = firstDisk.Delete(context.Background(), bucket, pathJoin(object, fi.DataDir, "part.1"), false)
776+ err = firstDisk.Delete(context.Background(), bucket, pathJoin(object, fi.DataDir, "part.1"), DeleteOptions{
777+ Recursive: false,
778+ Force: false,
779+ })
765780 if err != nil {
766781 t.Errorf("Failure during deleting part.1 - %v", err)
767782 }
@@ -792,7 +807,10 @@ func TestHealObjectCorruptedPools(t *testing.T) { · 24 unmodified lines
792807 // Test 4: checks if HealObject returns an error when xl.meta is not found
793808 // in more than read quorum number of disks, to create a corrupted situation.
794809 for i := 0; i <= nfi.Erasure.DataBlocks; i++ {
795− erasureDisks[i].Delete(context.Background(), bucket, pathJoin(object, xlStorageFormatFile), false)
810+ erasureDisks[i].Delete(context.Background(), bucket, pathJoin(object, xlStorageFormatFile), DeleteOptions{
811+ Recursive: false,
812+ Force: false,
813+ })
796814 }
797815
798816 // Try healing now, expect to receive errFileNotFound.
@@ -884,7 +902,10 @@ func TestHealObjectCorruptedXLMeta(t *testing.T) { · 85 unmodified lines
884902 t.Fatalf("Failed to getLatestFileInfo - %v", err)
885903 }
886904
887− err = firstDisk.Delete(context.Background(), bucket, pathJoin(object, xlStorageFormatFile), false)
905+ err = firstDisk.Delete(context.Background(), bucket, pathJoin(object, xlStorageFormatFile), DeleteOptions{
906+ Recursive: false,
907+ Force: false,
908+ })
888909 if err != nil {
889910 t.Fatalf("Failed to delete a file - %v", err)
890911 }
@@ -936,7 +957,10 @@ func TestHealObjectCorruptedXLMeta(t *testing.T) { · 45 unmodified lines
936957 // Test 3: checks if HealObject returns an error when xl.meta is not found
937958 // in more than read quorum number of disks, to create a corrupted situation.
938959 for i := 0; i <= nfi2.Erasure.DataBlocks; i++ {
939− erasureDisks[i].Delete(context.Background(), bucket, pathJoin(object, xlStorageFormatFile), false)
960+ erasureDisks[i].Delete(context.Background(), bucket, pathJoin(object, xlStorageFormatFile), DeleteOptions{
961+ Recursive: false,
962+ Force: false,
963+ })
940964 }
941965
942966 // Try healing now, expect to receive errFileNotFound.
@@ -1033,7 +1057,10 @@ func TestHealObjectCorruptedParts(t *testing.T) { · 90 unmodified lines
10331057 }
10341058
10351059 // Test 1, remove part.1
1036− err = firstDisk.Delete(context.Background(), bucket, pathJoin(object, fi.DataDir, "part.1"), false)
1060+ err = firstDisk.Delete(context.Background(), bucket, pathJoin(object, fi.DataDir, "part.1"), DeleteOptions{
1061+ Recursive: false,
1062+ Force: false,
1063+ })
10371064 if err != nil {
10381065 t.Fatalf("Failed to delete a file - %v", err)
10391066 }
@@ -1078,7 +1105,10 @@ func TestHealObjectCorruptedParts(t *testing.T) { · 38 unmodified lines
10781105 t.Fatalf("Failed to write a file - %v", err)
10791106 }
10801107
1081− err = secondDisk.Delete(context.Background(), bucket, object, true)
1108+ err = secondDisk.Delete(context.Background(), bucket, object, DeleteOptions{
1109+ Recursive: true,
1110+ Force: false,
1111+ })
10821112 if err != nil {
10831113 t.Fatalf("Failed to delete a file - %v", err)
10841114 }
@@ -1166,7 +1196,10 @@ func TestHealObjectErasure(t *testing.T) { · 81 unmodified lines
11661196 }
11671197
11681198 // Delete the whole object folder
1169− err = firstDisk.Delete(context.Background(), bucket, object, true)
1199+ err = firstDisk.Delete(context.Background(), bucket, object, DeleteOptions{
1200+ Recursive: true,
1201+ Force: false,
1202+ })
11701203 if err != nil {
11711204 t.Fatalf("Failed to delete a file - %v", err)
11721205 }
cmd/erasure-multipart.go+8−2
@@ -91,7 +91,10 @@ func (er erasureObjects) removeObjectPart(bucket, object, uploadID, dataDir stri · 90 unmodified lines
9191 // Ignoring failure to remove parts that weren't present in CompleteMultipartUpload
9292 // requests. xl.meta is the authoritative source of truth on which parts constitute
9393 // the object. The presence of parts that don't belong in the object doesn't affect correctness.
94− _ = storageDisks[index].Delete(context.TODO(), minioMetaMultipartBucket, curpartPath, false)
94+ _ = storageDisks[index].Delete(context.TODO(), minioMetaMultipartBucket, curpartPath, DeleteOptions{
95+ Recursive: false,
96+ Force: false,
97+ })
9598 return nil
9699 }, index)
97100 }
@@ -138,7 +141,10 @@ func (er erasureObjects) deleteAll(ctx context.Context, bucket, prefix string) { · 40 unmodified lines
138141 wg.Add(1)
139142 go func(disk StorageAPI) {
140143 defer wg.Done()
141− disk.Delete(ctx, bucket, prefix, true)
144+ disk.Delete(ctx, bucket, prefix, DeleteOptions{
145+ Recursive: true,
146+ Force: false,
147+ })
142148 }(disk)
143149 }
144150 wg.Wait()
cmd/erasure-object.go+8−2
@@ -1367,8 +1367,14 @@ func (er erasureObjects) deletePrefix(ctx context.Context, bucket, prefix string · 1366 unmodified lines
13671367 // Deletes
13681368 // - The prefix and its children
13691369 // - The prefix__XLDIR__
1370− defer disks[index].Delete(ctx, bucket, dirPrefix, true)
1371− return disks[index].Delete(ctx, bucket, prefix, true)
1370+ defer disks[index].Delete(ctx, bucket, dirPrefix, DeleteOptions{
1371+ Recursive: true,
1372+ Force: true,
1373+ })
1374+ return disks[index].Delete(ctx, bucket, prefix, DeleteOptions{
1375+ Recursive: true,
1376+ Force: true,
1377+ })
13721378 }, index)
13731379 }
13741380 for _, err := range g.Wait() {
cmd/erasure-object_test.go+8−2
@@ -528,7 +528,10 @@ func TestGetObjectNoQuorum(t *testing.T) { · 527 unmodified lines
528528 files, _ := disk.ListDir(ctx, bucket, object, -1)
529529 for _, file := range files {
530530 if file != "xl.meta" {
531− disk.Delete(ctx, bucket, pathJoin(object, file), true)
531+ disk.Delete(ctx, bucket, pathJoin(object, file), DeleteOptions{
532+ Recursive: true,
533+ Force: false,
534+ })
532535 }
533536 }
534537 }
@@ -629,7 +632,10 @@ func TestHeadObjectNoQuorum(t *testing.T) { · 94 unmodified lines
629632 files, _ := disk.ListDir(ctx, bucket, object, -1)
630633 for _, file := range files {
631634 if file != "xl.meta" {
632− disk.Delete(ctx, bucket, pathJoin(object, file), true)
635+ disk.Delete(ctx, bucket, pathJoin(object, file), DeleteOptions{
636+ Recursive: true,
637+ Force: false,
638+ })
633639 }
634640 }
635641 }
cmd/erasure-single-drive.go+16−4
@@ -1321,8 +1321,14 @@ func (es *erasureSingle) DeleteObjects(ctx context.Context, bucket string, objec · 1320 unmodified lines
13211321
13221322 func (es *erasureSingle) deletePrefix(ctx context.Context, bucket, prefix string) error {
13231323 dirPrefix := encodeDirObject(prefix)
1324− defer es.disk.Delete(ctx, bucket, dirPrefix, true)
1325− return es.disk.Delete(ctx, bucket, prefix, true)
1324+ defer es.disk.Delete(ctx, bucket, dirPrefix, DeleteOptions{
1325+ Recursive: true,
1326+ Force: true,
1327+ })
1328+ return es.disk.Delete(ctx, bucket, prefix, DeleteOptions{
1329+ Recursive: true,
1330+ Force: true,
1331+ })
13261332 }
13271333
13281334 // DeleteObject - deletes an object, this call doesn't necessary reply
@@ -1916,7 +1922,10 @@ func (es *erasureSingle) removeObjectPart(bucket, object, uploadID, dataDir stri · 587 unmodified lines
19161922 // Ignoring failure to remove parts that weren't present in CompleteMultipartUpload
19171923 // requests. xl.meta is the authoritative source of truth on which parts constitute
19181924 // the object. The presence of parts that don't belong in the object doesn't affect correctness.
1919− _ = storageDisks[index].Delete(context.TODO(), minioMetaMultipartBucket, curpartPath, false)
1925+ _ = storageDisks[index].Delete(context.TODO(), minioMetaMultipartBucket, curpartPath, DeleteOptions{
1926+ Recursive: false,
1927+ Force: false,
1928+ })
19201929 return nil
19211930 }, index)
19221931 }
@@ -1954,7 +1963,10 @@ func (es *erasureSingle) cleanupStaleUploadsOnDisk(ctx context.Context, disk Sto · 31 unmodified lines
19541963 }
19551964 wait := es.deletedCleanupSleeper.Timer(ctx)
19561965 if now.Sub(vi.Created) > expiry {
1957− disk.Delete(ctx, minioMetaTmpBucket, tmpDir, true)
1966+ disk.Delete(ctx, minioMetaTmpBucket, tmpDir, DeleteOptions{
1967+ Recursive: true,
1968+ Force: false,
1969+ })
19581970 }
19591971 wait()
19601972 return nil
cmd/format-erasure.go+4−1
@@ -367,7 +367,10 @@ func saveFormatErasure(disk StorageAPI, format *formatErasureV3, heal bool) erro · 366 unmodified lines
367367 tmpFormat := mustGetUUID()
368368
369369 // Purge any existing temporary file, okay to ignore errors here.
370− defer disk.Delete(context.TODO(), minioMetaBucket, tmpFormat, false)
370+ defer disk.Delete(context.TODO(), minioMetaBucket, tmpFormat, DeleteOptions{
371+ Recursive: false,
372+ Force: false,
373+ })
371374
372375 // write to unique file.
373376 if err = disk.WriteAll(context.TODO(), minioMetaBucket, tmpFormat, formatBytes); err != nil {
cmd/naughty-disk_test.go+2−2
@@ -221,11 +221,11 @@ func (d *naughtyDisk) CheckParts(ctx context.Context, volume string, path string · 220 unmodified lines
221221 return d.disk.CheckParts(ctx, volume, path, fi)
222222 }
223223
224−func (d *naughtyDisk) Delete(ctx context.Context, volume string, path string, recursive bool) (err error) {
224+func (d *naughtyDisk) Delete(ctx context.Context, volume string, path string, deleteOpts DeleteOptions) (err error) {
225225 if err := d.calcError(); err != nil {
226226 return err
227227 }
228− return d.disk.Delete(ctx, volume, path, recursive)
228+ return d.disk.Delete(ctx, volume, path, deleteOpts)
229229 }
230230
231231 func (d *naughtyDisk) DeleteVersions(ctx context.Context, volume string, versions []FileInfoVersions) []error {
cmd/storage-datatypes.go+7−0
@@ -21,6 +21,13 @@ import ( · 20 unmodified lines
2121 "time"
2222 )
2323
24+// DeleteOptions represents the disk level delete options available for the APIs
25+//msgp:ignore DeleteOptions
26+type DeleteOptions struct {
27+ Recursive bool
28+ Force bool
29+}
30+
2431 //go:generate msgp -file=$GOFILE
2532
2633 // DiskInfo is an extended type which returns current
cmd/storage-interface.go+2−2
@@ -95,7 +95,7 @@ type StorageAPI interface { · 94 unmodified lines
9595 ReadFileStream(ctx context.Context, volume, path string, offset, length int64) (io.ReadCloser, error)
9696 RenameFile(ctx context.Context, srcVolume, srcPath, dstVolume, dstPath string) error
9797 CheckParts(ctx context.Context, volume string, path string, fi FileInfo) error
98− Delete(ctx context.Context, volume string, path string, recursive bool) (err error)
98+ Delete(ctx context.Context, volume string, path string, deleteOpts DeleteOptions) (err error)
9999 VerifyFile(ctx context.Context, volume, path string, fi FileInfo) error
100100 StatInfoFile(ctx context.Context, volume, path string, glob bool) (stat []StatInfo, err error)
101101
@@ -223,7 +223,7 @@ func (p *unrecognizedDisk) CheckParts(ctx context.Context, volume string, path s · 121 unmodified lines
223223 return errDiskNotFound
224224 }
225225
226−func (p *unrecognizedDisk) Delete(ctx context.Context, volume string, path string, recursive bool) (err error) {
226+func (p *unrecognizedDisk) Delete(ctx context.Context, volume string, path string, deleteOpts DeleteOptions) (err error) {
227227 return errDiskNotFound
228228 }
229229
cmd/storage-rest-client.go+3−2
@@ -581,11 +581,12 @@ func (client *storageRESTClient) ListDir(ctx context.Context, volume, dirPath st · 580 unmodified lines
581581 }
582582
583583 // DeleteFile - deletes a file.
584−func (client *storageRESTClient) Delete(ctx context.Context, volume string, path string, recursive bool) error {
584+func (client *storageRESTClient) Delete(ctx context.Context, volume string, path string, deleteOpts DeleteOptions) error {
585585 values := make(url.Values)
586586 values.Set(storageRESTVolume, volume)
587587 values.Set(storageRESTFilePath, path)
588− values.Set(storageRESTRecursive, strconv.FormatBool(recursive))
588+ values.Set(storageRESTRecursive, strconv.FormatBool(deleteOpts.Recursive))
589+ values.Set(storageRESTForceDelete, strconv.FormatBool(deleteOpts.Force))
589590
590591 respBody, err := client.call(ctx, storageRESTMethodDeleteFile, values, nil, -1)
591592 defer xhttp.DrainBody(respBody)
cmd/storage-rest-server.go+9−2
@@ -652,8 +652,15 @@ func (s *storageRESTServer) DeleteFileHandler(w http.ResponseWriter, r *http.Req · 651 unmodified lines
652652 s.writeErrorResponse(w, err)
653653 return
654654 }
655−
656− err = s.storage.Delete(r.Context(), volume, filePath, recursive)
655+ force, err := strconv.ParseBool(r.Form.Get(storageRESTForceDelete))
656+ if err != nil {
657+ s.writeErrorResponse(w, err)
658+ return
659+ }
660+ err = s.storage.Delete(r.Context(), volume, filePath, DeleteOptions{
661+ Recursive: recursive,
662+ Force: force,
663+ })
657664 if err != nil {
658665 s.writeErrorResponse(w, err)
659666 }
cmd/storage-rest_test.go+4−1
@@ -383,7 +383,10 @@ func testStorageAPIDeleteFile(t *testing.T, storage StorageAPI) { · 382 unmodified lines
383383 }
384384
385385 for i, testCase := range testCases {
386− err := storage.Delete(context.Background(), testCase.volumeName, testCase.objectName, false)
386+ err := storage.Delete(context.Background(), testCase.volumeName, testCase.objectName, DeleteOptions{
387+ Recursive: false,
388+ Force: false,
389+ })
387390 expectErr := (err != nil)
388391
389392 if expectErr != testCase.expectErr {
cmd/xl-storage-disk-id-check.go+6−3
@@ -382,14 +382,14 @@ func (p *xlStorageDiskIDCheck) CheckParts(ctx context.Context, volume string, pa · 381 unmodified lines
382382 return p.storage.CheckParts(ctx, volume, path, fi)
383383 }
384384
385−func (p *xlStorageDiskIDCheck) Delete(ctx context.Context, volume string, path string, recursive bool) (err error) {
385+func (p *xlStorageDiskIDCheck) Delete(ctx context.Context, volume string, path string, deleteOpts DeleteOptions) (err error) {
386386 ctx, done, err := p.TrackDiskHealth(ctx, storageMetricDelete, volume, path)
387387 if err != nil {
388388 return err
389389 }
390390 defer done(&err)
391391
392− return p.storage.Delete(ctx, volume, path, recursive)
392+ return p.storage.Delete(ctx, volume, path, deleteOpts)
393393 }
394394
395395 // DeleteVersions deletes slice of versions, it can be same object
@@ -768,7 +768,10 @@ func (p *xlStorageDiskIDCheck) monitorDiskStatus() { · 372 unmodified lines
768768 if err != nil || len(b) != 10001 {
769769 continue
770770 }
771− err = p.storage.Delete(context.Background(), minioMetaTmpBucket, fn, false)
771+ err = p.storage.Delete(context.Background(), minioMetaTmpBucket, fn, DeleteOptions{
772+ Recursive: false,
773+ Force: false,
774+ })
772775 if err == nil {
773776 logger.Info("Able to read+write, bringing disk %s online.", p.storage.String())
774777 atomic.StoreInt32(&p.health.status, diskHealthOK)
cmd/xl-storage.go+50−33
@@ -818,7 +818,7 @@ func (s *xlStorage) DeleteVol(ctx context.Context, volume string, forceDelete bo · 817 unmodified lines
818818 }
819819
820820 if forceDelete {
821− err = s.moveToTrash(volumeDir, true)
821+ err = s.moveToTrash(volumeDir, true, true)
822822 } else {
823823 err = Remove(volumeDir)
824824 }
@@ -903,7 +903,7 @@ func (s *xlStorage) deleteVersions(ctx context.Context, volume, path string, fis · 78 unmodified lines
903903 if !isXL2V1Format(buf) {
904904 // Delete the meta file, if there are no more versions the
905905 // top level parent is automatically removed.
906− return s.deleteFile(volumeDir, pathJoin(volumeDir, path), true)
906+ return s.deleteFile(volumeDir, pathJoin(volumeDir, path), true, false)
907907 }
908908
909909 var xlMeta xlMetaV2
@@ -939,7 +939,7 @@ func (s *xlStorage) deleteVersions(ctx context.Context, volume, path string, fis · 29 unmodified lines
939939 if err = checkPathLength(filePath); err != nil {
940940 return err
941941 }
942− if err = s.moveToTrash(filePath, true); err != nil {
942+ if err = s.moveToTrash(filePath, true, false); err != nil {
943943 if err != errFileNotFound {
944944 return err
945945 }
@@ -959,9 +959,9 @@ func (s *xlStorage) deleteVersions(ctx context.Context, volume, path string, fis · 13 unmodified lines
959959 }
960960
961961 // Move xl.meta to trash
962− err = s.moveToTrash(pathJoin(volumeDir, path, xlStorageFormatFile), false)
962+ err = s.moveToTrash(pathJoin(volumeDir, path, xlStorageFormatFile), false, false)
963963 if err == nil || err == errFileNotFound {
964− s.deleteFile(volumeDir, pathJoin(volumeDir, path), false)
964+ s.deleteFile(volumeDir, pathJoin(volumeDir, path), false, false)
965965 }
966966 return err
967967 }
@@ -985,19 +985,36 @@ func (s *xlStorage) DeleteVersions(ctx context.Context, volume string, versions · 17 unmodified lines
985985 return errs
986986 }
987987
988−func (s *xlStorage) moveToTrash(filePath string, recursive bool) error {
988+func (s *xlStorage) moveToTrash(filePath string, recursive, force bool) error {
989989 pathUUID := mustGetUUID()
990+ targetPath := pathutil.Join(s.diskPath, minioMetaTmpDeletedBucket, pathUUID)
991+
992+ var renameFn func(source, target string) error
990993 if recursive {
991− return renameAll(filePath, pathutil.Join(s.diskPath, minioMetaTmpDeletedBucket, pathUUID))
994+ renameFn = renameAll
995+ } else {
996+ renameFn = Rename
997+ }
998+
999+ if err := renameFn(filePath, targetPath); err != nil {
1000+ return err
9921001 }
993− return Rename(filePath, pathutil.Join(s.diskPath, minioMetaTmpDeletedBucket, pathUUID))
1002+ // immediately purge the target
1003+ if force {
1004+ removeAll(targetPath)
1005+ }
1006+
1007+ return nil
9941008 }
9951009
9961010 // DeleteVersion - deletes FileInfo metadata for path at `xl.meta`. forceDelMarker
9971011 // will force creating a new `xl.meta` to create a new delete marker
9981012 func (s *xlStorage) DeleteVersion(ctx context.Context, volume, path string, fi FileInfo, forceDelMarker bool) error {
9991013 if HasSuffix(path, SlashSeparator) {
1000− return s.Delete(ctx, volume, path, false)
1014+ return s.Delete(ctx, volume, path, DeleteOptions{
1015+ Recursive: false,
1016+ Force: false,
1017+ })
10011018 }
10021019
10031020 buf, err := s.ReadAll(ctx, volume, pathJoin(path, xlStorageFormatFile))
@@ -1035,7 +1052,7 @@ func (s *xlStorage) DeleteVersion(ctx context.Context, volume, path string, fi F · 31 unmodified lines
10351052 if !isXL2V1Format(buf) {
10361053 // Delete the meta file, if there are no more versions the
10371054 // top level parent is automatically removed.
1038− return s.deleteFile(volumeDir, pathJoin(volumeDir, path), true)
1055+ return s.deleteFile(volumeDir, pathJoin(volumeDir, path), true, false)
10391056 }
10401057
10411058 var xlMeta xlMetaV2
@@ -1065,7 +1082,7 @@ func (s *xlStorage) DeleteVersion(ctx context.Context, volume, path string, fi F · 23 unmodified lines
10651082 if err = checkPathLength(filePath); err != nil {
10661083 return err
10671084 }
1068− if err = s.moveToTrash(filePath, true); err != nil {
1085+ if err = s.moveToTrash(filePath, true, false); err != nil {
10691086 if err != errFileNotFound {
10701087 return err
10711088 }
@@ -1088,9 +1105,9 @@ func (s *xlStorage) DeleteVersion(ctx context.Context, volume, path string, fi F · 16 unmodified lines
10881105 return err
10891106 }
10901107
1091− err = s.moveToTrash(filePath, false)
1108+ err = s.moveToTrash(filePath, false, false)
10921109 if err == nil || err == errFileNotFound {
1093− s.deleteFile(volumeDir, pathJoin(volumeDir, path), false)
1110+ s.deleteFile(volumeDir, pathJoin(volumeDir, path), false, false)
10941111 }
10951112 return err
10961113 }
@@ -2014,7 +2031,7 @@ func (s *xlStorage) CheckParts(ctx context.Context, volume string, path string, · 917 unmodified lines
20142031 // move up the tree, deleting empty parent directories until it finds one
20152032 // with files in it. Returns nil for a non-empty directory even when
20162033 // recursive is set to false.
2017−func (s *xlStorage) deleteFile(basePath, deletePath string, recursive bool) error {
2034+func (s *xlStorage) deleteFile(basePath, deletePath string, recursive, force bool) error {
20182035 if basePath == "" || deletePath == "" {
20192036 return nil
20202037 }
@@ -2027,7 +2044,7 @@ func (s *xlStorage) deleteFile(basePath, deletePath string, recursive bool) erro · 6 unmodified lines
20272044
20282045 var err error
20292046 if recursive {
2030− err = s.moveToTrash(deletePath, true)
2047+ err = s.moveToTrash(deletePath, true, force)
20312048 } else {
20322049 err = Remove(deletePath)
20332050 }
@@ -2060,13 +2077,13 @@ func (s *xlStorage) deleteFile(basePath, deletePath string, recursive bool) erro · 26 unmodified lines
20602077
20612078 // Delete parent directory obviously not recursively. Errors for
20622079 // parent directories shouldn't trickle down.
2063− s.deleteFile(basePath, deletePath, false)
2080+ s.deleteFile(basePath, deletePath, false, false)
20642081
20652082 return nil
20662083 }
20672084
20682085 // DeleteFile - delete a file at path.
2069−func (s *xlStorage) Delete(ctx context.Context, volume string, path string, recursive bool) (err error) {
2086+func (s *xlStorage) Delete(ctx context.Context, volume string, path string, deleteOpts DeleteOptions) (err error) {
20702087 volumeDir, err := s.getVolDir(volume)
20712088 if err != nil {
20722089 return err
@@ -2092,7 +2109,7 @@ func (s *xlStorage) Delete(ctx context.Context, volume string, path string, recu · 19 unmodified lines
20922109 }
20932110
20942111 // Delete file and delete parent directory as well if it's empty.
2095− return s.deleteFile(volumeDir, filePath, recursive)
2112+ return s.deleteFile(volumeDir, filePath, deleteOpts.Recursive, deleteOpts.Force)
20962113 }
20972114
20982115 func skipAccessChecks(volume string) (ok bool) {
@@ -2270,7 +2287,7 @@ func (s *xlStorage) RenameData(ctx context.Context, srcVolume, srcPath string, f · 171 unmodified lines
22702287 // legacy data dir means its old content, honor system umask.
22712288 if err = mkdirAll(legacyDataPath, 0o777); err != nil {
22722289 // any failed mkdir-calls delete them.
2273− s.deleteFile(dstVolumeDir, legacyDataPath, true)
2290+ s.deleteFile(dstVolumeDir, legacyDataPath, true, false)
22742291 return osErrToFileErr(err)
22752292 }
22762293
@@ -2282,7 +2299,7 @@ func (s *xlStorage) RenameData(ctx context.Context, srcVolume, srcPath string, f · 5 unmodified lines
22822299
22832300 if err = Rename(pathJoin(currentDataPath, entry), pathJoin(legacyDataPath, entry)); err != nil {
22842301 // Any failed rename calls un-roll previous transaction.
2285− s.deleteFile(dstVolumeDir, legacyDataPath, true)
2302+ s.deleteFile(dstVolumeDir, legacyDataPath, true, false)
22862303
22872304 return osErrToFileErr(err)
22882305 }
@@ -2327,7 +2344,7 @@ func (s *xlStorage) RenameData(ctx context.Context, srcVolume, srcPath string, f · 38 unmodified lines
23272344 if err = xlMeta.AddVersion(fi); err != nil {
23282345 if legacyPreserved {
23292346 // Any failed rename calls un-roll previous transaction.
2330− s.deleteFile(dstVolumeDir, legacyDataPath, true)
2347+ s.deleteFile(dstVolumeDir, legacyDataPath, true, false)
23312348 }
23322349 return err
23332350 }
@@ -2338,7 +2355,7 @@ func (s *xlStorage) RenameData(ctx context.Context, srcVolume, srcPath string, f · 4 unmodified lines
23382355 logger.LogIf(ctx, err)
23392356 if legacyPreserved {
23402357 // Any failed rename calls un-roll previous transaction.
2341− s.deleteFile(dstVolumeDir, legacyDataPath, true)
2358+ s.deleteFile(dstVolumeDir, legacyDataPath, true, false)
23422359 }
23432360 return errFileCorrupt
23442361 }
@@ -2347,7 +2364,7 @@ func (s *xlStorage) RenameData(ctx context.Context, srcVolume, srcPath string, f · 2 unmodified lines
23472364 if err = s.WriteAll(ctx, srcVolume, pathJoin(srcPath, xlStorageFormatFile), dstBuf); err != nil {
23482365 if legacyPreserved {
23492366 // Any failed rename calls un-roll previous transaction.
2350− s.deleteFile(dstVolumeDir, legacyDataPath, true)
2367+ s.deleteFile(dstVolumeDir, legacyDataPath, true, false)
23512368 }
23522369 return osErrToFileErr(err)
23532370 }
@@ -2355,19 +2372,19 @@ func (s *xlStorage) RenameData(ctx context.Context, srcVolume, srcPath string, f · 1 unmodified line
23552372
23562373 // renameAll only for objects that have xl.meta not saved inline.
23572374 if len(fi.Data) == 0 && fi.Size > 0 {
2358− s.moveToTrash(dstDataPath, true)
2375+ s.moveToTrash(dstDataPath, true, false)
23592376 if healing {
23602377 // If we are healing we should purge any legacyDataPath content,
23612378 // that was previously preserved during PutObject() call
23622379 // on a versioned bucket.
2363− s.moveToTrash(legacyDataPath, true)
2380+ s.moveToTrash(legacyDataPath, true, false)
23642381 }
23652382 if err = renameAll(srcDataPath, dstDataPath); err != nil {
23662383 if legacyPreserved {
23672384 // Any failed rename calls un-roll previous transaction.
2368− s.deleteFile(dstVolumeDir, legacyDataPath, true)
2385+ s.deleteFile(dstVolumeDir, legacyDataPath, true, false)
23692386 }
2370− s.deleteFile(dstVolumeDir, dstDataPath, false)
2387+ s.deleteFile(dstVolumeDir, dstDataPath, false, false)
23712388 return osErrToFileErr(err)
23722389 }
23732390 }
@@ -2376,9 +2393,9 @@ func (s *xlStorage) RenameData(ctx context.Context, srcVolume, srcPath string, f · 2 unmodified lines
23762393 if err = renameAll(srcFilePath, dstFilePath); err != nil {
23772394 if legacyPreserved {
23782395 // Any failed rename calls un-roll previous transaction.
2379− s.deleteFile(dstVolumeDir, legacyDataPath, true)
2396+ s.deleteFile(dstVolumeDir, legacyDataPath, true, false)
23802397 }
2381− s.deleteFile(dstVolumeDir, dstFilePath, false)
2398+ s.deleteFile(dstVolumeDir, dstFilePath, false, false)
23822399 return osErrToFileErr(err)
23832400 }
23842401
@@ -2386,16 +2403,16 @@ func (s *xlStorage) RenameData(ctx context.Context, srcVolume, srcPath string, f · 1 unmodified line
23862403 // movement, this is to ensure that previous data references can co-exist for
23872404 // any recoverability.
23882405 if oldDstDataPath != "" {
2389− s.moveToTrash(oldDstDataPath, true)
2406+ s.moveToTrash(oldDstDataPath, true, false)
23902407 }
23912408 } else {
23922409 // Write meta-file directly, no data
23932410 if err = s.WriteAll(ctx, dstVolume, pathJoin(dstPath, xlStorageFormatFile), dstBuf); err != nil {
23942411 if legacyPreserved {
23952412 // Any failed rename calls un-roll previous transaction.
2396− s.deleteFile(dstVolumeDir, legacyDataPath, true)
2413+ s.deleteFile(dstVolumeDir, legacyDataPath, true, false)
23972414 }
2398− s.deleteFile(dstVolumeDir, dstFilePath, false)
2415+ s.deleteFile(dstVolumeDir, dstFilePath, false, false)
23992416 return err
24002417 }
24012418 }
@@ -2484,7 +2501,7 @@ func (s *xlStorage) RenameFile(ctx context.Context, srcVolume, srcPath, dstVolum · 82 unmodified lines
24842501
24852502 // Remove parent dir of the source file if empty
24862503 parentDir := pathutil.Dir(srcFilePath)
2487− s.deleteFile(srcVolumeDir, parentDir, false)
2504+ s.deleteFile(srcVolumeDir, parentDir, false, false)
24882505
24892506 return nil
24902507 }
cmd/xl-storage_test.go+24−6
@@ -933,14 +933,20 @@ func TestXLStorageListDir(t *testing.T) { · 932 unmodified lines
933933 t.Fatalf("Unable to initialize xlStorage, %s", err)
934934 }
935935
936− if err = xlStorageNew.Delete(context.Background(), "mybucket", "myobject", false); err != errVolumeAccessDenied {
936+ if err = xlStorageNew.Delete(context.Background(), "mybucket", "myobject", DeleteOptions{
937+ Recursive: false,
938+ Force: false,
939+ }); err != errVolumeAccessDenied {
937940 t.Errorf("expected: %s, got: %s", errVolumeAccessDenied, err)
938941 }
939942 }
940943
941944 // TestXLStorage for delete on an removed disk.
942945 // should fail with disk not found.
943− err = xlStorageDeletedStorage.Delete(context.Background(), "del-vol", "my-file", false)
946+ err = xlStorageDeletedStorage.Delete(context.Background(), "del-vol", "my-file", DeleteOptions{
947+ Recursive: false,
948+ Force: false,
949+ })
944950 if err != errDiskNotFound {
945951 t.Errorf("Expected: \"Disk not found\", got \"%s\"", err)
946952 }
@@ -1029,7 +1035,10 @@ func TestXLStorageDeleteFile(t *testing.T) { · 82 unmodified lines
10291035 }
10301036
10311037 for i, testCase := range testCases {
1032− if err = xlStorage.Delete(context.Background(), testCase.srcVol, testCase.srcPath, false); err != testCase.expectedErr {
1038+ if err = xlStorage.Delete(context.Background(), testCase.srcVol, testCase.srcPath, DeleteOptions{
1039+ Recursive: false,
1040+ Force: false,
1041+ }); err != testCase.expectedErr {
10331042 t.Errorf("TestXLStorage case %d: Expected: \"%s\", got: \"%s\"", i+1, testCase.expectedErr, err)
10341043 }
10351044 }
@@ -1054,7 +1063,10 @@ func TestXLStorageDeleteFile(t *testing.T) { · 18 unmodified lines
10541063 t.Fatalf("Unable to initialize xlStorage, %s", err)
10551064 }
10561065
1057− if err = xlStorageNew.Delete(context.Background(), "mybucket", "myobject", false); err != errVolumeAccessDenied {
1066+ if err = xlStorageNew.Delete(context.Background(), "mybucket", "myobject", DeleteOptions{
1067+ Recursive: false,
1068+ Force: false,
1069+ }); err != errVolumeAccessDenied {
10581070 t.Errorf("expected: %s, got: %s", errVolumeAccessDenied, err)
10591071 }
10601072 }
@@ -1072,7 +1084,10 @@ func TestXLStorageDeleteFile(t *testing.T) { · 11 unmodified lines
10721084
10731085 // TestXLStorage for delete on an removed disk.
10741086 // should fail with disk not found.
1075− err = xlStorageDeletedStorage.Delete(context.Background(), "del-vol", "my-file", false)
1087+ err = xlStorageDeletedStorage.Delete(context.Background(), "del-vol", "my-file", DeleteOptions{
1088+ Recursive: false,
1089+ Force: false,
1090+ })
10761091 if err != errDiskNotFound {
10771092 t.Errorf("Expected: \"Disk not found\", got \"%s\"", err)
10781093 }
@@ -1907,7 +1922,10 @@ func TestXLStorageVerifyFile(t *testing.T) { · 828 unmodified lines
19071922 t.Fatal("expected to fail bitrot check")
19081923 }
19091924
1910− if err := storage.Delete(context.Background(), volName, fileName, false); err != nil {
1925+ if err := storage.Delete(context.Background(), volName, fileName, DeleteOptions{
1926+ Recursive: false,
1927+ Force: false,
1928+ }); err != nil {
19111929 t.Fatal(err)
19121930 }
19131931
cmd/xl-storage_windows_test.go+4−1
@@ -70,7 +70,10 @@ func TestUNCPaths(t *testing.T) { · 69 unmodified lines
7070 } else if err == nil && !test.pass {
7171 t.Error(err)
7272 }
73− fs.Delete(context.Background(), "voldir", test.objName, false)
73+ fs.Delete(context.Background(), "voldir", test.objName, DeleteOptions{
74+ Recursive: false,
75+ Force: false,
76+ })
7477 })
7578 }
7679 }

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t