@@ -3386,6 +3386,72 @@ Y_UNIT_TEST_TWIN(TestShardRestartPlannedCommitShouldSucceed, StreamLookup) {
33863386 }
33873387}
33883388
3389+ Y_UNIT_TEST (TestShardRestartDuringWaitingRead) {
3390+ TPortManager pm;
3391+ NKikimrConfig::TAppConfig app;
3392+ app.MutableTableServiceConfig ()->SetEnableKqpDataQuerySourceRead (true );
3393+ TServerSettings serverSettings (pm.GetPort (2134 ));
3394+ serverSettings.SetDomainName (" Root" )
3395+ .SetUseRealThreads (false )
3396+ .SetAppConfig (app)
3397+ // We read from an unresolved volatile tx
3398+ .SetEnableDataShardVolatileTransactions (true );
3399+
3400+ Tests::TServer::TPtr server = new TServer (serverSettings);
3401+ auto &runtime = *server->GetRuntime ();
3402+ auto sender = runtime.AllocateEdgeActor ();
3403+
3404+ InitRoot (server, sender);
3405+
3406+ CreateShardedTable (server, sender, " /Root" , " table-1" , 1 );
3407+ CreateShardedTable (server, sender, " /Root" , " table-2" , 1 );
3408+ auto table1shards = GetTableShards (server, sender, " /Root/table-1" );
3409+
3410+ ExecSQL (server, sender, Q_ (" UPSERT INTO `/Root/table-1` (key, value) VALUES (1, 10)" ));
3411+ ExecSQL (server, sender, Q_ (" UPSERT INTO `/Root/table-2` (key, value) VALUES (2, 20)" ));
3412+
3413+ // Block readset exchange
3414+ std::vector<std::unique_ptr<IEventHandle>> readSets;
3415+ auto blockReadSets = runtime.AddObserver <TEvTxProcessing::TEvReadSet>([&](TEvTxProcessing::TEvReadSet::TPtr& ev) {
3416+ readSets.emplace_back (ev.Release ());
3417+ });
3418+
3419+ // Start a distributed write to both tables
3420+ TString sessionId = CreateSessionRPC (runtime, " /Root" );
3421+ auto upsertResult = SendRequest (
3422+ runtime,
3423+ MakeSimpleRequestRPC (R"(
3424+ UPSERT INTO `/Root/table-1` (key, value) VALUES (3, 30);
3425+ UPSERT INTO `/Root/table-2` (key, value) VALUES (4, 40);
3426+ )" , sessionId, /* txId */ " " , /* commitTx */ true ),
3427+ " /Root" );
3428+ WaitFor (runtime, [&]{ return readSets.size () >= 4 ; }, " readsets" );
3429+
3430+ // Start reading the first table
3431+ TString readSessionId = CreateSessionRPC (runtime, " /Root" );
3432+ auto readResult = SendRequest (
3433+ runtime,
3434+ MakeSimpleRequestRPC (R"(
3435+ SELECT key, value FROM `/Root/table-1`
3436+ ORDER BY key;
3437+ )" , readSessionId, /* txId */ " " , /* commitTx */ true ),
3438+ " /Root" );
3439+
3440+ // Sleep to ensure read is properly waiting
3441+ runtime.SimulateSleep (TDuration::Seconds (1 ));
3442+
3443+ // Gracefully restart the first table shard
3444+ blockReadSets.Remove ();
3445+ GracefulRestartTablet (runtime, table1shards[0 ], sender);
3446+
3447+ // Read succeeds because it is automatically retried
3448+ // No assert should be triggered in debug builds
3449+ UNIT_ASSERT_VALUES_EQUAL (
3450+ FormatResult (AwaitResponse (runtime, std::move (readResult))),
3451+ " { items { uint32_value: 1 } items { uint32_value: 10 } }, "
3452+ " { items { uint32_value: 3 } items { uint32_value: 30 } }" );
3453+ }
3454+
33893455Y_UNIT_TEST (TestShardSnapshotReadNoEarlyReply) {
33903456 TPortManager pm;
33913457 TServerSettings serverSettings (pm.GetPort (2134 ));
0 commit comments