s3: route versioned PutObject finalize off the DLM (#9631)

s3: route versioned PutObject finalize off the distributed lock

A versioned write's finalize (flip the .versions pointer to the newest version,
demote the prior latest) now runs as a single RECOMPUTE_LATEST ObjectTransaction
on the object's owner filer, under its per-path lock, instead of the unserialized
updateLatestVersionInDirectory. The version file is written first; the owner
re-derives the pointer by scanning the directory.

RECOMPUTE_LATEST gains size_to_key / mtime_to_key to cache the chosen version's
size and mtime on the pointer, and demote_key / demote_value to stamp the
displaced prior latest (NoncurrentSinceNs for lifecycle) when the pointer moves.

Falls back to updateLatestVersionInDirectory when no owner is known yet.
This commit is contained in:
Chris Lu authored and GitHub committed 2026-05-24 03:10:30 -07:00
1 parent 32aa70ab59
commit db954b5503
8 files changed
+246 -18

No files matched your search

+8 -6
View File
@@ -15,23 +15,25 @@ import (
)
// routableWriteOwner returns the owner filer for an object's writes, or "" to
// keep them on the distributed lock. Versioned and object-lock buckets stay on
// the lock (handled by later routing PRs); any lookup error also falls back.
// keep them on the distributed lock. All writes to one object (versioned,
// suspended, non-versioned) share the owner; object-lock buckets stay on the
// lock until WORM-guard routing. Any lookup error also falls back.
func (s3a *S3ApiServer) routableWriteOwner(bucket, object string) pb.ServerAddress {
if object == "" || s3a.objectWriteLockClient == nil {
return ""
}
if configured, err := s3a.isVersioningConfigured(bucket); err != nil || configured {
return ""
}
if locked, err := s3a.isObjectLockEnabled(bucket); err != nil || locked {
return ""
}
return s3a.objectWriteLockClient.PrimaryForKey(fmt.Sprintf("s3.object.write:%s", s3a.toFilerPath(bucket, object)))
}
// routedObjectOwner resolves the owner for the unversioned DELETE fast path.
// routedObjectOwner is routableWriteOwner restricted to non-versioned buckets,
// for the unversioned DELETE fast path.
func (s3a *S3ApiServer) routedObjectOwner(bucket, object string) (pb.ServerAddress, bool) {
if configured, err := s3a.isVersioningConfigured(bucket); err != nil || configured {
return "", false
}
owner := s3a.routableWriteOwner(bucket, object)
return owner, owner != ""
}