|
1 | 1 | #include "base_compute_actor.h"
|
2 | 2 |
|
| 3 | +#include <ydb/core/fq/libs/common/rows_proto_splitter.h> |
3 | 4 | #include <ydb/core/fq/libs/common/util.h>
|
4 | 5 | #include <ydb/core/fq/libs/compute/common/metrics.h>
|
5 | 6 | #include <ydb/core/fq/libs/compute/common/retry_actor.h>
|
|
22 | 23 | #include <ydb/library/actors/core/log.h>
|
23 | 24 | #include <library/cpp/protobuf/interop/cast.h>
|
24 | 25 |
|
| 26 | +#include <queue> |
| 27 | + |
25 | 28 | #define LOG_E(stream) LOG_ERROR_S(*TlsActivationContext, NKikimrServices::FQ_RUN_ACTOR, "[ydb] [ResultWriter] QueryId: " << Params.QueryId << " OperationId: " << ProtoToString(OperationId) << " " << stream)
|
26 | 29 | #define LOG_W(stream) LOG_WARN_S( *TlsActivationContext, NKikimrServices::FQ_RUN_ACTOR, "[ydb] [ResultWriter] QueryId: " << Params.QueryId << " OperationId: " << ProtoToString(OperationId) << " " << stream)
|
27 | 30 | #define LOG_I(stream) LOG_INFO_S( *TlsActivationContext, NKikimrServices::FQ_RUN_ACTOR, "[ydb] [ResultWriter] QueryId: " << Params.QueryId << " OperationId: " << ProtoToString(OperationId) << " " << stream)
|
@@ -92,28 +95,39 @@ class TResultSetWriterActor : public TBaseComputeActor<TResultSetWriterActor> {
|
92 | 95 | )
|
93 | 96 |
|
94 | 97 | void Handle(const TEvYdbCompute::TEvFetchScriptResultResponse::TPtr& ev) {
|
95 |
| - const auto& response = *ev.Get()->Get(); |
| 98 | + auto& response = *ev.Get()->Get(); |
96 | 99 | if (response.Status != NYdb::EStatus::SUCCESS) {
|
97 | 100 | LOG_E("ResultSetId: " << ResultSetId << " Can't fetch script result: " << ev->Get()->Issues.ToOneLineString());
|
98 | 101 | Send(Parent, new TEvYdbCompute::TEvResultSetWriterResponse(ResultSetId, ev->Get()->Issues, NYdb::EStatus::INTERNAL_ERROR));
|
99 | 102 | FailedAndPassAway();
|
100 | 103 | return;
|
101 | 104 | }
|
102 | 105 |
|
103 |
| - auto startTime = TInstant::Now(); |
| 106 | + LOG_I("ResultSetId: " << ResultSetId << " FetchToken: " << FetchToken << " Successfully fetched " << response.ResultSet->RowsCount() << " rows"); |
104 | 107 | Truncated |= response.ResultSet->Truncated();
|
105 | 108 | FetchToken = response.NextFetchToken;
|
106 | 109 | auto emptyResultSet = response.ResultSet->RowsCount() == 0;
|
107 |
| - const auto resultSetProto = NYdb::TProtoAccessor::GetProto(*response.ResultSet); |
| 110 | + auto resultSetProto = NYdb::TProtoAccessor::GetProto(std::move(*response.ResultSet)); |
108 | 111 |
|
109 | 112 | if (!emptyResultSet) {
|
110 |
| - auto chunk = CreateProtoRequestWithoutResultSet(Offset); |
111 |
| - WriterInflight[Cookie] = {Offset, startTime}; |
112 |
| - Offset += response.ResultSet->RowsCount(); |
113 |
| - *chunk.mutable_result_set() = resultSetProto; |
114 |
| - auto writeResultCounters = Counters.GetCounters(ERequestType::RT_WRITE_RESULT_SET); |
115 |
| - writeResultCounters->InFly->Inc(); |
116 |
| - Send(NFq::MakeInternalServiceActorId(), new NFq::TEvInternalService::TEvWriteResultRequest(std::move(chunk)), 0, Cookie++); |
| 113 | + NFq::TRowsProtoSplitter rowsSplitter(std::move(resultSetProto), ProtoMessageLimit, BaseProtoByteSize, MaxRowsCountPerChunk); |
| 114 | + auto splittedResultSets = rowsSplitter.Split(); |
| 115 | + |
| 116 | + if (!splittedResultSets.Success) { |
| 117 | + LOG_E("ResultSetId: " << ResultSetId << " Can't split script result: " << splittedResultSets.Issues.ToOneLineString()); |
| 118 | + Send(Parent, new TEvYdbCompute::TEvResultSetWriterResponse(ResultSetId, splittedResultSets.Issues, NYdb::EStatus::BAD_REQUEST)); |
| 119 | + FailedAndPassAway(); |
| 120 | + return; |
| 121 | + } |
| 122 | + |
| 123 | + for (auto& resultSet : splittedResultSets.ResultSets) { |
| 124 | + auto protoReq = CreateProtoRequestWithoutResultSet(Offset); |
| 125 | + Offset += resultSet.rows().size(); |
| 126 | + protoReq.mutable_result_set()->Swap(&resultSet); |
| 127 | + ResultChunks.emplace(std::move(protoReq)); |
| 128 | + } |
| 129 | + |
| 130 | + TryStartResultWriters(); |
117 | 131 | }
|
118 | 132 |
|
119 | 133 | if (WriterInflight.empty()) {
|
@@ -149,17 +163,31 @@ class TResultSetWriterActor : public TBaseComputeActor<TResultSetWriterActor> {
|
149 | 163 | return;
|
150 | 164 | }
|
151 | 165 |
|
| 166 | + TryStartResultWriters(); |
| 167 | + |
152 | 168 | writeResultCounters->Ok->Inc();
|
153 | 169 | LOG_I("ResultSetId: " << ResultSetId << " Cookie: " << cookie << " Result successfully written for offset " << meta.Offset);
|
154 | 170 | if (FetchToken) {
|
155 |
| - if (FetchToken != LastProcessedToken) { |
| 171 | + if (FetchToken != LastProcessedToken && WriterInflight.size() < MAX_WRITER_INFLIGHT) { |
156 | 172 | SendFetchScriptResultRequest();
|
157 | 173 | }
|
158 | 174 | } else if (WriterInflight.empty()) {
|
159 | 175 | SendReplyAndPassAway();
|
160 | 176 | }
|
161 | 177 | }
|
162 | 178 |
|
| 179 | + void TryStartResultWriters() { |
| 180 | + auto writeResultCounters = Counters.GetCounters(ERequestType::RT_WRITE_RESULT_SET); |
| 181 | + while (!ResultChunks.empty() && WriterInflight.size() < MAX_WRITER_INFLIGHT) { |
| 182 | + auto chunk = std::move(ResultChunks.front()); |
| 183 | + ResultChunks.pop(); |
| 184 | + |
| 185 | + WriterInflight[Cookie] = {static_cast<int64_t>(chunk.offset()), TInstant::Now()}; |
| 186 | + writeResultCounters->InFly->Inc(); |
| 187 | + Send(NFq::MakeInternalServiceActorId(), new NFq::TEvInternalService::TEvWriteResultRequest(std::move(chunk)), 0, Cookie++); |
| 188 | + } |
| 189 | + } |
| 190 | + |
163 | 191 | void SendFetchScriptResultRequest() {
|
164 | 192 | LastProcessedToken = FetchToken;
|
165 | 193 | Register(new TRetryActor<TEvYdbCompute::TEvFetchScriptResultRequest, TEvYdbCompute::TEvFetchScriptResultResponse, NKikimr::NOperationId::TOperationId, int64_t, TString>(Counters.GetCounters(ERequestType::RT_FETCH_SCRIPT_RESULT), SelfId(), Connector, OperationId, ResultSetId, FetchToken));
|
@@ -194,6 +222,10 @@ class TResultSetWriterActor : public TBaseComputeActor<TResultSetWriterActor> {
|
194 | 222 | bool Truncated = false;
|
195 | 223 | TString FetchToken;
|
196 | 224 | TString LastProcessedToken;
|
| 225 | + const size_t ProtoMessageLimit = 10_MB; |
| 226 | + const size_t MaxRowsCountPerChunk = 100'000; |
| 227 | + const size_t BaseProtoByteSize = CreateProtoRequestWithoutResultSet(0).ByteSizeLong(); |
| 228 | + std::queue<Fq::Private::WriteTaskResultRequest> ResultChunks; |
197 | 229 | };
|
198 | 230 |
|
199 | 231 | class TResultWriterActor : public TBaseComputeActor<TResultWriterActor> {
|
|
0 commit comments