@@ -3020,10 +3020,12 @@ Y_UNIT_TEST_SUITE(DataShardVolatile) {
30203020
30213021 // We need to fill table with some data
30223022 Cerr << " ========= Upserting initial values =========" << Endl;
3023- KqpSimpleExec (runtime, R"(
3024- UPSERT INTO `/Root/table` (key, subkey, value)
3025- VALUES (1, 1), (11, 11)
3026- )" );
3023+ UNIT_ASSERT_VALUES_EQUAL (
3024+ KqpSimpleExec (runtime, R"(
3025+ UPSERT INTO `/Root/table` (key, value)
3026+ VALUES (1, 1), (11, 11)
3027+ )" ),
3028+ " <empty>" );
30273029
30283030 TForceVolatileProposeArbiter forceArbiter (runtime, shards.at (0 ));
30293031 TBlockEvents<TEvTxProcessing::TEvPlanStep> blockedPlan (runtime,
@@ -3080,6 +3082,206 @@ Y_UNIT_TEST_SUITE(DataShardVolatile) {
30803082 Cerr << " ... split finished" << Endl;
30813083 }
30823084
3085+ Y_UNIT_TEST (DistributedUpsertRestartBeforePrepare) {
3086+ TPortManager pm;
3087+ TServerSettings serverSettings (pm.GetPort (2134 ));
3088+ serverSettings.SetDomainName (" Root" )
3089+ .SetUseRealThreads (false )
3090+ .SetEnableDataShardVolatileTransactions (true );
3091+
3092+ Tests::TServer::TPtr server = new TServer (serverSettings);
3093+ auto &runtime = *server->GetRuntime ();
3094+ auto sender = runtime.AllocateEdgeActor ();
3095+
3096+ runtime.SetLogPriority (NKikimrServices::TX_DATASHARD, NLog::PRI_TRACE);
3097+ runtime.SetLogPriority (NKikimrServices::PIPE_CLIENT, NLog::PRI_TRACE);
3098+
3099+ InitRoot (server, sender);
3100+
3101+ Cerr << " ========= Creating the table =========" << Endl;
3102+ UNIT_ASSERT_VALUES_EQUAL (
3103+ KqpSchemeExec (runtime, R"(
3104+ CREATE TABLE `/Root/table` (key uint32, value uint32, PRIMARY KEY (key))
3105+ WITH (PARTITION_AT_KEYS = (10));
3106+ )" ),
3107+ " SUCCESS" );
3108+
3109+ const auto shards = GetTableShards (server, sender, " /Root/table" );
3110+ UNIT_ASSERT_VALUES_EQUAL (shards.size (), 2u );
3111+
3112+ // We need to fill table with some data
3113+ Cerr << " ========= Upserting initial values =========" << Endl;
3114+ UNIT_ASSERT_VALUES_EQUAL (
3115+ KqpSimpleExec (runtime, R"(
3116+ UPSERT INTO `/Root/table` (key, value)
3117+ VALUES (1, 1), (11, 11)
3118+ )" ),
3119+ " <empty>" );
3120+
3121+ TBlockEvents<TEvDataShard::TEvProposeTransaction> blockedPrepare (runtime);
3122+
3123+ Cerr << " ========= Starting upsert 1 =========" << Endl;
3124+ auto upsertFuture1 = KqpSimpleSend (runtime, R"(
3125+ UPSERT INTO `/Root/table` (key, value)
3126+ VALUES (2, 2), (12, 12);
3127+ )" );
3128+
3129+ runtime.WaitFor (" prepare requests" , [&]{ return blockedPrepare.size () >= 2 ; });
3130+ UNIT_ASSERT_VALUES_EQUAL (blockedPrepare.size (), 2u );
3131+
3132+ blockedPrepare.Stop ();
3133+
3134+ Cerr << " ========= Restarting shard 1 =========" << Endl;
3135+ GracefulRestartTablet (runtime, shards.at (0 ), sender);
3136+
3137+ UNIT_ASSERT_VALUES_EQUAL (
3138+ FormatResult (runtime.WaitFuture (std::move (upsertFuture1))),
3139+ " ERROR: UNAVAILABLE" );
3140+ }
3141+
3142+ Y_UNIT_TEST (DistributedUpsertRestartAfterPrepare) {
3143+ TPortManager pm;
3144+ TServerSettings serverSettings (pm.GetPort (2134 ));
3145+ serverSettings.SetDomainName (" Root" )
3146+ .SetUseRealThreads (false )
3147+ .SetEnableDataShardVolatileTransactions (true );
3148+
3149+ Tests::TServer::TPtr server = new TServer (serverSettings);
3150+ auto &runtime = *server->GetRuntime ();
3151+ auto sender = runtime.AllocateEdgeActor ();
3152+
3153+ runtime.SetLogPriority (NKikimrServices::TX_DATASHARD, NLog::PRI_TRACE);
3154+ runtime.SetLogPriority (NKikimrServices::PIPE_CLIENT, NLog::PRI_TRACE);
3155+
3156+ InitRoot (server, sender);
3157+
3158+ Cerr << " ========= Creating the table =========" << Endl;
3159+ UNIT_ASSERT_VALUES_EQUAL (
3160+ KqpSchemeExec (runtime, R"(
3161+ CREATE TABLE `/Root/table` (key uint32, value uint32, PRIMARY KEY (key))
3162+ WITH (PARTITION_AT_KEYS = (10));
3163+ )" ),
3164+ " SUCCESS" );
3165+
3166+ const auto shards = GetTableShards (server, sender, " /Root/table" );
3167+ UNIT_ASSERT_VALUES_EQUAL (shards.size (), 2u );
3168+
3169+ // We need to fill table with some data
3170+ Cerr << " ========= Upserting initial values =========" << Endl;
3171+ UNIT_ASSERT_VALUES_EQUAL (
3172+ KqpSimpleExec (runtime, R"(
3173+ UPSERT INTO `/Root/table` (key, value)
3174+ VALUES (1, 1), (11, 11)
3175+ )" ),
3176+ " <empty>" );
3177+
3178+ TBlockEvents<TEvDataShard::TEvProposeTransactionResult> blockedPrepare (runtime);
3179+
3180+ Cerr << " ========= Starting upsert 1 =========" << Endl;
3181+ auto upsertFuture1 = KqpSimpleSend (runtime, R"(
3182+ UPSERT INTO `/Root/table` (key, value)
3183+ VALUES (2, 2), (12, 12);
3184+ )" );
3185+
3186+ runtime.WaitFor (" prepare results" , [&]{ return blockedPrepare.size () >= 2 ; });
3187+ UNIT_ASSERT_VALUES_EQUAL (blockedPrepare.size (), 2u );
3188+
3189+ for (auto & ev : blockedPrepare) {
3190+ auto * msg = ev->Get ();
3191+ UNIT_ASSERT_VALUES_EQUAL (msg->Record .GetStatus (), NKikimrTxDataShard::TEvProposeTransactionResult::PREPARED);
3192+ }
3193+
3194+ // Unblock prepare results and restart the first shard
3195+ blockedPrepare.Stop ().Unblock ();
3196+
3197+ Cerr << " ========= Restarting shard 1 =========" << Endl;
3198+ GracefulRestartTablet (runtime, shards.at (0 ), sender);
3199+
3200+ UNIT_ASSERT_VALUES_EQUAL (
3201+ FormatResult (runtime.WaitFuture (std::move (upsertFuture1))),
3202+ " ERROR: ABORTED" );
3203+ }
3204+
3205+ Y_UNIT_TEST (DistributedUpsertRestartAfterPlan) {
3206+ TPortManager pm;
3207+ TServerSettings serverSettings (pm.GetPort (2134 ));
3208+ serverSettings.SetDomainName (" Root" )
3209+ .SetUseRealThreads (false )
3210+ .SetEnableDataShardVolatileTransactions (true );
3211+
3212+ Tests::TServer::TPtr server = new TServer (serverSettings);
3213+ auto &runtime = *server->GetRuntime ();
3214+ auto sender = runtime.AllocateEdgeActor ();
3215+
3216+ runtime.SetLogPriority (NKikimrServices::TX_DATASHARD, NLog::PRI_TRACE);
3217+ runtime.SetLogPriority (NKikimrServices::PIPE_CLIENT, NLog::PRI_TRACE);
3218+
3219+ InitRoot (server, sender);
3220+
3221+ Cerr << " ========= Creating the table =========" << Endl;
3222+ UNIT_ASSERT_VALUES_EQUAL (
3223+ KqpSchemeExec (runtime, R"(
3224+ CREATE TABLE `/Root/table` (key uint32, value uint32, PRIMARY KEY (key))
3225+ WITH (PARTITION_AT_KEYS = (10));
3226+ )" ),
3227+ " SUCCESS" );
3228+
3229+ const auto shards = GetTableShards (server, sender, " /Root/table" );
3230+ UNIT_ASSERT_VALUES_EQUAL (shards.size (), 2u );
3231+
3232+ // We need to fill table with some data
3233+ Cerr << " ========= Upserting initial values =========" << Endl;
3234+ UNIT_ASSERT_VALUES_EQUAL (
3235+ KqpSimpleExec (runtime, R"(
3236+ UPSERT INTO `/Root/table` (key, value)
3237+ VALUES (1, 1), (11, 11)
3238+ )" ),
3239+ " <empty>" );
3240+
3241+ TBlockEvents<TEvTxProcessing::TEvPlanStep> blockedPlan (runtime);
3242+
3243+ Cerr << " ========= Starting upsert 1 =========" << Endl;
3244+ auto upsertFuture1 = KqpSimpleSend (runtime, R"(
3245+ UPSERT INTO `/Root/table` (key, value)
3246+ VALUES (2, 2), (12, 12);
3247+ )" );
3248+
3249+ runtime.WaitFor (" shard plans" , [&]{ return blockedPlan.size () >= 2 ; });
3250+ UNIT_ASSERT_VALUES_EQUAL (blockedPlan.size (), 2u );
3251+
3252+ // Block TEvPrivate::TEvProgressTransaction for shard1
3253+ auto shard1actor = ResolveTablet (runtime, shards.at (0 ));
3254+ TBlockEvents<IEventHandle> blockedProgress (runtime,
3255+ [&](const TAutoPtr<IEventHandle>& ev) {
3256+ return ev->GetRecipientRewrite () == shard1actor &&
3257+ ev->GetTypeRewrite () == EventSpaceBegin (TKikimrEvents::ES_PRIVATE) + 0 ;
3258+ });
3259+
3260+ // Unblock prepare results and restart the first shard
3261+ blockedPlan.Stop ().Unblock ();
3262+ runtime.WaitFor (" blocked progress" , [&]{ return blockedProgress.size () >= 1 ; });
3263+ UNIT_ASSERT_VALUES_EQUAL (blockedProgress.size (), 1u );
3264+
3265+ Cerr << " ... sleeping for 1 second" << Endl;
3266+ runtime.SimulateSleep (TDuration::Seconds (1 ));
3267+
3268+ Cerr << " ========= Restarting shard 1 =========" << Endl;
3269+ GracefulRestartTablet (runtime, shards.at (0 ), sender);
3270+
3271+ UNIT_ASSERT_VALUES_EQUAL (
3272+ FormatResult (runtime.WaitFuture (std::move (upsertFuture1))),
3273+ " ERROR: ABORTED" );
3274+
3275+ Cerr << " ========= Checking table =========" << Endl;
3276+ UNIT_ASSERT_VALUES_EQUAL (
3277+ KqpSimpleExec (runtime, R"(
3278+ SELECT key, value FROM `/Root/table`
3279+ ORDER BY key;
3280+ )" ),
3281+ " { items { uint32_value: 1 } items { uint32_value: 1 } }, "
3282+ " { items { uint32_value: 11 } items { uint32_value: 11 } }" );
3283+ }
3284+
30833285} // Y_UNIT_TEST_SUITE(DataShardVolatile)
30843286
30853287} // namespace NKikimr
0 commit comments