@@ -82,6 +82,8 @@ class TFixture : public NUnitTest::TBaseFixture {
82
82
TDuration stabilizationWindow,
83
83
ui64 downUtilizationPercent,
84
84
ui64 upUtilizationPercent);
85
+ void SetPartitionWriteSpeed (const TString& topicPath,
86
+ size_t bytesPerSeconds);
85
87
86
88
void WriteToTopicWithInvalidTxId (bool invalidTxId);
87
89
@@ -434,6 +436,18 @@ void TFixture::AlterAutoPartitioning(const TString& topicPath,
434
436
UNIT_ASSERT_C (result.IsSuccess (), result.GetIssues ().ToString ());
435
437
}
436
438
439
+ void TFixture::SetPartitionWriteSpeed (const TString& topicPath,
440
+ size_t bytesPerSeconds)
441
+ {
442
+ NTopic::TTopicClient client (GetDriver ());
443
+ NTopic::TAlterTopicSettings settings;
444
+
445
+ settings.SetPartitionWriteSpeedBytesPerSecond (bytesPerSeconds);
446
+
447
+ auto result = client.AlterTopic (topicPath, settings).GetValueSync ();
448
+ UNIT_ASSERT_C (result.IsSuccess (), result.GetIssues ().ToString ());
449
+ }
450
+
437
451
const TDriver& TFixture::GetDriver () const
438
452
{
439
453
return *Driver;
@@ -2389,6 +2403,8 @@ Y_UNIT_TEST_F(Write_Random_Sized_Messages_In_Wide_Transactions, TFixture)
2389
2403
2390
2404
CreateTopic (" topic_A" , TEST_CONSUMER, PARTITIONS_COUNT);
2391
2405
2406
+ SetPartitionWriteSpeed (" topic_A" , 50'000'000 );
2407
+
2392
2408
TVector<NTable::TSession> sessions;
2393
2409
TVector<NTable::TTransaction> transactions;
2394
2410
@@ -2429,6 +2445,147 @@ Y_UNIT_TEST_F(Write_Random_Sized_Messages_In_Wide_Transactions, TFixture)
2429
2445
}
2430
2446
}
2431
2447
2448
+ Y_UNIT_TEST_F (Write_Only_Big_Messages_In_Wide_Transactions, TFixture)
2449
+ {
2450
+ // The test verifies the simultaneous execution of several transactions. There is a topic `topic_A` and
2451
+ // it contains a `PARTITIONS_COUNT' of partitions. In each transaction, the test writes to all partitions.
2452
+ // The size of the messages is chosen so that only large blobs are recorded in the transaction and there
2453
+ // are no records in the head. Thus, we verify that transaction bundling is working correctly.
2454
+
2455
+ const size_t PARTITIONS_COUNT = 20 ;
2456
+ const size_t TXS_COUNT = 100 ;
2457
+
2458
+ CreateTopic (" topic_A" , TEST_CONSUMER, PARTITIONS_COUNT);
2459
+
2460
+ SetPartitionWriteSpeed (" topic_A" , 50'000'000 );
2461
+
2462
+ std::vector<NTable::TSession> sessions;
2463
+ std::vector<NTable::TTransaction> transactions;
2464
+
2465
+ // We open TXS_COUNT transactions and write messages to the topic.
2466
+ for (size_t i = 0 ; i < TXS_COUNT; ++i) {
2467
+ sessions.push_back (CreateTableSession ());
2468
+ auto & session = sessions.back ();
2469
+
2470
+ transactions.push_back (BeginTx (session));
2471
+ auto & tx = transactions.back ();
2472
+
2473
+ for (size_t j = 0 ; j < PARTITIONS_COUNT; ++j) {
2474
+ TString sourceId = TEST_MESSAGE_GROUP_ID;
2475
+ sourceId += " _" ;
2476
+ sourceId += ToString (i);
2477
+ sourceId += " _" ;
2478
+ sourceId += ToString (j);
2479
+
2480
+ WriteToTopic (" topic_A" , sourceId, TString (6'500'000 , ' x' ), &tx, j);
2481
+
2482
+ WaitForAcks (" topic_A" , sourceId);
2483
+ }
2484
+ }
2485
+
2486
+ // We are doing an asynchronous commit of transactions. They will be executed simultaneously.
2487
+ std::vector<NTable::TAsyncCommitTransactionResult> futures;
2488
+
2489
+ for (size_t i = 0 ; i < TXS_COUNT; ++i) {
2490
+ futures.push_back (transactions[i].Commit ());
2491
+ }
2492
+
2493
+ // All transactions must be completed successfully.
2494
+ for (size_t i = 0 ; i < TXS_COUNT; ++i) {
2495
+ futures[i].Wait ();
2496
+ const auto & result = futures[i].GetValueSync ();
2497
+ UNIT_ASSERT_VALUES_EQUAL_C (result.GetStatus (), EStatus::SUCCESS, result.GetIssues ().ToString ());
2498
+ }
2499
+ }
2500
+
2501
+ Y_UNIT_TEST_F (Transactions_Conflict_On_SeqNo, TFixture)
2502
+ {
2503
+ const ui32 PARTITIONS_COUNT = 20 ;
2504
+ const size_t TXS_COUNT = 100 ;
2505
+
2506
+ CreateTopic (" topic_A" , TEST_CONSUMER, PARTITIONS_COUNT);
2507
+
2508
+ SetPartitionWriteSpeed (" topic_A" , 50'000'000 );
2509
+
2510
+ auto tableSession = CreateTableSession ();
2511
+ std::vector<std::shared_ptr<NTopic::ISimpleBlockingWriteSession>> topicWriteSessions;
2512
+
2513
+ for (ui32 i = 0 ; i < PARTITIONS_COUNT; ++i) {
2514
+ TString sourceId = TEST_MESSAGE_GROUP_ID;
2515
+ sourceId += " _" ;
2516
+ sourceId += ToString (i);
2517
+
2518
+ NTopic::TTopicClient client (GetDriver ());
2519
+ NTopic::TWriteSessionSettings options;
2520
+ options.Path (" topic_A" );
2521
+ options.ProducerId (sourceId);
2522
+ options.MessageGroupId (sourceId);
2523
+ options.PartitionId (i);
2524
+ options.Codec (ECodec::RAW);
2525
+
2526
+ auto session = client.CreateSimpleBlockingWriteSession (options);
2527
+
2528
+ topicWriteSessions.push_back (std::move (session));
2529
+ }
2530
+
2531
+ std::vector<NTable::TSession> sessions;
2532
+ std::vector<NTable::TTransaction> transactions;
2533
+
2534
+ for (size_t i = 0 ; i < TXS_COUNT; ++i) {
2535
+ sessions.push_back (CreateTableSession ());
2536
+ auto & session = sessions.back ();
2537
+
2538
+ transactions.push_back (BeginTx (session));
2539
+ auto & tx = transactions.back ();
2540
+
2541
+ for (size_t j = 0 ; j < PARTITIONS_COUNT; ++j) {
2542
+ TString sourceId = TEST_MESSAGE_GROUP_ID;
2543
+ sourceId += " _" ;
2544
+ sourceId += ToString (j);
2545
+
2546
+ for (size_t k = 0 , count = RandomNumber<size_t >(20 ) + 1 ; k < count; ++k) {
2547
+ const std::string data (RandomNumber<size_t >(1'000 ) + 100 , ' x' );
2548
+ NTopic::TWriteMessage params (data);
2549
+ params.Tx (tx);
2550
+
2551
+ topicWriteSessions[j]->Write (std::move (params));
2552
+ }
2553
+ }
2554
+ }
2555
+
2556
+ std::vector<NTable::TAsyncCommitTransactionResult> futures;
2557
+
2558
+ for (size_t i = 0 ; i < TXS_COUNT; ++i) {
2559
+ futures.push_back (transactions[i].Commit ());
2560
+ }
2561
+
2562
+ // Some transactions should end with the error `ABORTED`
2563
+ size_t successCount = 0 ;
2564
+
2565
+ for (size_t i = 0 ; i < TXS_COUNT; ++i) {
2566
+ for (bool stop = false ; !stop; ) {
2567
+ futures[i].Wait ();
2568
+ const auto & result = futures[i].GetValueSync ();
2569
+ switch (result.GetStatus ()) {
2570
+ case EStatus::SUCCESS:
2571
+ ++successCount;
2572
+ [[fallthrough]];
2573
+ case EStatus::ABORTED:
2574
+ stop = true ;
2575
+ break ;
2576
+ case EStatus::SESSION_BUSY:
2577
+ futures[i] = transactions[i].Commit ();
2578
+ break ;
2579
+ default :
2580
+ UNIT_FAIL (" unexpected status: " << static_cast <const NYdb::TStatus&>(result));
2581
+ break ;
2582
+ }
2583
+ }
2584
+ }
2585
+
2586
+ UNIT_ASSERT_VALUES_UNEQUAL (successCount, TXS_COUNT);
2587
+ }
2588
+
2432
2589
}
2433
2590
2434
2591
}
0 commit comments