@@ -147,4 +147,109 @@ Y_UNIT_TEST_SUITE(CorruptedReads) {
147147 }
148148 }
149149 }
150+
151+ Y_UNIT_TEST (Compaction) {
152+ TEnvironmentSetup env (TEnvironmentSetup::TSettings{
153+ .NodeCount = 8 ,
154+ .Erasure = TBlobStorageGroupType::Erasure4Plus2Block,
155+ });
156+
157+ env.CreateBoxAndPool (1 , 1 , 0 , NKikimrBlobStorage::EPDiskType::NVME);
158+ env.Sim (TDuration::Minutes (1 ));
159+ auto groups = env.GetGroups ();
160+ UNIT_ASSERT_VALUES_EQUAL (groups.size (), 1 );
161+ const TIntrusivePtr<TBlobStorageGroupInfo> info = env.GetGroupInfo (groups.front ());
162+ env.Sim (TDuration::Minutes (5 ));
163+
164+ const TActorId writer = env.Runtime ->AllocateEdgeActor (1 , __FILE__, __LINE__);
165+
166+ const ui32 orderNum = 0 ;
167+ const TVDiskID& vdiskId = info->GetVDiskId (orderNum);
168+ const TActorId& actorId = info->GetActorId (orderNum);
169+ UNIT_ASSERT_VALUES_EQUAL (actorId.NodeId (), writer.NodeId ());
170+
171+ std::vector<TLogoBlobID> blobs;
172+ THashMap<TLogoBlobID, TDiskPart> prevLocation;
173+
174+ for (ui32 iter = 0 ; iter < 2 ; ++iter) {
175+ ui32 index = iter + 1 ;
176+
177+ for (ui32 i = 0 ; i < 5000 ; ++i) {
178+ const size_t size = 100 + RandomNumber (10000u );
179+ TString data = FastGenDataForLZ4 (size, index);
180+ const TLogoBlobID id (1 , 1 , index, 0 , data.size (), 0 );
181+ index += 2 ;
182+
183+ env.Runtime ->WrapInActorContext (writer, [&] {
184+ SendToBSProxy (writer, info->GroupID , new TEvBlobStorage::TEvPut (id, TRope (data), TInstant::Max ()));
185+ });
186+ const auto & res = env.WaitForEdgeActorEvent <TEvBlobStorage::TEvPutResult>(writer, false );
187+ UNIT_ASSERT_VALUES_EQUAL (res->Get ()->Status , NKikimrProto::OK);
188+ }
189+
190+ auto ev = std::make_unique<IEventHandle>(actorId, writer, TEvCompactVDisk::Create (EHullDbType::LogoBlobs));
191+ ev->Rewrite (TEvBlobStorage::EvForwardToSkeleton, actorId);
192+ env.Runtime ->Send (ev.release (), writer.NodeId ());
193+ env.WaitForEdgeActorEvent <TEvCompactVDiskResult>(writer, false );
194+
195+ TIntrusivePtr<TPDiskMockState> state;
196+ for (auto & [pdiskId, ptr] : env.PDiskMockStates ) {
197+ const auto & [nodeId, _] = pdiskId;
198+ if (nodeId == writer.NodeId ()) {
199+ UNIT_ASSERT (!state);
200+ state = ptr;
201+ }
202+ }
203+
204+ auto res = env.SyncQuery <TEvBlobStorage::TEvCaptureVDiskLayoutResult, TEvBlobStorage::TEvCaptureVDiskLayout>(actorId);
205+ for (const auto & item : res->Layout ) {
206+ using T = TEvBlobStorage::TEvCaptureVDiskLayoutResult;
207+ if (item.Database != T::EDatabase::LogoBlobs) {
208+ continue ;
209+ }
210+ if (!item.BlobId ) {
211+ continue ;
212+ }
213+ const auto & location = item.Location ;
214+ if (iter == 0 ) {
215+ blobs.push_back (item.BlobId );
216+ prevLocation[item.BlobId ] = location;
217+ state->SetCorruptedArea (location.ChunkIdx , location.Offset , location.Offset + location.Size / 2 , true );
218+ } else if (prevLocation.contains (item.BlobId )) {
219+ UNIT_ASSERT (prevLocation[item.BlobId ] != location);
220+ }
221+ }
222+ }
223+
224+ auto queueActorId = env.CreateQueueActor (vdiskId, NKikimrBlobStorage::GetFastRead, 0 , actorId.NodeId ());
225+
226+ for (ui32 nodeId : env.Runtime ->GetNodes ()) {
227+ if (nodeId != queueActorId.NodeId ()) {
228+ env.StopNode (nodeId);
229+ }
230+ }
231+
232+ for (const TLogoBlobID& id : blobs) {
233+ auto query = TEvBlobStorage::TEvVGet::CreateExtremeDataQuery (vdiskId, TInstant::Max (),
234+ NKikimrBlobStorage::FastRead, TEvBlobStorage::TEvVGet::EFlags::None, {}, {id});
235+ env.Runtime ->Send (new IEventHandle (queueActorId, writer, query.release ()), queueActorId.NodeId ());
236+ auto res = env.WaitForEdgeActorEvent <TEvBlobStorage::TEvVGetResult>(writer, false );
237+ const auto & ev = res->Get ();
238+ auto & record = ev->Record ;
239+ UNIT_ASSERT_VALUES_EQUAL (record.GetStatus (), NKikimrProto::OK);
240+ UNIT_ASSERT_VALUES_EQUAL (record.ResultSize (), 1 );
241+ for (auto & item : record.GetResult ()) {
242+ UNIT_ASSERT_VALUES_EQUAL (item.GetStatus (), NKikimrProto::OK);
243+ const TLogoBlobID id = LogoBlobIDFromLogoBlobID (item.GetBlobID ());
244+ const TString data = FastGenDataForLZ4 (id.BlobSize (), id.Step ());
245+ std::vector<TRope> parts (info->Type .TotalPartCount ());
246+ ErasureSplit (static_cast <TBlobStorageGroupType::ECrcMode>(id.CrcMode ()), info->Type , TRope (data), parts);
247+ UNIT_ASSERT (ev->HasBlob (item));
248+ const TRope& readPartData = ev->GetBlobData (item);
249+ const TRope& expectedPart = parts[id.PartId () - 1 ];
250+ UNIT_ASSERT_VALUES_EQUAL (readPartData.size (), expectedPart.size ());
251+ UNIT_ASSERT_EQUAL (readPartData, expectedPart);
252+ }
253+ }
254+ }
150255}
0 commit comments