@@ -286,7 +286,7 @@ class TPartitionFixture : public NUnitTest::TBaseFixture {
286
286
void SendReserveBytes (const ui64 cookie, const ui32 size, const TString& ownerCookie, const ui64 messageNo, bool lastRequest = false );
287
287
void SendChangeOwner (const ui64 cookie, const TString& owner, const TActorId& pipeClient, const bool force = true );
288
288
void SendWrite (const ui64 cookie, const ui64 messageNo, const TString& ownerCookie, const TMaybe<ui64> offset, const TString& data,
289
- bool ignoreQuotaDeadline = false , ui64 seqNo = 0 );
289
+ bool ignoreQuotaDeadline = false , ui64 seqNo = 0 , bool isDirectWrite = false );
290
290
void SendGetWriteInfo ();
291
291
void ShadowPartitionCountersTest (bool isFirstClass);
292
292
@@ -302,6 +302,14 @@ class TPartitionFixture : public NUnitTest::TBaseFixture {
302
302
void SendEvent (IEventBase* event);
303
303
void SendEvent (IEventBase* event, const TActorId& from, const TActorId& to);
304
304
305
+ THolder<TEvPQ::TEvApproveWriteQuota> WaitForRequestQuotaAndHoldApproveWriteQuota ();
306
+ void SendDeletePartition ();
307
+ void WaitForDeletePartitionDoneTimeout ();
308
+ void SendApproveWriteQuota (THolder<TEvPQ::TEvApproveWriteQuota>&& event);
309
+ void WaitForQuotaConsumed ();
310
+ void WaitForWriteError (ui64 cookie, NPersQueue::NErrorCode::EErrorCode errorCode);
311
+ void WaitForDeletePartitionDone ();
312
+
305
313
TMaybe<TTestContext> Ctx;
306
314
TMaybe<TFinalizer> Finalizer;
307
315
@@ -639,7 +647,7 @@ void TPartitionFixture::SendReserveBytes(const ui64 cookie, const ui32 size, con
639
647
640
648
void TPartitionFixture::SendWrite
641
649
(const ui64 cookie, const ui64 messageNo, const TString& ownerCookie, const TMaybe<ui64> offset, const TString& data,
642
- bool ignoreQuotaDeadline, ui64 seqNo
650
+ bool ignoreQuotaDeadline, ui64 seqNo, bool isDirectWrite
643
651
) {
644
652
TEvPQ::TEvWrite::TMsg msg;
645
653
msg.SourceId = " SourceId" ;
@@ -661,7 +669,7 @@ void TPartitionFixture::SendWrite
661
669
TVector<TEvPQ::TEvWrite::TMsg> msgs;
662
670
msgs.push_back (msg);
663
671
664
- auto event = MakeHolder<TEvPQ::TEvWrite>(cookie, messageNo, ownerCookie, offset, std::move (msgs), false , std::nullopt);
672
+ auto event = MakeHolder<TEvPQ::TEvWrite>(cookie, messageNo, ownerCookie, offset, std::move (msgs), isDirectWrite , std::nullopt);
665
673
Ctx->Runtime ->SingleSys ()->Send (new IEventHandle (ActorId, Ctx->Edge , event.Release ()));
666
674
}
667
675
@@ -1365,6 +1373,92 @@ void TPartitionFixture::TestWriteSubDomainOutOfSpace(TDuration quotaWaitDuration
1365
1373
}
1366
1374
}
1367
1375
1376
+ THolder<TEvPQ::TEvApproveWriteQuota> TPartitionFixture::WaitForRequestQuotaAndHoldApproveWriteQuota ()
1377
+ {
1378
+ THolder<TEvPQ::TEvApproveWriteQuota> approveWriteQuota;
1379
+
1380
+ auto observer = [&approveWriteQuota](TAutoPtr<IEventHandle>& ev) mutable {
1381
+ if (auto * event = ev->CastAsLocal <TEvPQ::TEvApproveWriteQuota>()) {
1382
+ approveWriteQuota = MakeHolder<TEvPQ::TEvApproveWriteQuota>(event->Cookie ,
1383
+ event->AccountQuotaWaitTime ,
1384
+ event->PartitionQuotaWaitTime );
1385
+ return TTestActorRuntimeBase::EEventAction::DROP;
1386
+ }
1387
+ return TTestActorRuntimeBase::EEventAction::PROCESS;
1388
+ };
1389
+ auto prevObserver = Ctx->Runtime ->SetObserverFunc (observer);
1390
+
1391
+ TDispatchOptions options;
1392
+ options.CustomFinalCondition = [&]() {
1393
+ return approveWriteQuota != nullptr ;
1394
+ };
1395
+ UNIT_ASSERT (Ctx->Runtime ->DispatchEvents (options));
1396
+
1397
+ Ctx->Runtime ->SetObserverFunc (prevObserver);
1398
+
1399
+ UNIT_ASSERT (approveWriteQuota != nullptr );
1400
+
1401
+ return approveWriteQuota;
1402
+ }
1403
+
1404
+ void TPartitionFixture::SendDeletePartition ()
1405
+ {
1406
+ auto event = MakeHolder<TEvPQ::TEvDeletePartition>();
1407
+ Ctx->Runtime ->SingleSys ()->Send (new IEventHandle (ActorId, Ctx->Edge , event.Release ()));
1408
+ }
1409
+
1410
+ void TPartitionFixture::WaitForDeletePartitionDoneTimeout ()
1411
+ {
1412
+ auto event = Ctx->Runtime ->GrabEdgeEvent <TEvPQ::TEvDeletePartitionDone>(TDuration::Seconds (3 ));
1413
+ UNIT_ASSERT_VALUES_EQUAL (event, nullptr );
1414
+ }
1415
+
1416
+ void TPartitionFixture::SendApproveWriteQuota (THolder<TEvPQ::TEvApproveWriteQuota>&& event)
1417
+ {
1418
+ Ctx->Runtime ->SingleSys ()->Send (new IEventHandle (ActorId, Ctx->Edge , event.Release ()));
1419
+ event = nullptr ;
1420
+ }
1421
+
1422
+ void TPartitionFixture::WaitForQuotaConsumed ()
1423
+ {
1424
+ bool hasQuotaConsumed = false ;
1425
+
1426
+ auto observer = [&hasQuotaConsumed](TAutoPtr<IEventHandle>& ev) mutable {
1427
+ if (auto * event = ev->CastAsLocal <TEvPQ::TEvConsumed>()) {
1428
+ hasQuotaConsumed = true ;
1429
+ }
1430
+ return TTestActorRuntimeBase::EEventAction::PROCESS;
1431
+ };
1432
+ auto prevObserver = Ctx->Runtime ->SetObserverFunc (observer);
1433
+
1434
+ TDispatchOptions options;
1435
+ options.CustomFinalCondition = [&]() {
1436
+ return hasQuotaConsumed;
1437
+ };
1438
+ UNIT_ASSERT (Ctx->Runtime ->DispatchEvents (options));
1439
+
1440
+ Ctx->Runtime ->SetObserverFunc (prevObserver);
1441
+
1442
+ UNIT_ASSERT (hasQuotaConsumed);
1443
+ }
1444
+
1445
+ void TPartitionFixture::WaitForWriteError (ui64 cookie, NPersQueue::NErrorCode::EErrorCode errorCode)
1446
+ {
1447
+ auto event = Ctx->Runtime ->GrabEdgeEvent <TEvPQ::TEvError>();
1448
+
1449
+ UNIT_ASSERT (event != nullptr );
1450
+
1451
+ UNIT_ASSERT_VALUES_EQUAL (cookie, event->Cookie );
1452
+ UNIT_ASSERT_C (errorCode == event->ErrorCode , " extected: " << (int )errorCode << " , accepted: " << (int )event->ErrorCode );
1453
+ }
1454
+
1455
+ void TPartitionFixture::WaitForDeletePartitionDone ()
1456
+ {
1457
+ auto event = Ctx->Runtime ->GrabEdgeEvent <TEvPQ::TEvDeletePartitionDone>();
1458
+
1459
+ UNIT_ASSERT (event != nullptr );
1460
+ }
1461
+
1368
1462
struct TTestUserAct {
1369
1463
TSrcIdMap SourceIds = {};
1370
1464
TString ClientId = {};
@@ -3478,6 +3572,36 @@ Y_UNIT_TEST_F(EndWriteTimestamp_HeadKeys, TPartitionFixture) {
3478
3572
UNIT_ASSERT_C (now - TDuration::Seconds (2 ) < endWriteTimestamp && endWriteTimestamp < now, " " << (now - TDuration::Seconds (2 )) << " < " << endWriteTimestamp << " < " << now );
3479
3573
} // EndWriteTimestamp_FromMeta
3480
3574
3575
+ Y_UNIT_TEST_F (The_DeletePartition_Message_Arrives_Before_The_ApproveWriteQuota_Message, TPartitionFixture)
3576
+ {
3577
+ // create a supportive partition
3578
+ const TPartitionId partitionId{1 , TWriteId{2 , 3 }, 4 };
3579
+ CreatePartition ({.Partition =partitionId});
3580
+
3581
+ // write 2 messages in it
3582
+ SendWrite (1 , 0 , " owner" , 0 , " message #1" , false , 1 , true );
3583
+ SendWrite (2 , 1 , " owner" , 1 , " message #2" , false , 2 , true );
3584
+
3585
+ // delay the response from the quoter
3586
+ auto approveWriteQuota = WaitForRequestQuotaAndHoldApproveWriteQuota ();
3587
+
3588
+ // Send a `TEvDeletePartition`. The partition will wait for the response from the quoter to arrive.
3589
+ SendDeletePartition ();
3590
+ WaitForDeletePartitionDoneTimeout ();
3591
+
3592
+ // The answer is from the quoter
3593
+ SendApproveWriteQuota (std::move (approveWriteQuota));
3594
+ WaitForQuotaConsumed ();
3595
+
3596
+ WaitCmdWrite ();
3597
+ SendCmdWriteResponse (NMsgBusProxy::MSTATUS_OK);
3598
+
3599
+ // Write operations fail with an error
3600
+ WaitForWriteError (1 , NPersQueue::NErrorCode::ERROR);
3601
+ WaitForDeletePartitionDone ();
3602
+ WaitForWriteError (2 , NPersQueue::NErrorCode::ERROR);
3603
+ }
3604
+
3481
3605
} // End of suite
3482
3606
3483
3607
} // namespace
0 commit comments