11package shard_test
22
33import (
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
1820type 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+
198257func shardWithMetrics (t * testing.T , path string ) (* shard.Shard , * metricsStore ) {
199258 mm := & metricsStore {
200259 objectCounters : map [string ]uint64 {
0 commit comments