From 76b2a6e6e37cd4dd2ee1bfec6c8af9e6ddd55282 Mon Sep 17 00:00:00 2001 From: xiejian Date: Thu, 23 Jan 2025 11:00:09 +0800 Subject: [PATCH] fix(shardnode): record Slice.ValidSize when alloc or seal with #22357426 Signed-off-by: xiejian --- blobstore/common/errors/errors.go | 1 + blobstore/common/errors/shardnode.go | 2 + .../shardnode/catalog/allocator/allocator.go | 7 --- blobstore/shardnode/catalog/space.go | 40 +++++++++++++- blobstore/shardnode/catalog/space_test.go | 53 ++++++++++++------- 5 files changed, 76 insertions(+), 27 deletions(-) diff --git a/blobstore/common/errors/errors.go b/blobstore/common/errors/errors.go index c5a798de8..e5c6dc5f5 100644 --- a/blobstore/common/errors/errors.go +++ b/blobstore/common/errors/errors.go @@ -174,6 +174,7 @@ var errCodeMap = map[int]string{ CodeNoEnoughRaftMember: "shardnode:no enough raft member", CodeIllegalUpdateUnit: "shardnode:illegal update suid", CodeItemIDEmpty: "shardnode:item ID is empty", + CodeIllegalLocationSize: "shardnode:illegal location size", } // HTTPError make rpc.HTTPError diff --git a/blobstore/common/errors/shardnode.go b/blobstore/common/errors/shardnode.go index 2080c6f7d..445560812 100644 --- a/blobstore/common/errors/shardnode.go +++ b/blobstore/common/errors/shardnode.go @@ -34,6 +34,7 @@ const ( CodeNoEnoughRaftMember = 1017 CodeIllegalUpdateUnit = 1018 CodeItemIDEmpty = 1019 + CodeIllegalLocationSize = 1020 ) // 10xx @@ -57,4 +58,5 @@ var ( ErrNoEnoughRaftMember = Error(CodeNoEnoughRaftMember) ErrIllegalUpdateUnit = Error(CodeIllegalUpdateUnit) ErrItemIDEmpty = Error(CodeItemIDEmpty) + ErrIllegalLocationSize = Error(CodeIllegalLocationSize) ) diff --git a/blobstore/shardnode/catalog/allocator/allocator.go b/blobstore/shardnode/catalog/allocator/allocator.go index 3d5fae7f9..270ea2b3a 100644 --- a/blobstore/shardnode/catalog/allocator/allocator.go +++ b/blobstore/shardnode/catalog/allocator/allocator.go @@ -60,7 +60,6 @@ func (alc *allocator) AllocSlices(ctx context.Context, codeMode codemode.CodeMod blobN := blobCount(fileSize, sliceSize) blobs := make([]proto.Slice, 0, blobN) - var size uint64 for _, bidRet := range allocRets { if blobN <= 0 { break @@ -68,18 +67,12 @@ func (alc *allocator) AllocSlices(ctx context.Context, codeMode codemode.CodeMod count := minU64(blobN, uint64(bidRet.BidEnd)-uint64(bidRet.BidStart)+1) blobN -= count - validSize := uint64(sliceSize) * count - if blobN <= 0 { - validSize = fileSize - size - } blobs = append(blobs, proto.Slice{ MinSliceID: bidRet.BidStart, Vid: bidRet.Vid, Count: uint32(count), - ValidSize: validSize, }) - size += validSize } if blobN > 0 { return nil, errors.New("no enough blob ids from allocator") diff --git a/blobstore/shardnode/catalog/space.go b/blobstore/shardnode/catalog/space.go index 01c0db5e6..3002e3a71 100644 --- a/blobstore/shardnode/catalog/space.go +++ b/blobstore/shardnode/catalog/space.go @@ -337,7 +337,35 @@ func (s *Space) SealBlob(ctx context.Context, req *shardnode.SealBlobArgs) error b.Sealed = true b.Location.Size_ = req.GetSize_() - b.Location.Slices = req.GetSlices() + + sliceSize := b.Location.SliceSize + remainSize := req.GetSize_() + for i := range req.Slices { + if i == len(req.Slices)-1 { + if remainSize > uint64(req.Slices[i].Count*sliceSize) { + return apierr.ErrIllegalLocationSize + } + req.Slices[i].ValidSize = remainSize + break + } + // local validSize recorded + if b.Location.Slices[i].ValidSize != 0 { + validSize := b.Location.Slices[i].ValidSize + if validSize >= remainSize { + return apierr.ErrIllegalLocationSize + } + req.Slices[i].ValidSize = validSize + remainSize -= validSize + continue + } + validSize := uint64(req.Slices[i].Count * sliceSize) + if validSize >= remainSize { + return apierr.ErrIllegalLocationSize + } + req.Slices[i].ValidSize = validSize + remainSize -= validSize + } + if err = security.LocationCrcFill(&b.Location); err != nil { return err } @@ -425,6 +453,7 @@ func (s *Space) AllocSlice(ctx context.Context, req *shardnode.AllocSliceArgs) ( var ( idxes []uint32 idx uint32 + validIdx uint32 ok bool failedVid []proto.Vid ) @@ -456,10 +485,17 @@ func (s *Space) AllocSlice(ctx context.Context, req *shardnode.AllocSliceArgs) ( localSlices[idx] = failedSlice localSlices = append(localSlices[:idx+1], append(slices, localSlices[idx+1:]...)...) } + validIdx = idx } else { + validIdx = uint32(len(localSlices)) localSlices = append(localSlices, slices...) } + var i uint32 + for i = 0; i < validIdx; i++ { + localSlices[i].ValidSize = uint64(sliceSize * localSlices[i].Count) + } + b.Location.Slices = localSlices if err = security.LocationCrcFill(&b.Location); err != nil { return @@ -574,7 +610,7 @@ func checkSlices(loc, req []proto.Slice, sliceSize uint32) ([]uint32, bool) { if _, ok := locMap[id]; !ok { return idxes, false } - if req[i].Vid != locMap[id].Vid || req[i].Count > locMap[id].Count || req[i].ValidSize > locMap[id].ValidSize { + if req[i].Vid != locMap[id].Vid || req[i].Count > locMap[id].Count { return idxes, false } idxes = append(idxes, locIndexMap[id]) diff --git a/blobstore/shardnode/catalog/space_test.go b/blobstore/shardnode/catalog/space_test.go index 8aaf8e7b4..dfc23e19d 100644 --- a/blobstore/shardnode/catalog/space_test.go +++ b/blobstore/shardnode/catalog/space_test.go @@ -206,9 +206,9 @@ func TestSpace_AllocSlice(t *testing.T) { space.allocator = alc locSlices := []proto.Slice{ - {Vid: 1, MinSliceID: 1, Count: 10, ValidSize: 100}, - {Vid: 1, MinSliceID: 2, Count: 20, ValidSize: 200}, - {Vid: 1, MinSliceID: 3, Count: 30, ValidSize: 300}, + {Vid: 1, MinSliceID: 1, Count: 10, ValidSize: 0}, + {Vid: 1, MinSliceID: 2, Count: 20, ValidSize: 0}, + {Vid: 1, MinSliceID: 3, Count: 30, ValidSize: 0}, } name := []byte("blob") mode := codemode.EC6P6 @@ -240,7 +240,7 @@ func TestSpace_AllocSlice(t *testing.T) { require.Equal(t, newSlices, ret.Slices) // illegal failedSlice - args.FailedSlice = proto.Slice{Vid: 1, MinSliceID: 2, Count: 10, ValidSize: 300} + args.FailedSlice = proto.Slice{Vid: 1, MinSliceID: 2, Count: 30, ValidSize: 300} _, err = space.AllocSlice(ctx, args) require.Equal(t, apierr.ErrIllegalSlices, err) @@ -282,8 +282,8 @@ func TestSpace_SealBlob(t *testing.T) { locSlices := []proto.Slice{ {Vid: 1, MinSliceID: 1, Count: 10, ValidSize: 100}, - {Vid: 1, MinSliceID: 2, Count: 20, ValidSize: 200}, - {Vid: 1, MinSliceID: 3, Count: 30, ValidSize: 300}, + {Vid: 1, MinSliceID: 2, Count: 20, ValidSize: 100}, + {Vid: 1, MinSliceID: 3, Count: 30, ValidSize: 0}, } name := []byte("blob") mode := codemode.EC6P6 @@ -297,19 +297,36 @@ func TestSpace_SealBlob(t *testing.T) { } raw, err := b.Marshal() require.Nil(t, err) - mockSpace.mockHandler.EXPECT().Get(A, A, A).Return(newMockValGetter(raw), nil).Times(2) - mockSpace.mockHandler.EXPECT().Update(A, A, A).Return(nil).Times(1) + mockSpace.mockHandler.EXPECT().Get(A, A, A).Return(newMockValGetter(raw), nil).Times(6) + mockSpace.mockHandler.EXPECT().Update(A, A, A).Return(nil).Times(3) args := &shardnode.SealBlobArgs{ Header: shardnode.ShardOpHeader{}, Name: name, - Size_: 600, + Size_: 300, Slices: locSlices, } err = space.SealBlob(ctx, args) require.Nil(t, err) - args.Slices[1].ValidSize = 300 + args.Size_ = 500 + err = space.SealBlob(ctx, args) + require.Nil(t, err) + + args.Size_ = 200 + err = space.SealBlob(ctx, args) + require.Equal(t, apierr.ErrIllegalLocationSize, err) + + args.Size_ = 700 + err = space.SealBlob(ctx, args) + require.Equal(t, apierr.ErrIllegalLocationSize, err) + + args.Size_ = 200 + args.Slices = args.Slices[:2] + err = space.SealBlob(ctx, args) + require.Equal(t, nil, err) + + args.Slices[1].Count = 30 err = space.SealBlob(ctx, args) require.Equal(t, apierr.ErrIllegalSlices, err) } @@ -445,8 +462,8 @@ func TestCheckSlices(t *testing.T) { name: "valid slices", args: args{ loc: []proto.Slice{ - {Vid: 1, MinSliceID: 1, Count: 10, ValidSize: 100}, - {Vid: 1, MinSliceID: 2, Count: 20, ValidSize: 200}, + {Vid: 1, MinSliceID: 1, Count: 10, ValidSize: 0}, + {Vid: 1, MinSliceID: 2, Count: 20, ValidSize: 0}, }, req: []proto.Slice{ {Vid: 1, MinSliceID: 1, Count: 5, ValidSize: 50}, @@ -460,8 +477,8 @@ func TestCheckSlices(t *testing.T) { name: "invalid slices - missing MinSliceID", args: args{ loc: []proto.Slice{ - {Vid: 1, MinSliceID: 1, Count: 10, ValidSize: 100}, - {Vid: 1, MinSliceID: 2, Count: 20, ValidSize: 200}, + {Vid: 1, MinSliceID: 1, Count: 10, ValidSize: 0}, + {Vid: 1, MinSliceID: 2, Count: 20, ValidSize: 0}, }, req: []proto.Slice{ {Vid: 1, MinSliceID: 3, Count: 5, ValidSize: 50}, @@ -474,8 +491,8 @@ func TestCheckSlices(t *testing.T) { name: "invalid slices - count exceeds", args: args{ loc: []proto.Slice{ - {Vid: 1, MinSliceID: 1, Count: 10, ValidSize: 100}, - {Vid: 1, MinSliceID: 2, Count: 20, ValidSize: 200}, + {Vid: 1, MinSliceID: 1, Count: 10, ValidSize: 0}, + {Vid: 1, MinSliceID: 2, Count: 20, ValidSize: 0}, }, req: []proto.Slice{ {Vid: 1, MinSliceID: 1, Count: 15, ValidSize: 150}, @@ -488,8 +505,8 @@ func TestCheckSlices(t *testing.T) { name: "invalid slices - valid size exceeds", args: args{ loc: []proto.Slice{ - {Vid: 1, MinSliceID: 1, Count: 10, ValidSize: 100}, - {Vid: 1, MinSliceID: 2, Count: 20, ValidSize: 200}, + {Vid: 1, MinSliceID: 1, Count: 10, ValidSize: 0}, + {Vid: 1, MinSliceID: 2, Count: 20, ValidSize: 0}, }, req: []proto.Slice{ {Vid: 1, MinSliceID: 1, Count: 20, ValidSize: 200},