diff --git a/pkg/local_object_storage/metabase/metadata.go b/pkg/local_object_storage/metabase/metadata.go index 7211295542..76f30a4a64 100644 --- a/pkg/local_object_storage/metabase/metadata.go +++ b/pkg/local_object_storage/metabase/metadata.go @@ -48,7 +48,7 @@ func invalidMetaBucketKeyErr(key []byte, cause error) error { return fmt.Errorf("invalid meta bucket key (prefix 0x%X): %w", key[0], cause) } -func putMetadataForObject(tx *bbolt.Tx, hdr object.Object, root, phy bool) error { +func putMetadataForObject(tx *bbolt.Tx, hdr object.Object, hasParent, phy bool) error { owner := hdr.Owner() if owner.IsZero() { return fmt.Errorf("invalid owner: %w", user.ErrZeroID) @@ -66,12 +66,12 @@ func putMetadataForObject(tx *bbolt.Tx, hdr object.Object, root, phy bool) error pldHmmHash = h.Value() } return putMetadata(tx, hdr.GetContainerID(), hdr.GetID(), ver, owner, hdr.Type(), hdr.CreationEpoch(), hdr.PayloadSize(), pldHash.Value(), - pldHmmHash, hdr.SplitID().ToV2(), hdr.GetParentID(), hdr.GetFirstID(), hdr.Attributes(), root, phy) + pldHmmHash, hdr.SplitID().ToV2(), hdr.GetParentID(), hdr.GetFirstID(), hdr.Attributes(), hasParent, phy) } func putMetadata(tx *bbolt.Tx, cnr cid.ID, id oid.ID, ver version.Version, owner user.ID, typ object.Type, creationEpoch uint64, payloadLen uint64, pldHash, pldHmmHash, splitID []byte, parentID, firstID oid.ID, attrs []object.Attribute, - root, phy bool) error { + hasParent, phy bool) error { metaBkt, err := tx.CreateBucketIfNotExists(metaBucketKey(cnr)) if err != nil { return fmt.Errorf("create meta bucket for container: %w", err) @@ -119,7 +119,7 @@ func putMetadata(tx *bbolt.Tx, cnr cid.ID, id oid.ID, ver version.Version, owner return err } } - if root { + if !hasParent && typ == object.TypeRegular { if err = putPlainAttribute(metaBkt, &keyBuf, id, object.FilterRoot, binPropMarker); err != nil { return err } diff --git a/pkg/local_object_storage/metabase/metadata_test.go b/pkg/local_object_storage/metabase/metadata_test.go index 1251b99a97..14fb3dcaaa 100644 --- a/pkg/local_object_storage/metabase/metadata_test.go +++ b/pkg/local_object_storage/metabase/metadata_test.go @@ -34,28 +34,32 @@ func appendAttribute(obj *object.Object, k, v string) { obj.SetAttributes(append(obj.Attributes(), *object.NewAttribute(k, v))...) } -func assertAttrIDPrefixed[T string | []byte](t testing.TB, mb *bbolt.Bucket, id oid.ID, prefix byte, attr string, val T) { +func assertPrefixedAttrIDPresence[T string | []byte](t testing.TB, mb *bbolt.Bucket, id oid.ID, prefix byte, attr string, val T, exp bool) { k := []byte{prefix} k = append(k, attr...) k = append(k, 0xFF) k = append(k, val...) k = append(k, id[:]...) - require.Equal(t, []byte{}, mb.Get(k)) + require.Equal(t, exp, mb.Get(k) != nil) } -func assertAttr[T string | []byte](t testing.TB, mb *bbolt.Bucket, id oid.ID, attr string, val T) { - assertAttrIDPrefixed(t, mb, id, 0x02, attr, val) +func assertAttrPresence[T string | []byte](t testing.TB, mb *bbolt.Bucket, id oid.ID, attr string, val T, exp bool) { + assertPrefixedAttrIDPresence(t, mb, id, 0x02, attr, val, exp) k := []byte{0x03} k = append(k, id[:]...) k = append(k, attr...) k = append(k, 0xFF) k = append(k, val...) - require.Equal(t, []byte{}, mb.Get(k)) + require.Equal(t, exp, mb.Get(k) != nil) +} + +func assertAttr[T string | []byte](t testing.TB, mb *bbolt.Bucket, id oid.ID, attr string, val T) { + assertAttrPresence(t, mb, id, attr, val, true) } func assertIntAttr(t testing.TB, mb *bbolt.Bucket, id oid.ID, attr string, origin string, val []byte) { assertAttr(t, mb, id, attr, origin) - assertAttrIDPrefixed(t, mb, id, 0x01, attr, val) + assertPrefixedAttrIDPresence(t, mb, id, 0x01, attr, val, true) } func TestPutMetadata(t *testing.T) { @@ -129,7 +133,7 @@ func TestPutMetadata(t *testing.T) { 0, 0, 0, 0, 101, 118, 30, 154, 145, 227, 159, 231}) assertIntAttr(t, mb, id, "$Object:payloadLength", "2091724451450177666", []byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 7, 76, 78, 96, 175, 200, 130}) - assertAttr(t, mb, id, "$Object:ROOT", "1") + assertAttrPresence(t, mb, id, "$Object:ROOT", "1", false) assertAttr(t, mb, id, "$Object:PHY", "1") assertAttr(t, mb, id, "attr_1", "val_1") assertAttr(t, mb, id, "attr_2", "val_2") @@ -677,7 +681,7 @@ func TestDB_SearchObjects(t *testing.T) { object.MatchUnspecified, object.MatchStringEqual, object.MatchStringNotEqual, object.MatchNumGT, object.MatchNumGE, object.MatchNumLT, object.MatchNumLE, } { - check("$Object:ROOT", matcher, "", []uint{0, 1}) + check("$Object:ROOT", matcher, "", []uint{0}) } check("$Object:ROOT", object.MatchNotPresent, "", nil) }) diff --git a/pkg/local_object_storage/metabase/put.go b/pkg/local_object_storage/metabase/put.go index ce1c1e4d88..d6ecaac174 100644 --- a/pkg/local_object_storage/metabase/put.go +++ b/pkg/local_object_storage/metabase/put.go @@ -172,7 +172,7 @@ func (db *DB) put( pldHmmHash = h.Value() } if err := putMetadata(tx, cnr, obj.GetID(), ver, *owner, obj.Type(), obj.CreationEpoch(), obj.PayloadSize(), - pldHash.Value(), pldHmmHash, obj.SplitID().ToV2(), obj.GetParentID(), obj.GetFirstID(), obj.Attributes(), par == nil, !isParent); err != nil { + pldHash.Value(), pldHmmHash, obj.SplitID().ToV2(), obj.GetParentID(), obj.GetFirstID(), obj.Attributes(), par != nil, !isParent); err != nil { return fmt.Errorf("put metadata: %w", err) } diff --git a/pkg/local_object_storage/metabase/version.go b/pkg/local_object_storage/metabase/version.go index a944c18873..3ce742ce22 100644 --- a/pkg/local_object_storage/metabase/version.go +++ b/pkg/local_object_storage/metabase/version.go @@ -137,11 +137,12 @@ func migrateFrom3Version(_ *DB, tx *bbolt.Tx) error { return fmt.Errorf("decode header of object %s from bucket value: %w", id, err) } par := hdr.Parent() - if err := putMetadataForObject(tx, hdr, par == nil, true); err != nil { + hasParent := par != nil + if err := putMetadataForObject(tx, hdr, hasParent, true); err != nil { return fmt.Errorf("put metadata for object %s: %w", id, err) } - if par != nil { - if err := putMetadataForObject(tx, *par, true, false); err != nil { + if hasParent { + if err := putMetadataForObject(tx, *par, false, false); err != nil { return fmt.Errorf("put metadata for parent of object %s: %w", id, err) } } diff --git a/pkg/local_object_storage/metabase/version_test.go b/pkg/local_object_storage/metabase/version_test.go index 4fbd2ba427..2851ebd7a6 100644 --- a/pkg/local_object_storage/metabase/version_test.go +++ b/pkg/local_object_storage/metabase/version_test.go @@ -563,11 +563,11 @@ func TestMigrate3to4(t *testing.T) { fs.AddRootFilter() res, _, err = db.Search(objs[i].GetContainerID(), fs, nil, nil, nil, 1000) require.NoError(t, err, i) - require.Len(t, res, 1, i) if i == 0 { + require.Len(t, res, 1) require.Equal(t, par.GetID(), res[0].ID) } else { - require.Equal(t, objs[i].GetID(), res[0].ID, i) + require.Empty(t, res, i) } fs = fs[:0] fs.AddPhyFilter()