2021-07-02 15:12:43 +01:00
|
|
|
// Copyright (C) 2020 Storj Labs, Inc.
|
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
|
|
|
package metabase
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
|
2022-08-12 18:52:02 +01:00
|
|
|
"go.uber.org/zap"
|
|
|
|
|
|
|
|
"storj.io/common/uuid"
|
2021-07-02 15:12:43 +01:00
|
|
|
)
|
|
|
|
|
2021-07-08 15:50:37 +01:00
|
|
|
// UpdateObjectMetadata contains arguments necessary for replacing an object metadata.
|
|
|
|
type UpdateObjectMetadata struct {
|
2022-08-12 18:52:02 +01:00
|
|
|
ProjectID uuid.UUID
|
|
|
|
BucketName string
|
|
|
|
ObjectKey ObjectKey
|
|
|
|
StreamID uuid.UUID
|
2021-07-02 15:12:43 +01:00
|
|
|
|
|
|
|
EncryptedMetadata []byte
|
2021-10-12 14:37:12 +01:00
|
|
|
EncryptedMetadataNonce []byte
|
2021-07-02 15:12:43 +01:00
|
|
|
EncryptedMetadataEncryptedKey []byte
|
|
|
|
}
|
|
|
|
|
2022-08-12 18:52:02 +01:00
|
|
|
// Verify object stream fields.
|
|
|
|
func (obj *UpdateObjectMetadata) Verify() error {
|
|
|
|
switch {
|
|
|
|
case obj.ProjectID.IsZero():
|
|
|
|
return ErrInvalidRequest.New("ProjectID missing")
|
|
|
|
case obj.BucketName == "":
|
|
|
|
return ErrInvalidRequest.New("BucketName missing")
|
|
|
|
case len(obj.ObjectKey) == 0:
|
|
|
|
return ErrInvalidRequest.New("ObjectKey missing")
|
|
|
|
case obj.StreamID.IsZero():
|
|
|
|
return ErrInvalidRequest.New("StreamID missing")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-07-08 15:50:37 +01:00
|
|
|
// UpdateObjectMetadata updates an object metadata.
|
|
|
|
func (db *DB) UpdateObjectMetadata(ctx context.Context, opts UpdateObjectMetadata) (err error) {
|
2021-07-02 15:12:43 +01:00
|
|
|
defer mon.Task()(&ctx)(&err)
|
|
|
|
|
2022-08-12 18:52:02 +01:00
|
|
|
if err := opts.Verify(); err != nil {
|
2021-07-02 15:12:43 +01:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO So the issue is that during a multipart upload of an object,
|
|
|
|
// uplink can update object metadata. If we add the arguments EncryptedMetadata
|
|
|
|
// to CommitObject, they will need to account for them being optional.
|
|
|
|
// Leading to scenarios where uplink calls update metadata, but wants to clear them
|
|
|
|
// during commit object.
|
|
|
|
result, err := db.db.ExecContext(ctx, `
|
|
|
|
UPDATE objects SET
|
2022-08-12 18:52:02 +01:00
|
|
|
encrypted_metadata_nonce = $5,
|
|
|
|
encrypted_metadata = $6,
|
|
|
|
encrypted_metadata_encrypted_key = $7
|
2021-07-02 15:12:43 +01:00
|
|
|
WHERE
|
2021-07-08 15:50:37 +01:00
|
|
|
project_id = $1 AND
|
|
|
|
bucket_name = $2 AND
|
|
|
|
object_key = $3 AND
|
2022-08-12 18:52:02 +01:00
|
|
|
version IN (SELECT version FROM objects WHERE
|
|
|
|
project_id = $1 AND
|
|
|
|
bucket_name = $2 AND
|
|
|
|
object_key = $3 AND
|
|
|
|
status = `+committedStatus+` AND
|
|
|
|
(expires_at IS NULL OR expires_at > now())
|
|
|
|
ORDER BY version desc
|
|
|
|
) AND
|
|
|
|
stream_id = $4 AND
|
2021-07-08 15:50:37 +01:00
|
|
|
status = `+committedStatus,
|
2022-08-12 18:52:02 +01:00
|
|
|
opts.ProjectID, []byte(opts.BucketName), opts.ObjectKey, opts.StreamID,
|
2021-07-02 15:12:43 +01:00
|
|
|
opts.EncryptedMetadataNonce, opts.EncryptedMetadata, opts.EncryptedMetadataEncryptedKey)
|
|
|
|
if err != nil {
|
|
|
|
return Error.New("unable to update object metadata: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
affected, err := result.RowsAffected()
|
|
|
|
if err != nil {
|
|
|
|
return Error.New("failed to get rows affected: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if affected == 0 {
|
2023-04-19 10:54:16 +01:00
|
|
|
return ErrObjectNotFound.New("object with specified version and committed status is missing")
|
2022-08-12 18:52:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if affected > 1 {
|
|
|
|
db.log.Warn("object with multiple committed versions were found!",
|
|
|
|
zap.Stringer("Project ID", opts.ProjectID), zap.String("Bucket Name", opts.BucketName),
|
|
|
|
zap.String("Object Key", string(opts.ObjectKey)), zap.Stringer("Stream ID", opts.StreamID))
|
|
|
|
mon.Meter("multiple_committed_versions").Mark(1)
|
2021-07-02 15:12:43 +01:00
|
|
|
}
|
|
|
|
|
2022-08-12 18:52:02 +01:00
|
|
|
mon.Meter("object_update_metadata").Mark(int(affected))
|
2021-07-02 15:12:43 +01:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|