mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-09-20 13:30:46 +02:00
s3: commit a versioned PutObject and its latest pointer in one transaction (#9756)
* s3: commit a versioned PutObject and its latest pointer in one transaction A versioned PutObject wrote the version file and flipped the .versions latest pointer in two separate routed transactions. Fold the RECOMPUTE_LATEST into the version file's PUT so both commit atomically under the object's per-path lock: the recompute, applied after the PUT in the same transaction, scans the directory and sees the new version. A crash can no longer leave the version present with a stale pointer. putToFiler now takes a putFinalize describing the finalize step — routed mutations folded into the PUT, or an afterCreate run under the object write lock off the ring. Suspended-versioning keeps its afterCreate-only form; multipart, copy, and delete-marker finalizes are unchanged. * s3: trim verbose finalize comments
This commit is contained in:
@@ -170,19 +170,20 @@ func (s3a *S3ApiServer) routedDeleteNullVersion(owner pb.ServerAddress, bucket,
|
||||
}
|
||||
}
|
||||
|
||||
// versionedAfterCreate returns the putToFiler hook that finalizes a versioned
|
||||
// write: the routed RECOMPUTE_LATEST when the owner is known, else the existing
|
||||
// lock-free updateLatestVersionInDirectory.
|
||||
func (s3a *S3ApiServer) versionedAfterCreate(bucket, object, versionId, versionFileName string, useInvertedFormat bool) func(*filer_pb.Entry) s3err.ErrorCode {
|
||||
owner := s3a.objectWriteOwner(bucket, object)
|
||||
return func(versionEntry *filer_pb.Entry) s3err.ErrorCode {
|
||||
if owner != "" {
|
||||
return s3a.routedVersionedFinalize(owner, bucket, object, useInvertedFormat)
|
||||
}
|
||||
if err := s3a.updateLatestVersionInDirectory(bucket, object, versionId, versionFileName, versionEntry); err != nil {
|
||||
glog.Errorf("putVersionedObject: failed to update latest version in directory: %v", err)
|
||||
return s3err.ErrInternalError
|
||||
}
|
||||
return s3err.ErrNone
|
||||
// versionedFinalize flips the .versions latest pointer for a versioned PutObject:
|
||||
// on the routed path RECOMPUTE_LATEST rides in the version file's PUT transaction,
|
||||
// committing atomically under the object's per-path lock; off the ring
|
||||
// updateLatestVersionInDirectory does it under the object write lock.
|
||||
func (s3a *S3ApiServer) versionedFinalize(bucket, object, versionId, versionFileName string, useInvertedFormat bool) *putFinalize {
|
||||
return &putFinalize{
|
||||
lockKey: s3a.toFilerPath(bucket, object),
|
||||
mutations: []*filer_pb.ObjectMutation{s3a.latestPointerRecompute(bucket, object, useInvertedFormat, "", true)},
|
||||
afterCreate: func(versionEntry *filer_pb.Entry) s3err.ErrorCode {
|
||||
if err := s3a.updateLatestVersionInDirectory(bucket, object, versionId, versionFileName, versionEntry); err != nil {
|
||||
glog.Errorf("putVersionedObject: failed to update latest version in directory: %v", err)
|
||||
return s3err.ErrInternalError
|
||||
}
|
||||
return s3err.ErrNone
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user