mirror of
https://github.com/pgsty/minio.git
synced 2026-11-11 01:55:30 +03:00
perf(pools): read a key's history once in a migration walk's prechecks
A decommission or rebalance walk prechecks each due version of a key with the versions of the key in all pools, to decide whether the version moves or is left to its ILM expiry. Each precheck read and merged the key's whole history from every pool, so a key with V due versions read it V times in the walk alone; with long histories this grew roughly quadratically. Read the history once per key into a cache that the walk keeps for the entry, and evaluate every version's precheck against it. The precheck only chooses between moving a version and leaving it to the expiry; the expiry reads the history again under the object lock before it deletes anything, so a stale cache can only move a version or defer it to a recheck. A read error is kept, so every due version of that key moves. The expiry's own per-version reads are unchanged. Test: decommission and rebalance of a key with 63 due noncurrent versions read its history once, with the same outcome; without the cache they read it 63 times. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Feng Ruohang <rh@vonng.com>
This commit is contained in:
@@ -590,7 +590,7 @@ func (z *erasureServerPools) rebalanceBucket(ctx context.Context, bucket string,
|
||||
for setIdx, set := range pool.sets {
|
||||
// filterLifecycle returns an ILM deletion that migration must handle
|
||||
// before retiring the source copy, or NoneAction.
|
||||
filterLifecycle := func(bucket, object string, fi FileInfo) lifecycle.Action {
|
||||
filterLifecycle := func(bucket, object string, fi FileInfo, history *migrationHistory) lifecycle.Action {
|
||||
if lc == nil {
|
||||
return lifecycle.NoneAction
|
||||
}
|
||||
@@ -605,7 +605,7 @@ func (z *erasureServerPools) rebalanceBucket(ctx context.Context, bucket string,
|
||||
// a noncurrent version and has to be moved like any other. The
|
||||
// scanner applies the expiry once it lives in another pool.
|
||||
return lifecycle.NoneAction
|
||||
case evt.Action.Delete() && !z.migrationExpiryApplies(ctx, objInfo, evt):
|
||||
case evt.Action.Delete() && !z.migrationExpiryApplies(ctx, objInfo, evt, history):
|
||||
// Another pool holds versions with which the rule does not
|
||||
// apply. The version moves like any other.
|
||||
return lifecycle.NoneAction
|
||||
@@ -638,6 +638,8 @@ func (z *erasureServerPools) rebalanceBucket(ctx context.Context, bucket string,
|
||||
|
||||
var rebalanced int
|
||||
var expired []migrationExpiredVersion
|
||||
// The key's history in all pools, read once for its versions.
|
||||
var history migrationHistory
|
||||
for _, version := range fivs.Versions {
|
||||
stopFn := globalRebalanceMetrics.log(rebalanceMetricRebalanceObject, poolIdx, bucket, version.Name, version.VersionID)
|
||||
|
||||
@@ -648,7 +650,7 @@ func (z *erasureServerPools) rebalanceBucket(ctx context.Context, bucket string,
|
||||
}
|
||||
|
||||
// Apply lifecycle rules on the objects that are expired.
|
||||
if action := filterLifecycle(bucket, version.Name, version); action.Delete() {
|
||||
if action := filterLifecycle(bucket, version.Name, version, &history); action.Delete() {
|
||||
// Count the version, or the source copies of the moved
|
||||
// ones stay behind as duplicates. Its own source copy
|
||||
// goes with them when ILM deletes it alone; any other
|
||||
|
||||
Reference in New Issue
Block a user