[#1163] metabase: Handle multiple splitInfos for EC

For REP updating split info is handled explicitly by a high-level PUT logic.
For EC it is trickier, because the address of an object we put is only
distantly related to a split info.

Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
This commit is contained in:
Evgenii Stratonikov 2024-06-06 10:52:17 +03:00
parent 2e074d3846
commit 3f1961157e
2 changed files with 168 additions and 71 deletions

View file

@ -642,7 +642,7 @@ func (tt *testTarget) WriteObject(_ context.Context, obj *objectSDK.Object) erro
return nil
}
func cutObject(t *testing.T, p transformer.ChunkedObjectWriter, hdr *objectSDK.Object, size int) {
func cutObject(t *testing.T, p transformer.ChunkedObjectWriter, hdr *objectSDK.Object, size int) *transformer.AccessIdentifiers {
ctx := context.Background()
require.NoError(t, p.WriteHeader(ctx, hdr))
@ -652,8 +652,128 @@ func cutObject(t *testing.T, p transformer.ChunkedObjectWriter, hdr *objectSDK.O
_, err := p.Write(ctx, payload)
require.NoError(t, err)
_, err = p.Close(ctx)
ids, err := p.Close(ctx)
require.NoError(t, err)
return ids
}
func TestDB_RawHead_SplitInfo(t *testing.T) {
t.Parallel()
const (
partSize = 10
partCount = 2
dataCount = 2
parityCount = 1
)
db := newDB(t)
defer func() { require.NoError(t, db.Close()) }()
cnr := cidtest.ID()
pk, err := keys.NewPrivateKey()
require.NoError(t, err)
tt := new(testTarget)
p := transformer.NewPayloadSizeLimiter(transformer.Params{
Key: &pk.PrivateKey,
NextTargetInit: func() transformer.ObjectWriter { return tt },
NetworkState: epochState{e: 1},
MaxSize: partSize,
})
hdr := objectSDK.New()
hdr.SetContainerID(cnr)
hdr.SetOwnerID(usertest.ID())
ids := cutObject(t, p, hdr, partSize*partCount)
require.Equal(t, len(tt.objects), partCount+1)
t.Run("rep", func(t *testing.T) {
testGetRawSplitInfo(t, cnr, ids, tt.objects[partCount], tt.objects[partCount-1])
})
t.Run("with ec", func(t *testing.T) {
ec, err := erasurecode.NewConstructor(dataCount, parityCount)
require.NoError(t, err)
cs, err := ec.Split(tt.objects[partCount-1], &pk.PrivateKey)
require.NoError(t, err)
testGetRawSplitInfo(t, cnr, ids, tt.objects[partCount], cs[0])
})
}
func testGetRawSplitInfo(t *testing.T, cnr cidSDK.ID, ids *transformer.AccessIdentifiers, linking, lastPart *objectSDK.Object) {
expectedLinkID, ok := linking.ID()
require.True(t, ok)
t.Run("first last, then linking", func(t *testing.T) {
db := newDB(t)
defer func() { require.NoError(t, db.Close()) }()
require.NoError(t, metaPut(db, lastPart, nil))
require.NoError(t, metaPut(db, linking, nil))
var addr oid.Address
addr.SetContainer(cnr)
addr.SetObject(*ids.ParentID)
_, err := metaGet(db, addr, true)
var siErr *objectSDK.SplitInfoError
require.ErrorAs(t, err, &siErr)
lastID, ok := siErr.SplitInfo().LastPart()
require.True(t, ok)
require.Equal(t, ids.SelfID, lastID)
linkID, ok := siErr.SplitInfo().Link()
require.True(t, ok)
require.Equal(t, expectedLinkID, linkID)
})
t.Run("first linking, then last", func(t *testing.T) {
db := newDB(t)
defer func() { require.NoError(t, db.Close()) }()
require.NoError(t, metaPut(db, linking, nil))
require.NoError(t, metaPut(db, lastPart, nil))
var addr oid.Address
addr.SetContainer(cnr)
addr.SetObject(*ids.ParentID)
_, err := metaGet(db, addr, true)
var siErr *objectSDK.SplitInfoError
require.ErrorAs(t, err, &siErr)
lastID, ok := siErr.SplitInfo().LastPart()
require.True(t, ok)
require.Equal(t, ids.SelfID, lastID)
linkID, ok := siErr.SplitInfo().Link()
require.True(t, ok)
require.Equal(t, expectedLinkID, linkID)
})
t.Run("only last part", func(t *testing.T) {
db := newDB(t)
defer func() { require.NoError(t, db.Close()) }()
require.NoError(t, metaPut(db, lastPart, nil))
var addr oid.Address
addr.SetContainer(cnr)
addr.SetObject(*ids.ParentID)
_, err := metaGet(db, addr, true)
var siErr *objectSDK.SplitInfoError
require.ErrorAs(t, err, &siErr)
lastPart, ok := siErr.SplitInfo().LastPart()
require.True(t, ok)
require.Equal(t, ids.SelfID, lastPart)
})
}
func TestDB_SelectSplitID_EC(t *testing.T) {