package meta import ( "bytes" "context" "errors" "fmt" "os" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/internal/metaerr" metamode "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode" "go.etcd.io/bbolt" ) var ( shardInfoBucket = []byte{shardInfoPrefix} shardIDKey = []byte("id") ) // GetShardID sets metabase operation mode // and reads shard id from db. // If id is missing, returns nil, nil. // // GetShardID does not report any metrics. func (db *DB) GetShardID(ctx context.Context, mode metamode.Mode) ([]byte, error) { db.modeMtx.Lock() defer db.modeMtx.Unlock() db.mode = mode if _, err := os.Stat(db.info.Path); errors.Is(err, os.ErrNotExist) { return nil, nil } if err := db.openDB(ctx, mode); err != nil { return nil, fmt.Errorf("failed to open metabase: %w", err) } id, err := db.readShardID() if cErr := db.close(); cErr != nil { err = errors.Join(err, fmt.Errorf("failed to close metabase: %w", cErr)) } return id, metaerr.Wrap(err) } // ReadShardID reads shard id from db. // If id is missing, returns nil, nil. func (db *DB) readShardID() ([]byte, error) { var id []byte err := db.boltDB.View(func(tx *bbolt.Tx) error { b := tx.Bucket(shardInfoBucket) if b != nil { id = bytes.Clone(b.Get(shardIDKey)) } return nil }) return id, metaerr.Wrap(err) } // SetShardID sets metabase operation mode // and writes shard id to db. func (db *DB) SetShardID(ctx context.Context, id []byte, mode metamode.Mode) error { db.modeMtx.Lock() defer db.modeMtx.Unlock() db.mode = mode if mode.ReadOnly() { return ErrReadOnlyMode } if err := db.openDB(ctx, mode); err != nil { return fmt.Errorf("failed to open metabase: %w", err) } err := db.writeShardID(id) if err == nil { db.metrics.SetMode(metamode.ConvertToComponentModeDegraded(mode)) } if cErr := db.close(); cErr != nil { err = errors.Join(err, fmt.Errorf("failed to close metabase: %w", cErr)) } return metaerr.Wrap(err) } // writeShardID writes shard id to db. func (db *DB) writeShardID(id []byte) error { return metaerr.Wrap(db.boltDB.Update(func(tx *bbolt.Tx) error { b, err := tx.CreateBucketIfNotExists(shardInfoBucket) if err != nil { return err } return b.Put(shardIDKey, id) })) }