diff options
| author | Alek5andr-Kotov <[email protected]> | 2024-07-24 13:59:34 +0300 |
|---|---|---|
| committer | GitHub <[email protected]> | 2024-07-24 13:59:34 +0300 |
| commit | bf2dd5d419c35103b0ce56db43c65becc4285695 (patch) | |
| tree | ba10b85764dba8167afc224e3bbd61e6e07b7138 | |
| parent | 55903d1d3165cdcc42b9217cbae58b48c49088fb (diff) | |
Transaction state after PQ tablet restart (#7015)
| -rw-r--r-- | ydb/core/persqueue/pq_impl.cpp | 81 | ||||
| -rw-r--r-- | ydb/core/persqueue/pq_impl.h | 1 | ||||
| -rw-r--r-- | ydb/core/persqueue/ut/pqtablet_ut.cpp | 164 |
3 files changed, 192 insertions, 54 deletions
diff --git a/ydb/core/persqueue/pq_impl.cpp b/ydb/core/persqueue/pq_impl.cpp index 9ec0dacc98b..baa67e2eda6 100644 --- a/ydb/core/persqueue/pq_impl.cpp +++ b/ydb/core/persqueue/pq_impl.cpp @@ -923,11 +923,9 @@ void TPersQueue::MoveTopTxToCalculating(TDistributedTransaction& tx, converterFactory, tx.TopicConverter, ctx); - if (InitCompleted) { - CreateNewPartitions(tx.TabletConfig, - tx.TopicConverter, - ctx); - } + CreateNewPartitions(tx.TabletConfig, + tx.TopicConverter, + ctx); SendEvProposePartitionConfig(ctx, tx); break; } @@ -940,24 +938,6 @@ void TPersQueue::MoveTopTxToCalculating(TDistributedTransaction& tx, ", NewState " << NKikimrPQ::TTransaction_EState_Name(tx.State)); } -void TPersQueue::UpdateTopTxState(const TActorContext& ctx) -{ - Y_ABORT_UNLESS(!InitCompleted); - - if (TxQueue.empty()) { - return; - } - - Y_ABORT_UNLESS(Txs.contains(TxQueue.front().second)); - auto& tx = Txs.at(TxQueue.front().second); - - if (tx.State <= NKikimrPQ::TTransaction::PLANNED) { - return; - } - - MoveTopTxToCalculating(tx, ctx); -} - void TPersQueue::AddSupportivePartition(const TPartitionId& partitionId) { Partitions.emplace(partitionId, @@ -1097,8 +1077,6 @@ void TPersQueue::ReadConfig(const NKikimrClient::TKeyValueResponse::TReadResult& ctx); } - UpdateTopTxState(ctx); - ConfigInited = true; InitializeMeteringSink(ctx); @@ -3961,7 +3939,9 @@ void TPersQueue::SendEvTxCommitToPartitions(const TActorContext& ctx, auto event = std::make_unique<TEvPQ::TEvTxCommit>(tx.Step, tx.TxId); auto p = Partitions.find(TPartitionId(partitionId)); - Y_ABORT_UNLESS(p != Partitions.end()); + Y_ABORT_UNLESS(p != Partitions.end(), + "Tablet %" PRIu64 ", Partition %" PRIu32 ", TxId %" PRIu64, + TabletID(), partitionId, tx.TxId); ctx.Send(p->second.Actor, event.release()); } @@ -4061,7 +4041,9 @@ void TPersQueue::CheckTxState(const TActorContext& ctx, switch (tx.State) { case NKikimrPQ::TTransaction::UNKNOWN: - Y_ABORT_UNLESS(tx.TxId != Max<ui64>()); + Y_ABORT_UNLESS(tx.TxId != Max<ui64>(), + "PQ %" PRIu64 ", TxId %" PRIu64, + TabletID(), tx.TxId); WriteTx(tx, NKikimrPQ::TTransaction::PREPARED); ScheduleProposeTransactionResult(tx); @@ -4073,7 +4055,9 @@ void TPersQueue::CheckTxState(const TActorContext& ctx, break; case NKikimrPQ::TTransaction::PREPARING: - Y_ABORT_UNLESS(tx.WriteInProgress); + Y_ABORT_UNLESS(tx.WriteInProgress, + "PQ %" PRIu64 ", TxId %" PRIu64, + TabletID(), tx.TxId); tx.WriteInProgress = false; @@ -4088,7 +4072,9 @@ void TPersQueue::CheckTxState(const TActorContext& ctx, break; case NKikimrPQ::TTransaction::PREPARED: - Y_ABORT_UNLESS(tx.Step != Max<ui64>()); + Y_ABORT_UNLESS(tx.Step != Max<ui64>(), + "PQ %" PRIu64 ", TxId %" PRIu64, + TabletID(), tx.TxId); WriteTx(tx, NKikimrPQ::TTransaction::PLANNED); @@ -4099,7 +4085,9 @@ void TPersQueue::CheckTxState(const TActorContext& ctx, break; case NKikimrPQ::TTransaction::PLANNING: - Y_ABORT_UNLESS(tx.WriteInProgress); + Y_ABORT_UNLESS(tx.WriteInProgress, + "PQ %" PRIu64 ", TxId %" PRIu64, + TabletID(), tx.TxId); tx.WriteInProgress = false; @@ -4123,7 +4111,10 @@ void TPersQueue::CheckTxState(const TActorContext& ctx, break; case NKikimrPQ::TTransaction::CALCULATING: - Y_ABORT_UNLESS(tx.PartitionRepliesCount <= tx.PartitionRepliesExpected); + Y_ABORT_UNLESS(tx.PartitionRepliesCount <= tx.PartitionRepliesExpected, + "PQ %" PRIu64 ", TxId %" PRIu64 ", PartitionRepliesCount %" PRISZT ", PartitionRepliesExpected %" PRISZT, + TabletID(), tx.TxId, + tx.PartitionRepliesCount, tx.PartitionRepliesExpected); PQ_LOG_D("Received " << tx.PartitionRepliesCount << ", Expected " << tx.PartitionRepliesExpected); @@ -4132,8 +4123,6 @@ void TPersQueue::CheckTxState(const TActorContext& ctx, switch (tx.Kind) { case NKikimrPQ::TTransaction::KIND_DATA: case NKikimrPQ::TTransaction::KIND_CONFIG: - WriteTx(tx, NKikimrPQ::TTransaction::WAIT_RS); - tx.State = NKikimrPQ::TTransaction::CALCULATED; PQ_LOG_D("TxId " << tx.TxId << ", NewState " << NKikimrPQ::TTransaction_EState_Name(tx.State)); @@ -4143,14 +4132,16 @@ void TPersQueue::CheckTxState(const TActorContext& ctx, case NKikimrPQ::TTransaction::KIND_UNKNOWN: Y_ABORT_UNLESS(false); } + } else { + break; } - break; + [[fallthrough]]; case NKikimrPQ::TTransaction::CALCULATED: - Y_ABORT_UNLESS(tx.WriteInProgress); - - tx.WriteInProgress = false; + Y_ABORT_UNLESS(!tx.WriteInProgress, + "PQ %" PRIu64 ", TxId %" PRIu64, + TabletID(), tx.TxId); tx.State = NKikimrPQ::TTransaction::WAIT_RS; PQ_LOG_D("TxId " << tx.TxId << @@ -4164,7 +4155,8 @@ void TPersQueue::CheckTxState(const TActorContext& ctx, // from TEvProposeTransaction // Y_ABORT_UNLESS(tx.ReadSetAcks.size() <= tx.PredicatesReceived.size(), - "tx.ReadSetAcks.size=%" PRISZT ", tx.PredicatesReceived.size=%" PRISZT, + "PQ %" PRIu64 ", TxId %" PRIu64 ", ReadSetAcks.size %" PRISZT ", PredicatesReceived.size %" PRISZT, + TabletID(), tx.TxId, tx.ReadSetAcks.size(), tx.PredicatesReceived.size()); SendEvReadSetToReceivers(ctx, tx); @@ -4188,14 +4180,21 @@ void TPersQueue::CheckTxState(const TActorContext& ctx, [[fallthrough]]; case NKikimrPQ::TTransaction::EXECUTING: - Y_ABORT_UNLESS(tx.PartitionRepliesCount <= tx.PartitionRepliesExpected); + Y_ABORT_UNLESS(tx.PartitionRepliesCount <= tx.PartitionRepliesExpected, + "PQ %" PRIu64 ", TxId %" PRIu64 ", PartitionRepliesCount %" PRISZT ", PartitionRepliesExpected %" PRISZT, + TabletID(), tx.TxId, + tx.PartitionRepliesCount, tx.PartitionRepliesExpected); PQ_LOG_D("Received " << tx.PartitionRepliesCount << ", Expected " << tx.PartitionRepliesExpected); if (tx.PartitionRepliesCount == tx.PartitionRepliesExpected) { - Y_ABORT_UNLESS(!TxQueue.empty()); - Y_ABORT_UNLESS(TxQueue.front().second == tx.TxId); + Y_ABORT_UNLESS(!TxQueue.empty(), + "PQ %" PRIu64 ", TxId %" PRIu64, + TabletID(), tx.TxId); + Y_ABORT_UNLESS(TxQueue.front().second == tx.TxId, + "PQ %" PRIu64 ", TxId %" PRIu64, + TabletID(), tx.TxId); SendEvProposeTransactionResult(ctx, tx); diff --git a/ydb/core/persqueue/pq_impl.h b/ydb/core/persqueue/pq_impl.h index b6a787f5df4..f01a0a3f786 100644 --- a/ydb/core/persqueue/pq_impl.h +++ b/ydb/core/persqueue/pq_impl.h @@ -504,7 +504,6 @@ private: const TWriteId& writeId) const; bool CheckTxWriteOperations(const NKikimrPQ::TDataTransaction& txBody) const; - void UpdateTopTxState(const TActorContext& ctx); void MoveTopTxToCalculating(TDistributedTransaction& tx, const TActorContext& ctx); }; diff --git a/ydb/core/persqueue/ut/pqtablet_ut.cpp b/ydb/core/persqueue/ut/pqtablet_ut.cpp index 5d382d36083..59dba2354f3 100644 --- a/ydb/core/persqueue/ut/pqtablet_ut.cpp +++ b/ydb/core/persqueue/ut/pqtablet_ut.cpp @@ -206,9 +206,9 @@ protected: void StartPQWriteTxsObserver(); void WaitForPQWriteTxs(); - template <class T> void WaitForEvent(); - void WaitForCalcPredicateResult(); - void WaitForProposePartitionConfigResult(); + template <class T> void WaitForEvent(size_t count); + void WaitForCalcPredicateResult(size_t count = 1); + void WaitForProposePartitionConfigResult(size_t count = 1); void TestWaitingForTEvReadSet(size_t senders, size_t receivers); @@ -524,14 +524,16 @@ void TPQTabletFixture::WaitDropTabletReply(const TDropTabletReplyMatcher& matche } template <class T> -void TPQTabletFixture::WaitForEvent() +void TPQTabletFixture::WaitForEvent(size_t count) { bool found = false; + size_t received = 0; TTestActorRuntimeBase::TEventObserver prev; - auto observer = [&found, &prev](TAutoPtr<IEventHandle>& event) { + auto observer = [&found, &prev, &received, count](TAutoPtr<IEventHandle>& event) { if (auto* msg = event->CastAsLocal<T>()) { - found = true; + ++received; + found = (received >= count); } return prev ? prev(event) : TTestActorRuntimeBase::EEventAction::PROCESS; @@ -549,14 +551,14 @@ void TPQTabletFixture::WaitForEvent() Ctx->Runtime->SetObserverFunc(prev); } -void TPQTabletFixture::WaitForCalcPredicateResult() +void TPQTabletFixture::WaitForCalcPredicateResult(size_t count) { - WaitForEvent<TEvPQ::TEvTxCalcPredicateResult>(); + WaitForEvent<TEvPQ::TEvTxCalcPredicateResult>(count); } -void TPQTabletFixture::WaitForProposePartitionConfigResult() +void TPQTabletFixture::WaitForProposePartitionConfigResult(size_t count) { - WaitForEvent<TEvPQ::TEvProposePartitionConfigResult>(); + WaitForEvent<TEvPQ::TEvProposePartitionConfigResult>(count); } std::unique_ptr<TEvPersQueue::TEvRequest> TPQTabletFixture::MakeGetOwnershipRequest(const TGetOwnershipRequestParams& params, @@ -1370,7 +1372,7 @@ Y_UNIT_TEST_F(Read_TEvTxCommit_After_Restart, TPQTabletFixture) WaitForCalcPredicateResult(); - // the transaction is now in the WAIT_RS state on disk and in memory + // the transaction is now in the WAIT_RS state in memory and PLANNED state in disk PQTabletRestart(*Ctx); @@ -1416,7 +1418,145 @@ Y_UNIT_TEST_F(Config_TEvTxCommit_After_Restart, TPQTabletFixture) WaitForProposePartitionConfigResult(); - // the transaction is now in the WAIT_RS state on disk and in memory + // the transaction is now in the WAIT_RS state in memory and PLANNED state in disk + + PQTabletRestart(*Ctx); + + tablet->SendReadSet(*Ctx->Runtime, {.Step=100, .TxId=txId, .Target=Ctx->TabletId, .Decision=NKikimrTx::TReadSetData::DECISION_COMMIT}); + + WaitProposeTransactionResponse({.TxId=txId, + .Status=NKikimrPQ::TEvProposeTransactionResult::COMPLETE}); + + tablet->SendReadSetAck(*Ctx->Runtime, {.Step=100, .TxId=txId, .Source=Ctx->TabletId}); + WaitReadSetAck(*tablet, {.Step=100, .TxId=txId, .Source=mockTabletId, .Target=Ctx->TabletId, .Consumer=Ctx->TabletId}); +} + +Y_UNIT_TEST_F(One_Tablet_For_All_Partitions, TPQTabletFixture) +{ + const ui64 txId = 67890; + + PQTabletPrepare({.partitions=1}, {}, *Ctx); + + auto tabletConfig = NHelpers::MakeConfig({.Version=2, + .Consumers={ + {.Consumer="client-1", .Generation=0}, + {.Consumer="client-3", .Generation=7} + }, + .Partitions={ + {.Id=0}, + {.Id=1}, + {.Id=2} + }, + .AllPartitions={ + {.Id=0, .TabletId=Ctx->TabletId, .Children={1, 2}, .Parents={}}, + {.Id=1, .TabletId=Ctx->TabletId, .Children={}, .Parents={0}}, + {.Id=2, .TabletId=Ctx->TabletId, .Children={}, .Parents={0}} + }}); + + SendProposeTransactionRequest({.TxId=txId, + .Configs=NHelpers::TConfigParams{ + .Tablet=tabletConfig, + .Bootstrap=NHelpers::MakeBootstrapConfig(), + }}); + WaitProposeTransactionResponse({.TxId=txId, + .Status=NKikimrPQ::TEvProposeTransactionResult::PREPARED}); + + SendPlanStep({.Step=100, .TxIds={txId}}); + + WaitForProposePartitionConfigResult(2); + + // the transaction is now in the WAIT_RS state in memory and PLANNED state in disk + + PQTabletRestart(*Ctx); + + WaitProposeTransactionResponse({.TxId=txId, + .Status=NKikimrPQ::TEvProposeTransactionResult::COMPLETE}); +} + +Y_UNIT_TEST_F(One_New_Partition_In_Another_Tablet, TPQTabletFixture) +{ + const ui64 txId = 67890; + const ui64 mockTabletId = 22222; + + NHelpers::TPQTabletMock* tablet = CreatePQTabletMock(mockTabletId); + PQTabletPrepare({.partitions=1}, {}, *Ctx); + + auto tabletConfig = NHelpers::MakeConfig({.Version=2, + .Consumers={ + {.Consumer="client-1", .Generation=0}, + {.Consumer="client-3", .Generation=7} + }, + .Partitions={ + {.Id=0}, + {.Id=1}, + }, + .AllPartitions={ + {.Id=0, .TabletId=Ctx->TabletId, .Children={1, 2}, .Parents={}}, + {.Id=1, .TabletId=Ctx->TabletId, .Children={}, .Parents={0}}, + {.Id=2, .TabletId=mockTabletId, .Children={}, .Parents={0}} + }}); + + SendProposeTransactionRequest({.TxId=txId, + .Configs=NHelpers::TConfigParams{ + .Tablet=tabletConfig, + .Bootstrap=NHelpers::MakeBootstrapConfig(), + }}); + WaitProposeTransactionResponse({.TxId=txId, + .Status=NKikimrPQ::TEvProposeTransactionResult::PREPARED}); + + SendPlanStep({.Step=100, .TxIds={txId}}); + + WaitForProposePartitionConfigResult(2); + + // the transaction is now in the WAIT_RS state in memory and PLANNED state in disk + + PQTabletRestart(*Ctx); + + tablet->SendReadSet(*Ctx->Runtime, {.Step=100, .TxId=txId, .Target=Ctx->TabletId, .Decision=NKikimrTx::TReadSetData::DECISION_COMMIT}); + + WaitProposeTransactionResponse({.TxId=txId, + .Status=NKikimrPQ::TEvProposeTransactionResult::COMPLETE}); + + tablet->SendReadSetAck(*Ctx->Runtime, {.Step=100, .TxId=txId, .Source=Ctx->TabletId}); + WaitReadSetAck(*tablet, {.Step=100, .TxId=txId, .Source=mockTabletId, .Target=Ctx->TabletId, .Consumer=Ctx->TabletId}); +} + +Y_UNIT_TEST_F(All_New_Partitions_In_Another_Tablet, TPQTabletFixture) +{ + const ui64 txId = 67890; + const ui64 mockTabletId = 22222; + + NHelpers::TPQTabletMock* tablet = CreatePQTabletMock(mockTabletId); + PQTabletPrepare({.partitions=1}, {}, *Ctx); + + auto tabletConfig = NHelpers::MakeConfig({.Version=2, + .Consumers={ + {.Consumer="client-1", .Generation=0}, + {.Consumer="client-3", .Generation=7} + }, + .Partitions={ + {.Id=0}, + {.Id=1}, + }, + .AllPartitions={ + {.Id=0, .TabletId=Ctx->TabletId, .Children={}, .Parents={2}}, + {.Id=1, .TabletId=Ctx->TabletId, .Children={}, .Parents={2}}, + {.Id=2, .TabletId=mockTabletId, .Children={0, 1}, .Parents={}} + }}); + + SendProposeTransactionRequest({.TxId=txId, + .Configs=NHelpers::TConfigParams{ + .Tablet=tabletConfig, + .Bootstrap=NHelpers::MakeBootstrapConfig(), + }}); + WaitProposeTransactionResponse({.TxId=txId, + .Status=NKikimrPQ::TEvProposeTransactionResult::PREPARED}); + + SendPlanStep({.Step=100, .TxIds={txId}}); + + WaitForProposePartitionConfigResult(2); + + // the transaction is now in the WAIT_RS state in memory and PLANNED state in disk PQTabletRestart(*Ctx); |
