From fa4e7966a8f1efbc369009ea7b8e70a63ec8b96f Mon Sep 17 00:00:00 2001 From: PJ Date: Mon, 4 Mar 2024 16:31:37 +0100 Subject: [PATCH 1/2] stores: update RefreshHealth query and add unit test --- stores/metadata.go | 46 ++++------------ stores/metadata_test.go | 117 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+), 36 deletions(-) diff --git a/stores/metadata.go b/stores/metadata.go index 901c0f73b..529d7ec89 100644 --- a/stores/metadata.go +++ b/stores/metadata.go @@ -1991,42 +1991,16 @@ LIMIT ? rowsAffected = res.RowsAffected // Update the health of objects with outdated health. - var err error - if isSQLite(tx) { - err = tx.Exec(` - UPDATE objects - SET health = ( - SELECT MIN(slabs.health) - FROM slabs - INNER JOIN slices ON slices.db_slab_id = slabs.id - INNER JOIN objects ON slices.db_object_id = objects.id - ) - WHERE EXISTS ( - SELECT 1 FROM slabs - INNER JOIN slices ON slices.db_slab_id = slabs.id - INNER JOIN objects ON slices.db_object_id = objects.id - WHERE slabs.health < objects.health - ) - `).Error - } else { - err = tx.Exec(` - UPDATE objects - JOIN ( - SELECT slices.db_object_id, MIN(slabs.health) AS min_health - FROM slabs - INNER JOIN slices ON slices.db_slab_id = slabs.id - GROUP BY slices.db_object_id - ) AS min_healths ON objects.id = min_healths.db_object_id - SET objects.health = min_healths.min_health - WHERE objects.health > ( - SELECT MIN(slabs.health) - FROM slabs - INNER JOIN slices ON slices.db_slab_id = slabs.id - WHERE slices.db_object_id = objects.id - ); - `).Error - } - return err + return tx.Exec(` +UPDATE objects SET health = ( + SELECT MIN(slabs.health) + FROM slabs + INNER JOIN slices ON slices.db_slab_id = slabs.id AND slices.db_object_id = objects.id +) WHERE health != ( + SELECT MIN(slabs.health) + FROM slabs + INNER JOIN slices ON slices.db_slab_id = slabs.id AND slices.db_object_id = objects.id +)`).Error }) if err != nil { return err diff --git a/stores/metadata_test.go b/stores/metadata_test.go index 16e104695..a5fc76b05 100644 --- a/stores/metadata_test.go +++ b/stores/metadata_test.go @@ -3879,6 +3879,123 @@ func TestSlabHealthInvalidation(t *testing.T) { } } +func TestRefreshHealth(t *testing.T) { + ss := newTestSQLStore(t, defaultTestSQLStoreConfig) + defer ss.Close() + + // define a helper function to return an object's health + health := func(name string) float64 { + t.Helper() + o, err := ss.Object(context.Background(), api.DefaultBucketName, name) + if err != nil { + t.Fatal(err) + } + return o.Health + } + + // add test hosts + hks, err := ss.addTestHosts(2) + if err != nil { + t.Fatal(err) + } + + // add test contract & set it as contract set + fcids, _, err := ss.addTestContracts(hks) + if err != nil { + t.Fatal(err) + } + err = ss.SetContractSet(context.Background(), testContractSet, fcids) + if err != nil { + t.Fatal(err) + } + + // add two test objects + o1 := t.Name() + "1" + s1 := object.GenerateEncryptionKey() + if added, err := ss.addTestObject(o1, object.Object{ + Key: object.GenerateEncryptionKey(), + Slabs: []object.SlabSlice{{Slab: object.Slab{ + Key: s1, + Shards: []object.Sector{ + newTestShard(hks[0], fcids[0], types.Hash256{0}), + newTestShard(hks[1], fcids[1], types.Hash256{1}), + }, + }}}, + }); err != nil { + t.Fatal(err) + } else if added.Health != 1 { + t.Fatal("expected health to be 1, got", added.Health) + } + + o2 := t.Name() + "2" + s2 := object.GenerateEncryptionKey() + if added, err := ss.addTestObject(o2, object.Object{ + Key: object.GenerateEncryptionKey(), + Slabs: []object.SlabSlice{{Slab: object.Slab{ + Key: s2, + Shards: []object.Sector{ + newTestShard(hks[0], fcids[0], types.Hash256{2}), + newTestShard(hks[1], fcids[1], types.Hash256{3}), + }, + }}}, + }); err != nil { + t.Fatal(err) + } else if added.Health != 1 { + t.Fatal("expected health to be 1, got", added.Health) + } + + // update contract set and refresh health, assert health is .5 + err = ss.SetContractSet(context.Background(), testContractSet, fcids[:1]) + if err != nil { + t.Fatal(err) + } + err = ss.RefreshHealth(context.Background()) + if err != nil { + t.Fatal(err) + } + if health(o1) != .5 { + t.Fatal("expected health to be .5, got", health(o1)) + } else if health(o2) != .5 { + t.Fatal("expected health to be .5, got", health(o2)) + } + + // set the health of s1 to be lower than .5 + s1b, _ := s1.MarshalBinary() + err = ss.db.Exec("UPDATE slabs SET health = 0.4 WHERE key = ?", secretKey(s1b)).Error + if err != nil { + t.Fatal(err) + } + + // refresh health and assert only object 1's health got updated + err = ss.RefreshHealth(context.Background()) + if err != nil { + t.Fatal(err) + } + if health(o1) != .4 { + t.Fatal("expected health to be .4, got", health(o1)) + } else if health(o2) != .5 { + t.Fatal("expected health to be .5, got", health(o2)) + } + + // set the health of s2 to be higher than .5 + s2b, _ := s2.MarshalBinary() + err = ss.db.Exec("UPDATE slabs SET health = 0.6 WHERE key = ?", secretKey(s2b)).Error + if err != nil { + t.Fatal(err) + } + + // refresh health and assert only object 2's health got updated + err = ss.RefreshHealth(context.Background()) + if err != nil { + t.Fatal(err) + } + if health(o1) != .4 { + t.Fatal("expected health to be .4, got", health(o1)) + } else if health(o2) != .6 { + t.Fatal("expected health to be .6, got", health(o2)) + } +} + func TestSlabCleanupTrigger(t *testing.T) { ss := newTestSQLStore(t, defaultTestSQLStoreConfig) defer ss.Close() From cb73ef0803116c4ec065dd628517882dbadd244b Mon Sep 17 00:00:00 2001 From: PJ Date: Mon, 4 Mar 2024 16:50:36 +0100 Subject: [PATCH 2/2] stores: fix TestRefreshHealth for MySQL test suite --- stores/metadata_test.go | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/stores/metadata_test.go b/stores/metadata_test.go index a5fc76b05..27aa26a13 100644 --- a/stores/metadata_test.go +++ b/stores/metadata_test.go @@ -3911,11 +3911,10 @@ func TestRefreshHealth(t *testing.T) { // add two test objects o1 := t.Name() + "1" - s1 := object.GenerateEncryptionKey() if added, err := ss.addTestObject(o1, object.Object{ Key: object.GenerateEncryptionKey(), Slabs: []object.SlabSlice{{Slab: object.Slab{ - Key: s1, + Key: object.GenerateEncryptionKey(), Shards: []object.Sector{ newTestShard(hks[0], fcids[0], types.Hash256{0}), newTestShard(hks[1], fcids[1], types.Hash256{1}), @@ -3928,11 +3927,10 @@ func TestRefreshHealth(t *testing.T) { } o2 := t.Name() + "2" - s2 := object.GenerateEncryptionKey() if added, err := ss.addTestObject(o2, object.Object{ Key: object.GenerateEncryptionKey(), Slabs: []object.SlabSlice{{Slab: object.Slab{ - Key: s2, + Key: object.GenerateEncryptionKey(), Shards: []object.Sector{ newTestShard(hks[0], fcids[0], types.Hash256{2}), newTestShard(hks[1], fcids[1], types.Hash256{3}), @@ -3960,8 +3958,7 @@ func TestRefreshHealth(t *testing.T) { } // set the health of s1 to be lower than .5 - s1b, _ := s1.MarshalBinary() - err = ss.db.Exec("UPDATE slabs SET health = 0.4 WHERE key = ?", secretKey(s1b)).Error + err = ss.overrideSlabHealth(o1, 0.4) if err != nil { t.Fatal(err) } @@ -3978,8 +3975,7 @@ func TestRefreshHealth(t *testing.T) { } // set the health of s2 to be higher than .5 - s2b, _ := s2.MarshalBinary() - err = ss.db.Exec("UPDATE slabs SET health = 0.6 WHERE key = ?", secretKey(s2b)).Error + err = ss.overrideSlabHealth(o2, 0.6) if err != nil { t.Fatal(err) }