Address review feedback on the routed fast paths:
- PutObject: map the response's machine-readable FilerError code to the same S3
error the lock path produces (key-too-long, parent/existing-is-file,
existing-is-directory, precondition), instead of re-wrapping resp.Error in a
fresh error that filerErrorToS3Error can no longer match by sentinel. Unknown
codes and in-band errors fall back to the lock path for exact semantics.
- DeleteObject: on any non-precondition routed error, fall back to the lock
path instead of returning InternalError. This restores directory-marker
handling (demote a marker that still has children rather than failing on a
non-empty folder), which the raw DeleteEntry call lacks.
For non-versioned, non-object-lock buckets, PutObject and unversioned
DeleteObject now send their metadata write straight to the object key's owner
filer (resolved from the lock-ring view) with the precondition attached. The
owner serializes the write with its local per-path lock and evaluates the
condition atomically, so these paths no longer acquire a distributed lock.
The fast path is opt-in per request and falls back to withObjectWriteLock for
anything it does not fully cover: versioned or object-lock buckets, conditions
that do not reduce to a single primitive (ETag lists, weak ETags, time-based,
combined headers), an unresolved owner, or an unreachable owner filer. So
behavior is unchanged outside the safe subset.
Multi-step finalizations (copy, CompleteMultipartUpload) and versioned writes
keep the distributed lock: they mutate several entries under one held lock,
which a single conditional create or delete does not cover.
DeleteEntry gains the same optional WriteCondition and per-path lock as
CreateEntry so a routed conditional delete is atomic on the owner.