Skip to content

Commit

Permalink
stores: check if object exists before deleting
Browse files Browse the repository at this point in the history
  • Loading branch information
ChrisSchinnerl committed Mar 12, 2024
1 parent 508624d commit 6004fa3
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 26 deletions.
36 changes: 19 additions & 17 deletions stores/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -1723,8 +1723,7 @@ func (s *SQLStore) UpdateObject(ctx context.Context, bucket, path, contractSet,
usedContracts := o.Contracts()

// UpdateObject is ACID.
var nDeleted int64
err := s.retryTransaction(func(tx *gorm.DB) error {
return s.retryTransaction(func(tx *gorm.DB) error {
// Try to delete. We want to get rid of the object and its slices if it
// exists.
//
Expand All @@ -1735,12 +1734,10 @@ func (s *SQLStore) UpdateObject(ctx context.Context, bucket, path, contractSet,
// NOTE: the metadata is not deleted because this delete will cascade,
// if we stop recreating the object we have to make sure to delete the
// object's metadata before trying to recreate it
var err error
resp := tx.Exec("DELETE FROM objects WHERE object_id = ? AND db_bucket_id = ?", path, bucketID)
if resp.Error != nil {
return fmt.Errorf("UpdateObject: failed to delete object: %w", resp.Error)
_, err := s.deleteObject(tx, bucket, path)
if err != nil {
return fmt.Errorf("UpdateObject: failed to delete object: %w", err)
}
nDeleted = resp.RowsAffected

// Insert a new object.
objKey, err := o.Key.MarshalBinary()
Expand Down Expand Up @@ -1796,15 +1793,6 @@ func (s *SQLStore) UpdateObject(ctx context.Context, bucket, path, contractSet,
}
return nil
})
if err != nil {
return err
}
if nDeleted > 0 {
if err := s.retryTransaction(pruneSlabs); err != nil {
return fmt.Errorf("UpdateObject: failed to prune slabs: %w", err)
}
}
return pruneSlabs(s.db)
}

func (s *SQLStore) RemoveObject(ctx context.Context, bucket, key string) error {
Expand Down Expand Up @@ -2757,7 +2745,21 @@ AND slabs.db_buffered_slab_id IS NULL
// without an obect after the deletion. That means in case of packed uploads,
// the slab is only deleted when no more objects point to it.
func (s *SQLStore) deleteObject(tx *gorm.DB, bucket string, path string) (int64, error) {
tx = tx.Where("object_id = ? AND ?", path, sqlWhereBucket("objects", bucket)).
// check if the object exists first to avoid unnecessary locking for the
// common case
var objID uint
resp := tx.Model(&dbObject{}).
Where("object_id = ? AND ?", path, sqlWhereBucket("objects", bucket)).
Select("id").
Limit(1).
Scan(&objID)
if err := resp.Error; err != nil {
return 0, err
} else if resp.RowsAffected == 0 {
return 0, nil
}

tx = tx.Where("id", objID).
Delete(&dbObject{})
if tx.Error != nil {
return 0, tx.Error
Expand Down
21 changes: 12 additions & 9 deletions stores/metadata_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4550,6 +4550,11 @@ func TestTypeCurrency(t *testing.T) {
// TestUpdateObjectParallel calls UpdateObject from multiple threads in parallel
// while retries are disabled to make sure calling the same method from multiple
// threads won't cause deadlocks.
//
// NOTE: This test only covers the optimistic case of inserting objects without
// overwriting them. As soon as combining deletions and insertions within the
// same transaction, deadlocks become more likely due to the gap locks MySQL
// uses.
func TestUpdateObjectParallel(t *testing.T) {
cfg := defaultTestSQLStoreConfig

Expand Down Expand Up @@ -4591,7 +4596,7 @@ func TestUpdateObjectParallel(t *testing.T) {
Health: 1.0,
Key: object.GenerateEncryptionKey(),
MinShards: 1,
Shards: newTestShards(hk1, fcid1, types.Hash256{1}),
Shards: newTestShards(hk1, fcid1, frand.Entropy256()),
},
Offset: 10,
Length: 100,
Expand All @@ -4601,7 +4606,7 @@ func TestUpdateObjectParallel(t *testing.T) {
Health: 1.0,
Key: object.GenerateEncryptionKey(),
MinShards: 2,
Shards: newTestShards(hk2, fcid2, types.Hash256{2}),
Shards: newTestShards(hk2, fcid2, frand.Entropy256()),
},
Offset: 20,
Length: 200,
Expand All @@ -4627,13 +4632,11 @@ func TestUpdateObjectParallel(t *testing.T) {
}

// create 1000 objects and then overwrite them
for i := 0; i < 2; i++ {
for j := 0; j < 1000; j++ {
select {
case c <- fmt.Sprintf("object-%d", j):
case <-ctx.Done():
return
}
for i := 0; i < 1000; i++ {
select {
case c <- fmt.Sprintf("object-%d", i):
case <-ctx.Done():
return
}
}

Expand Down

0 comments on commit 6004fa3

Please sign in to comment.