diff --git a/cmd/data-crawler.go b/cmd/data-crawler.go index 08a84c4de..723b0fb2e 100644 --- a/cmd/data-crawler.go +++ b/cmd/data-crawler.go @@ -509,8 +509,9 @@ func (i *crawlItem) transformMetaDir() { // actionMeta contains information used to apply actions. type actionMeta struct { - oi ObjectInfo - trustOI bool // Set true if oi can be trusted and has been read with quorum. + oi ObjectInfo + trustOI bool // Set true if oi can be trusted and has been read with quorum. + numVersions int // The number of versions of this object } // applyActions will apply lifecycle checks on to a scanned item. @@ -535,12 +536,13 @@ func (i *crawlItem) applyActions(ctx context.Context, o ObjectLayer, meta action VersionID: meta.oi.VersionID, DeleteMarker: meta.oi.DeleteMarker, IsLatest: meta.oi.IsLatest, + NumVersions: meta.numVersions, }) if i.debug { logger.Info(color.Green("applyActions:")+" lifecycle: %q, Initial scan: %v", i.objectPath(), action) } switch action { - case lifecycle.DeleteAction: + case lifecycle.DeleteAction, lifecycle.DeleteVersionAction: default: // No action. return size @@ -586,14 +588,22 @@ func (i *crawlItem) applyActions(ctx context.Context, o ObjectLayer, meta action } versionID = obj.VersionID switch action { - case lifecycle.DeleteAction: + case lifecycle.DeleteAction, lifecycle.DeleteVersionAction: default: // No action. return size } } - obj, err := o.DeleteObject(ctx, i.bucket, i.objectPath(), ObjectOptions{VersionID: versionID}) + opts := ObjectOptions{} + switch action { + case lifecycle.DeleteVersionAction: + opts.VersionID = versionID + case lifecycle.DeleteAction: + opts.Versioned = globalBucketVersioningSys.Enabled(i.bucket) + } + + obj, err := o.DeleteObject(ctx, i.bucket, i.objectPath(), opts) if err != nil { // Assume it is still there. logger.LogIf(ctx, err) diff --git a/cmd/xl-storage.go b/cmd/xl-storage.go index 20033fa37..87efcfd68 100644 --- a/cmd/xl-storage.go +++ b/cmd/xl-storage.go @@ -408,7 +408,7 @@ func (s *xlStorage) CrawlAndGetDataUsage(ctx context.Context, cache dataUsageCac var totalSize int64 for _, version := range fivs.Versions { - size := item.applyActions(ctx, objAPI, actionMeta{oi: version.ToObjectInfo(item.bucket, item.objectPath())}) + size := item.applyActions(ctx, objAPI, actionMeta{numVersions: len(fivs.Versions), oi: version.ToObjectInfo(item.bucket, item.objectPath())}) if !version.Deleted { totalSize += size } diff --git a/pkg/bucket/lifecycle/lifecycle.go b/pkg/bucket/lifecycle/lifecycle.go index 5e62c2752..613689d45 100644 --- a/pkg/bucket/lifecycle/lifecycle.go +++ b/pkg/bucket/lifecycle/lifecycle.go @@ -40,6 +40,8 @@ const ( NoneAction Action = iota // DeleteAction means the object needs to be removed after evaluting lifecycle rules DeleteAction + // DeleteVersionAction deletes a particular version + DeleteVersionAction ) // Lifecycle - Configuration for bucket lifecycle. @@ -176,6 +178,7 @@ type ObjectOpts struct { VersionID string IsLatest bool DeleteMarker bool + NumVersions int } // ComputeAction returns the action to perform by evaluating all lifecycle rules @@ -187,27 +190,28 @@ func (lc Lifecycle) ComputeAction(obj ObjectOpts) Action { } for _, rule := range lc.FilterActionableRules(obj) { - if obj.DeleteMarker && obj.IsLatest && bool(rule.Expiration.DeleteMarker) { + if obj.DeleteMarker && obj.NumVersions == 1 && bool(rule.Expiration.DeleteMarker) { // Indicates whether MinIO will remove a delete marker with no noncurrent versions. // Only latest marker is removed. If set to true, the delete marker will be expired; // if set to false the policy takes no action. This cannot be specified with Days or // Date in a Lifecycle Expiration Policy. - return DeleteAction + return DeleteVersionAction } if !rule.NoncurrentVersionExpiration.IsDaysNull() { if obj.VersionID != "" && !obj.IsLatest { // Non current versions should be deleted. if time.Now().After(expectedExpiryTime(obj.ModTime, rule.NoncurrentVersionExpiration.NoncurrentDays)) { - return DeleteAction + return DeleteVersionAction } return NoneAction } return NoneAction } - // All other expiration only applies to latest versions. - if obj.IsLatest { + // All other expiration only applies to latest versions + // (except if this is a delete marker) + if obj.IsLatest && !obj.DeleteMarker { switch { case !rule.Expiration.IsDateNull(): if time.Now().UTC().After(rule.Expiration.Date.Time) {