Skip to content

Commit 8efacf9

Browse files
authored
Prepare & execute topics in BufferWriteActor (#12464)
1 parent 04c46d2 commit 8efacf9

File tree

9 files changed

+810
-318
lines changed

9 files changed

+810
-318
lines changed

ydb/core/kqp/common/kqp_tx_manager.cpp

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,32 @@ class TKqpTransactionManager : public IKqpTransactionManager {
5353
}
5454
}
5555

56+
void AddTopic(ui64 topicId, const TString& path) override {
57+
Y_ABORT_UNLESS(State == ETransactionState::COLLECTING);
58+
ShardsIds.insert(topicId);
59+
auto& shardInfo = ShardsInfo[topicId];
60+
61+
const auto [stringsIter, _] = TablePathes.insert(path);
62+
const TStringBuf pathBuf = *stringsIter;
63+
shardInfo.Pathes.insert(pathBuf);
64+
}
65+
66+
void AddTopicsToShards() override {
67+
if (!HasTopics()) {
68+
return;
69+
}
70+
71+
for (auto& topicId : GetTopicOperations().GetSendingTabletIds()) {
72+
AddTopic(topicId, *GetTopicOperations().GetTabletName(topicId));
73+
AddAction(topicId, EAction::READ);
74+
}
75+
76+
for (auto& topicId : GetTopicOperations().GetReceivingTabletIds()) {
77+
AddTopic(topicId, *GetTopicOperations().GetTabletName(topicId));
78+
AddAction(topicId, EAction::WRITE);
79+
}
80+
}
81+
5682
bool AddLock(ui64 shardId, const NKikimrDataEvents::TLock& lockProto) override {
5783
Y_ABORT_UNLESS(State == ETransactionState::COLLECTING);
5884
TKqpLock lock(lockProto);
@@ -124,6 +150,22 @@ class TKqpTransactionManager : public IKqpTransactionManager {
124150
ShardsInfo.at(shardId).State = state;
125151
}
126152

153+
void SetTopicOperations(NTopic::TTopicOperations&& topicOperations) override {
154+
TopicOperations = std::move(topicOperations);
155+
}
156+
157+
const NTopic::TTopicOperations& GetTopicOperations() const override {
158+
return TopicOperations;
159+
}
160+
161+
void BuildTopicTxs(NTopic::TTopicOperationTransactions& txs) override {
162+
TopicOperations.BuildTopicTxs(txs);
163+
}
164+
165+
bool HasTopics() const override {
166+
return GetTopicOperations().GetSize() != 0;
167+
}
168+
127169
TVector<NKikimrDataEvents::TLock> GetLocks() const override {
128170
TVector<NKikimrDataEvents::TLock> locks;
129171
for (const auto& [_, shardInfo] : ShardsInfo) {
@@ -189,7 +231,8 @@ class TKqpTransactionManager : public IKqpTransactionManager {
189231
bool IsVolatile() const override {
190232
return !HasOlapTable()
191233
&& !IsReadOnly()
192-
&& !IsSingleShard();
234+
&& !IsSingleShard()
235+
&& !HasTopics();
193236

194237
// TODO: && !HasPersistentChannels;
195238
// Note: currently persistent channels are never used
@@ -342,7 +385,7 @@ class TKqpTransactionManager : public IKqpTransactionManager {
342385
shardInfo.State = EShardState::EXECUTING;
343386
}
344387

345-
AFL_ENSURE(ReceivingShards.empty() || !IsSingleShard() || HasOlapTable());
388+
AFL_ENSURE(ReceivingShards.empty() || HasTopics() || !IsSingleShard() || HasOlapTable());
346389
}
347390

348391
TCommitInfo GetCommitInfo() override {
@@ -440,6 +483,8 @@ class TKqpTransactionManager : public IKqpTransactionManager {
440483

441484
THashSet<ui64> ShardsToWaitPrepare;
442485

486+
NTopic::TTopicOperations TopicOperations;
487+
443488
ui64 MinStep = 0;
444489
ui64 MaxStep = 0;
445490
ui64 Coordinator = 0;

ydb/core/kqp/common/kqp_tx_manager.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ class IKqpTransactionManager {
3737

3838
virtual void AddShard(ui64 shardId, bool isOlap, const TString& path) = 0;
3939
virtual void AddAction(ui64 shardId, ui8 action) = 0;
40+
virtual void AddTopic(ui64 topicId, const TString& path) = 0;
41+
virtual void AddTopicsToShards() = 0;
4042
virtual bool AddLock(ui64 shardId, const NKikimrDataEvents::TLock& lock) = 0;
4143

4244
virtual void BreakLock(ui64 shardId) = 0;
@@ -49,6 +51,13 @@ class IKqpTransactionManager {
4951
virtual EShardState GetState(ui64 shardId) const = 0;
5052
virtual void SetState(ui64 shardId, EShardState state) = 0;
5153

54+
virtual void SetTopicOperations(NTopic::TTopicOperations&& topicOperations) = 0;
55+
virtual const NTopic::TTopicOperations& GetTopicOperations() const = 0;
56+
57+
virtual void BuildTopicTxs(NTopic::TTopicOperationTransactions& txs) = 0;
58+
59+
virtual bool HasTopics() const = 0;
60+
5261
virtual bool IsTxPrepared() const = 0;
5362
virtual bool IsTxFinished() const = 0;
5463

ydb/core/kqp/executer_actor/kqp_data_executer.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1542,7 +1542,12 @@ class TKqpDataExecuter : public TKqpExecuterBase<TKqpDataExecuter, EExecType::Da
15421542

15431543
private:
15441544
bool IsReadOnlyTx() const {
1545-
if (Request.TopicOperations.HasOperations()) {
1545+
if (BufferActorId && TxManager->GetTopicOperations().HasOperations()) {
1546+
YQL_ENSURE(!Request.UseImmediateEffects);
1547+
return false;
1548+
}
1549+
1550+
if (!BufferActorId && Request.TopicOperations.HasOperations()) {
15461551
YQL_ENSURE(!Request.UseImmediateEffects);
15471552
return false;
15481553
}
@@ -2112,7 +2117,8 @@ class TKqpDataExecuter : public TKqpExecuterBase<TKqpDataExecuter, EExecType::Da
21122117
}
21132118

21142119
// Single-shard datashard transactions are always immediate
2115-
ImmediateTx = (datashardTxs.size() + evWriteTxs.size() + Request.TopicOperations.GetSize() + sourceScanPartitionsCount) <= 1
2120+
auto topicSize = (BufferActorId) ? TxManager->GetTopicOperations().GetSize() : Request.TopicOperations.GetSize();
2121+
ImmediateTx = (datashardTxs.size() + evWriteTxs.size() + topicSize + sourceScanPartitionsCount) <= 1
21162122
&& !UnknownAffectedShardCount
21172123
&& evWriteTxs.empty()
21182124
&& !HasOlapTable;
@@ -2392,6 +2398,7 @@ class TKqpDataExecuter : public TKqpExecuterBase<TKqpDataExecuter, EExecType::Da
23922398
}
23932399
}
23942400

2401+
YQL_ENSURE(!TxManager);
23952402
Request.TopicOperations.BuildTopicTxs(topicTxs);
23962403

23972404
const bool needRollback = Request.LocksOp == ELocksOp::Rollback;
@@ -2428,8 +2435,8 @@ class TKqpDataExecuter : public TKqpExecuterBase<TKqpDataExecuter, EExecType::Da
24282435
// HTAP transactions always use generic readsets
24292436
!evWriteTxs.empty());
24302437

2431-
if (!locksMap.empty() || VolatileTx ||
2432-
Request.TopicOperations.HasReadOperations() || Request.TopicOperations.HasWriteOperations())
2438+
if (!locksMap.empty() || VolatileTx || Request.TopicOperations.HasReadOperations()
2439+
|| Request.TopicOperations.HasWriteOperations())
24332440
{
24342441
YQL_ENSURE(Request.LocksOp == ELocksOp::Commit || Request.LocksOp == ELocksOp::Rollback || VolatileTx);
24352442

@@ -2776,6 +2783,7 @@ class TKqpDataExecuter : public TKqpExecuterBase<TKqpDataExecuter, EExecType::Da
27762783
void ExecuteTopicTabletTransactions(TTopicTabletTxs& topicTxs) {
27772784
YQL_ENSURE(!TxManager);
27782785
TMaybe<ui64> writeId;
2786+
27792787
if (Request.TopicOperations.HasWriteId()) {
27802788
writeId = Request.TopicOperations.GetWriteId();
27812789
}

ydb/core/kqp/runtime/kqp_write_actor.cpp

Lines changed: 167 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <ydb/core/tx/data_events/shards_splitter.h>
2121
#include <ydb/core/tx/scheme_cache/scheme_cache.h>
2222
#include <ydb/core/tx/tx.h>
23+
#include <ydb/core/persqueue/events/global.h>
2324
#include <ydb/library/actors/core/actorsystem.h>
2425
#include <ydb/library/actors/core/interconnect.h>
2526
#include <ydb/library/wilson_ids/wilson.h>
@@ -1356,6 +1357,7 @@ struct TEvBufferWriteResult : public TEventLocal<TEvBufferWriteResult, TKqpEvent
13561357

13571358
class TKqpBufferWriteActor :public TActorBootstrapped<TKqpBufferWriteActor>, public IKqpTableWriterCallbacks {
13581359
using TBase = TActorBootstrapped<TKqpBufferWriteActor>;
1360+
using TTopicTabletTxs = NTopic::TTopicOperationTransactions;
13591361

13601362
public:
13611363
enum class EState {
@@ -1384,6 +1386,7 @@ class TKqpBufferWriteActor :public TActorBootstrapped<TKqpBufferWriteActor>, pub
13841386
State = EState::WRITING;
13851387
Alloc->Release();
13861388
Counters->BufferActorsCount->Inc();
1389+
TxManager->AddTopicsToShards();
13871390
}
13881391

13891392
void Bootstrap() {
@@ -1404,6 +1407,7 @@ class TKqpBufferWriteActor :public TActorBootstrapped<TKqpBufferWriteActor>, pub
14041407
hFunc(TEvBufferWrite, Handle);
14051408

14061409
hFunc(TEvTxProxy::TEvProposeTransactionStatus, Handle);
1410+
hFunc(TEvPersQueue::TEvProposeTransactionResult, Handle);
14071411
hFunc(NKikimr::NEvents::TDataEvents::TEvWriteResult, Handle);
14081412
hFunc(TEvPipeCache::TEvDeliveryProblem, Handle);
14091413
default:
@@ -1590,6 +1594,7 @@ class TKqpBufferWriteActor :public TActorBootstrapped<TKqpBufferWriteActor>, pub
15901594
Close();
15911595
Process();
15921596
SendToExternalShards(false);
1597+
SendToTopics();
15931598
}
15941599

15951600
void ImmediateCommit() {
@@ -1687,6 +1692,63 @@ class TKqpBufferWriteActor :public TActorBootstrapped<TKqpBufferWriteActor>, pub
16871692
}
16881693
}
16891694

1695+
void SendToTopics() {
1696+
if (!TxManager->HasTopics()) {
1697+
return;
1698+
}
1699+
1700+
TTopicTabletTxs topicTxs;
1701+
TxManager->BuildTopicTxs(topicTxs);
1702+
1703+
TMaybe<ui64> writeId;
1704+
if (TxManager->GetTopicOperations().HasWriteId()) {
1705+
writeId = TxManager->GetTopicOperations().GetWriteId();
1706+
}
1707+
1708+
for (auto& [tabletId, t] : topicTxs) {
1709+
auto& transaction = t.tx;
1710+
transaction.SetOp(NKikimrPQ::TDataTransaction::Commit);
1711+
1712+
const auto prepareSettings = TxManager->GetPrepareTransactionInfo();
1713+
if (!prepareSettings.ArbiterColumnShard) {
1714+
for (const ui64 sendingShardId : prepareSettings.SendingShards) {
1715+
transaction.AddSendingShards(sendingShardId);
1716+
}
1717+
for (const ui64 receivingShardId : prepareSettings.ReceivingShards) {
1718+
transaction.AddReceivingShards(receivingShardId);
1719+
}
1720+
} else {
1721+
transaction.AddSendingShards(*prepareSettings.ArbiterColumnShard);
1722+
transaction.AddReceivingShards(*prepareSettings.ArbiterColumnShard);
1723+
}
1724+
1725+
auto ev = std::make_unique<TEvPersQueue::TEvProposeTransactionBuilder>();
1726+
1727+
if (t.hasWrite && writeId.Defined()) {
1728+
auto* w = transaction.MutableWriteId();
1729+
w->SetNodeId(SelfId().NodeId());
1730+
w->SetKeyId(*writeId);
1731+
}
1732+
transaction.SetImmediate(false);
1733+
1734+
ActorIdToProto(SelfId(), ev->Record.MutableSourceActor());
1735+
ev->Record.MutableData()->Swap(&transaction);
1736+
ev->Record.SetTxId(*TxId);
1737+
1738+
SendTime[tabletId] = TInstant::Now();
1739+
auto traceId = BufferWriteActor.GetTraceId();
1740+
1741+
CA_LOG_D("Preparing KQP transaction on topic tablet: " << tabletId << ", writeId: " << writeId);
1742+
1743+
Send(
1744+
MakePipePerNodeCacheID(false),
1745+
new TEvPipeCache::TEvForward(ev.release(), tabletId, /* subscribe */ true),
1746+
IEventHandle::FlagTrackDelivery,
1747+
0,
1748+
std::move(traceId));
1749+
}
1750+
}
1751+
16901752
void SendCommitToCoordinator() {
16911753
const auto commitInfo = TxManager->GetCommitInfo();
16921754

@@ -1810,6 +1872,69 @@ class TKqpBufferWriteActor :public TActorBootstrapped<TKqpBufferWriteActor>, pub
18101872
}
18111873
}
18121874

1875+
void Handle(TEvPersQueue::TEvProposeTransactionResult::TPtr& ev) {
1876+
auto& event = ev->Get()->Record;
1877+
const ui64 tabletId = event.GetOrigin();
1878+
1879+
CA_LOG_D("Got ProposeTransactionResult" <<
1880+
", PQ tablet: " << tabletId <<
1881+
", status: " << NKikimrPQ::TEvProposeTransactionResult_EStatus_Name(event.GetStatus()));
1882+
1883+
switch (event.GetStatus()) {
1884+
case NKikimrPQ::TEvProposeTransactionResult::PREPARED:
1885+
ProcessPreparedTopic(ev);
1886+
return;
1887+
case NKikimrPQ::TEvProposeTransactionResult::COMPLETE:
1888+
ProcessCompletedTopic(ev);
1889+
return;
1890+
case NKikimrPQ::TEvProposeTransactionResult::ABORTED:
1891+
CA_LOG_E("Got ABORTED ProposeTransactionResult for PQ."
1892+
<< " ShardID=" << ev->Get()->Record.GetOrigin() << ","
1893+
<< " Sink=" << this->SelfId() << ".");
1894+
ReplyErrorAndDie(
1895+
TStringBuilder() << "Aborted proposal status for PQ. ",
1896+
NYql::NDqProto::StatusIds::ABORTED,
1897+
{});
1898+
return;
1899+
case NKikimrPQ::TEvProposeTransactionResult::BAD_REQUEST:
1900+
CA_LOG_E("Got BAD REQUEST ProposeTransactionResult for PQ."
1901+
<< " ShardID=" << ev->Get()->Record.GetOrigin() << ","
1902+
<< " Sink=" << this->SelfId() << ".");
1903+
ReplyErrorAndDie(
1904+
TStringBuilder() << "Bad request proposal status for PQ. ",
1905+
NYql::NDqProto::StatusIds::BAD_REQUEST,
1906+
{});
1907+
return;
1908+
case NKikimrPQ::TEvProposeTransactionResult::OVERLOADED:
1909+
CA_LOG_E("Got OVERLOADED ProposeTransactionResult for PQ."
1910+
<< " ShardID=" << ev->Get()->Record.GetOrigin() << ","
1911+
<< " Sink=" << this->SelfId() << ".");
1912+
ReplyErrorAndDie(
1913+
TStringBuilder() << "Overloaded proposal status for PQ. ",
1914+
NYql::NDqProto::StatusIds::OVERLOADED,
1915+
{});
1916+
return;
1917+
case NKikimrPQ::TEvProposeTransactionResult::CANCELLED:
1918+
CA_LOG_E("Got CANCELLED ProposeTransactionResult for PQ."
1919+
<< " ShardID=" << ev->Get()->Record.GetOrigin() << ","
1920+
<< " Sink=" << this->SelfId() << ".");
1921+
ReplyErrorAndDie(
1922+
TStringBuilder() << "Cancelled proposal status for PQ. ",
1923+
NYql::NDqProto::StatusIds::CANCELLED,
1924+
{});
1925+
return;
1926+
default:
1927+
CA_LOG_E("Got undefined ProposeTransactionResult for PQ."
1928+
<< " ShardID=" << ev->Get()->Record.GetOrigin() << ","
1929+
<< " Sink=" << this->SelfId() << ".");
1930+
ReplyErrorAndDie(
1931+
TStringBuilder() << "Undefined proposal status for PQ. ",
1932+
NYql::NDqProto::StatusIds::INTERNAL_ERROR,
1933+
{});
1934+
return;
1935+
}
1936+
}
1937+
18131938
void Handle(TEvPipeCache::TEvDeliveryProblem::TPtr& ev) {
18141939
CA_LOG_W("TEvDeliveryProblem was received from tablet: " << ev->Get()->TabletId);
18151940
ReplyErrorAndDie(TStringBuilder() << "Failed to deviler message.", NYql::NDqProto::StatusIds::UNAVAILABLE, {});
@@ -1837,7 +1962,7 @@ class TKqpBufferWriteActor :public TActorBootstrapped<TKqpBufferWriteActor>, pub
18371962
Rollback();
18381963
State = EState::FINISHED;
18391964
Send(ExecuterActorId, new TEvKqpBuffer::TEvResult{});
1840-
} else if (TxManager->IsSingleShard() && !TxManager->HasOlapTable() && !WriteInfos.empty()) {
1965+
} else if (TxManager->IsSingleShard() && !TxManager->HasOlapTable() && !WriteInfos.empty() && !TxManager->HasTopics()) {
18411966
TxManager->StartExecute();
18421967
ImmediateCommit();
18431968
} else {
@@ -2016,6 +2141,47 @@ class TKqpBufferWriteActor :public TActorBootstrapped<TKqpBufferWriteActor>, pub
20162141
}
20172142
}
20182143

2144+
void ProcessPreparedTopic(TEvPersQueue::TEvProposeTransactionResult::TPtr& ev) {
2145+
if (State != EState::PREPARING) {
2146+
CA_LOG_D("Ignored topic prepared event.");
2147+
return;
2148+
}
2149+
OnMessageReceived(ev->Get()->Record.GetOrigin());
2150+
CA_LOG_D("Got propose prepared result TxId=" << ev->Get()->Record.GetTxId()
2151+
<< ", TabletId=" << ev->Get()->Record.GetOrigin()
2152+
<< ", Cookie=" << ev->Cookie);
2153+
2154+
const auto& record = ev->Get()->Record;
2155+
IKqpTransactionManager::TPrepareResult preparedInfo;
2156+
preparedInfo.ShardId = record.GetOrigin();
2157+
preparedInfo.MinStep = record.GetMinStep();
2158+
preparedInfo.MaxStep = record.GetMaxStep();
2159+
2160+
preparedInfo.Coordinator = 0;
2161+
if (record.DomainCoordinatorsSize()) {
2162+
auto domainCoordinators = TCoordinators(TVector<ui64>(record.GetDomainCoordinators().begin(),
2163+
record.GetDomainCoordinators().end()));
2164+
preparedInfo.Coordinator = domainCoordinators.Select(*TxId);
2165+
}
2166+
2167+
OnPrepared(std::move(preparedInfo), 0);
2168+
}
2169+
2170+
void ProcessCompletedTopic(TEvPersQueue::TEvProposeTransactionResult::TPtr& ev) {
2171+
NKikimrPQ::TEvProposeTransactionResult& event = ev->Get()->Record;
2172+
2173+
if (State != EState::COMMITTING) {
2174+
CA_LOG_D("Ignored completed event.");
2175+
return;
2176+
}
2177+
OnMessageReceived(event.GetOrigin());
2178+
CA_LOG_D("Got propose completed result" <<
2179+
", topic tablet: " << event.GetOrigin() <<
2180+
", status: " << NKikimrPQ::TEvProposeTransactionResult_EStatus_Name(event.GetStatus()));
2181+
2182+
OnCommitted(event.GetOrigin(), 0);
2183+
}
2184+
20192185
void ProcessWritePreparedShard(NKikimr::NEvents::TDataEvents::TEvWriteResult::TPtr& ev) {
20202186
if (State != EState::PREPARING) {
20212187
CA_LOG_D("Ignored write prepared event.");

0 commit comments

Comments
 (0)