in internal/gcsx/compose_object_creator.go [84:175]
func (oc *composeObjectCreator) Create(
ctx context.Context,
objectName string,
srcObject *gcs.Object,
mtime *time.Time,
chunkTransferTimeoutSecs int64,
r io.Reader) (o *gcs.Object, err error) {
// Choose a name for a temporary object.
tmpName, err := oc.chooseName()
if err != nil {
err = fmt.Errorf("chooseName: %w", err)
return
}
// Create a temporary object containing the additional contents.
req := gcs.NewCreateObjectRequest(nil, tmpName, nil, chunkTransferTimeoutSecs)
req.Contents = r
tmp, err := oc.bucket.CreateObject(ctx, req)
if err != nil {
err = fmt.Errorf("CreateObject: %w", err)
return
}
// Attempt to delete the temporary object when we're done.
defer func() {
deleteErr := oc.bucket.DeleteObject(
ctx,
&gcs.DeleteObjectRequest{
Name: tmp.Name,
Generation: 0, // Delete the latest generation of temporary object.
})
if err == nil && deleteErr != nil {
err = fmt.Errorf("DeleteObject: %w", deleteErr)
}
}()
MetadataMap := make(map[string]string)
/* Copy Metadata fields from src object to new object generated by compose. */
for key, value := range srcObject.Metadata {
MetadataMap[key] = value
}
if mtime != nil {
MetadataMap[gcs.MtimeMetadataKey] = mtime.UTC().Format(time.RFC3339Nano)
}
// Compose the old contents plus the new over the old.
o, err = oc.bucket.ComposeObjects(
ctx,
&gcs.ComposeObjectsRequest{
DstName: srcObject.Name,
DstGenerationPrecondition: &srcObject.Generation,
DstMetaGenerationPrecondition: &srcObject.MetaGeneration,
Sources: []gcs.ComposeSource{
gcs.ComposeSource{
Name: srcObject.Name,
Generation: srcObject.Generation,
},
gcs.ComposeSource{
Name: tmp.Name,
Generation: tmp.Generation,
},
},
Metadata: MetadataMap,
CacheControl: srcObject.CacheControl,
ContentDisposition: srcObject.ContentDisposition,
ContentEncoding: srcObject.ContentEncoding,
ContentType: srcObject.ContentType,
CustomTime: srcObject.CustomTime,
EventBasedHold: srcObject.EventBasedHold,
StorageClass: srcObject.StorageClass,
})
if err != nil {
// A not found error means that either the source object was clobbered or the
// temporary object was. The latter is unlikely, so we signal a precondition
// error.
var notFoundErr *gcs.NotFoundError
if errors.As(err, ¬FoundErr) {
err = &gcs.PreconditionError{
Err: err,
}
}
err = fmt.Errorf("ComposeObjects: %w", err)
return
}
return
}