Skip to content

Commit 33ff78b

Browse files
committed
metabase: add sync counters on migration
Signed-off-by: Andrey Butusov <[email protected]>
1 parent 72e14f1 commit 33ff78b

File tree

3 files changed

+82
-0
lines changed

3 files changed

+82
-0
lines changed

pkg/local_object_storage/metabase/version.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,11 @@ func migrateFrom7Version(db *DB) error {
605605
}
606606
}
607607

608+
err = syncCounter(tx, currEpoch, true)
609+
if err != nil {
610+
return fmt.Errorf("syncing counters: %w", err)
611+
}
612+
608613
return updateVersion(tx, 8)
609614
})
610615
}

pkg/local_object_storage/metabase/version_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -854,6 +854,9 @@ func TestMigrate7to8(t *testing.T) {
854854
o.SetContainerID(cnr)
855855
totalSize += o.PayloadSize()
856856

857+
require.NoError(t, db.updateCounter(tx, phy, 1, true))
858+
require.NoError(t, db.updateCounter(tx, logical, 1, true))
859+
857860
return PutMetadataForObject(tx, o, true)
858861
})
859862
require.NoError(t, err)
@@ -875,6 +878,18 @@ func TestMigrate7to8(t *testing.T) {
875878
return err
876879
}
877880

881+
// corrupt counters
882+
b := tx.Bucket(shardInfoBucket)
883+
require.NotNil(t, b)
884+
require.Equal(t, uint64(objsNum), binary.LittleEndian.Uint64(b.Get(objectPhyCounterKey)))
885+
require.Equal(t, uint64(objsNum), binary.LittleEndian.Uint64(b.Get(objectLogicCounterKey)))
886+
cc := make([]byte, 8)
887+
binary.LittleEndian.PutUint64(cc, uint64(100)) // corrupt physical counter
888+
require.NoError(t, b.Put(objectPhyCounterKey, cc))
889+
cc = make([]byte, 8)
890+
binary.LittleEndian.PutUint64(cc, uint64(100)) // corrupt logical counter
891+
require.NoError(t, b.Put(objectLogicCounterKey, cc))
892+
878893
bkt := tx.Bucket([]byte{0x05})
879894
require.NotNil(t, bkt)
880895
require.NoError(t, bkt.Put([]byte("version"), []byte{0x07, 0, 0, 0, 0, 0, 0, 0}))
@@ -907,6 +922,9 @@ func TestMigrate7to8(t *testing.T) {
907922
require.NotNil(t, bkt)
908923
require.Equal(t, []byte{currentMetaVersion, 0, 0, 0, 0, 0, 0, 0}, bkt.Get([]byte("version")))
909924

925+
pc, lc := getCounters(tx)
926+
require.Equal(t, uint64(objsNum), pc)
927+
require.Equal(t, uint64(objsNum), lc)
910928
return nil
911929
})
912930
require.NoError(t, err)

pkg/local_object_storage/shard/metrics_test.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package shard_test
22

33
import (
4+
"encoding/binary"
45
"path/filepath"
56
"testing"
67

@@ -13,6 +14,7 @@ import (
1314
"github.com/nspcc-dev/neofs-sdk-go/object"
1415
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
1516
"github.com/stretchr/testify/require"
17+
"go.etcd.io/bbolt"
1618
)
1719

1820
type metricsStore struct {
@@ -195,6 +197,63 @@ func TestInhumeContainerCounters(t *testing.T) {
195197
require.Equal(t, initialPayload, mm.payloadSize)
196198
}
197199

200+
func TestShardCounterMigration(t *testing.T) {
201+
path := t.TempDir()
202+
sh, mm := shardWithMetrics(t, path)
203+
204+
const n = 11
205+
for range n {
206+
obj := generateObject()
207+
require.NoError(t, sh.Put(obj, nil))
208+
}
209+
require.Equal(t, uint64(n), mm.objectCounters[physical])
210+
require.Equal(t, uint64(n), mm.objectCounters[logical])
211+
212+
// Close shard so we can mutate Bolt file.
213+
require.NoError(t, sh.Close())
214+
215+
metaPath := filepath.Join(path, "meta")
216+
mdb, err := bbolt.Open(metaPath, 0o600, nil)
217+
require.NoError(t, err)
218+
219+
var (
220+
bucketPrefix = []byte{5} // shardInfoPrefix
221+
objectPhyCounterKey = []byte("phy_counter")
222+
objectLogicCounterKey = []byte("logic_counter")
223+
corruptPhysical = uint64(100)
224+
corruptLogical = uint64(200)
225+
)
226+
227+
require.NoError(t, mdb.Update(func(tx *bbolt.Tx) error {
228+
b := tx.Bucket(bucketPrefix)
229+
require.NotNil(t, b)
230+
231+
require.Equal(t, uint64(n), binary.LittleEndian.Uint64(b.Get(objectPhyCounterKey)))
232+
require.Equal(t, uint64(n), binary.LittleEndian.Uint64(b.Get(objectLogicCounterKey)))
233+
234+
cc := make([]byte, 8)
235+
binary.LittleEndian.PutUint64(cc, corruptPhysical)
236+
require.NoError(t, b.Put(objectPhyCounterKey, cc))
237+
cc = make([]byte, 8)
238+
binary.LittleEndian.PutUint64(cc, corruptLogical)
239+
require.NoError(t, b.Put(objectLogicCounterKey, cc))
240+
241+
// force metabase version to 7 to restore counters
242+
bkt := tx.Bucket([]byte{0x05})
243+
require.NotNil(t, bkt)
244+
require.NoError(t, bkt.Put([]byte("version"), []byte{0x07, 0, 0, 0, 0, 0, 0, 0}))
245+
return nil
246+
}))
247+
require.NoError(t, mdb.Close())
248+
249+
// re-open shard, initMetrics should force sync counters and restore real values
250+
sh, mm = shardWithMetrics(t, path)
251+
252+
require.Equal(t, uint64(n), mm.objectCounters[physical])
253+
require.Equal(t, uint64(n), mm.objectCounters[logical])
254+
require.NoError(t, sh.Close())
255+
}
256+
198257
func shardWithMetrics(t *testing.T, path string) (*shard.Shard, *metricsStore) {
199258
mm := &metricsStore{
200259
objectCounters: map[string]uint64{

0 commit comments

Comments
 (0)