summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPisarenko Grigoriy <[email protected]>2024-10-23 20:38:39 +0300
committerGitHub <[email protected]>2024-10-23 20:38:39 +0300
commit0ea658ab6edb7971ea29254cb58bfcb210e4bf05 (patch)
treeeb168446a019b49e48aa79b2c583ae9055e9df02
parent081bba7331c89c4c056ad8269d42e74cff773eb5 (diff)
YQ-3784 support computation graph invalidation in purecalc (#10799)
-rw-r--r--ydb/library/yql/public/purecalc/common/worker.cpp16
-rw-r--r--ydb/library/yql/public/purecalc/common/worker.h1
-rw-r--r--ydb/library/yql/public/purecalc/ut/test_mixed_allocators.cpp139
-rw-r--r--ydb/library/yql/public/purecalc/ut/ya.make1
4 files changed, 155 insertions, 2 deletions
diff --git a/ydb/library/yql/public/purecalc/common/worker.cpp b/ydb/library/yql/public/purecalc/common/worker.cpp
index f7d1ad1e723..e04e2062ba8 100644
--- a/ydb/library/yql/public/purecalc/common/worker.cpp
+++ b/ydb/library/yql/public/purecalc/common/worker.cpp
@@ -526,6 +526,18 @@ void TPushStreamWorker::FeedToConsumer() {
}
}
+NYql::NUdf::IBoxedValue* TPushStreamWorker::GetPushStream() const {
+ auto& ctx = Graph_.ComputationGraph_->GetContext();
+ NUdf::TUnboxedValue pushStream = SelfNode_->GetValue(ctx);
+
+ if (Y_UNLIKELY(pushStream.IsInvalid())) {
+ SelfNode_->SetValue(ctx, Graph_.ComputationGraph_->GetHolderFactory().Create<TPushStream>());
+ pushStream = SelfNode_->GetValue(ctx);
+ }
+
+ return pushStream.AsBoxed().Get();
+}
+
void TPushStreamWorker::SetConsumer(THolder<IConsumer<const NKikimr::NUdf::TUnboxedValue*>> consumer) {
auto guard = Guard(GetScopedAlloc());
const auto inputsCount = Graph_.SelfNodes_.size();
@@ -553,7 +565,7 @@ void TPushStreamWorker::Push(NKikimr::NUdf::TUnboxedValue&& value) {
YQL_ENSURE(!Finished_, "OnFinish has already been sent to the consumer; no new values can be pushed");
if (Y_LIKELY(SelfNode_)) {
- static_cast<TPushStream*>(SelfNode_->GetValue(Graph_.ComputationGraph_->GetContext()).AsBoxed().Get())->SetValue(std::move(value));
+ static_cast<TPushStream*>(GetPushStream())->SetValue(std::move(value));
}
FeedToConsumer();
@@ -564,7 +576,7 @@ void TPushStreamWorker::OnFinish() {
YQL_ENSURE(!Finished_, "already finished");
if (Y_LIKELY(SelfNode_)) {
- static_cast<TPushStream*>(SelfNode_->GetValue(Graph_.ComputationGraph_->GetContext()).AsBoxed().Get())->SetFinished();
+ static_cast<TPushStream*>(GetPushStream())->SetFinished();
}
FeedToConsumer();
diff --git a/ydb/library/yql/public/purecalc/common/worker.h b/ydb/library/yql/public/purecalc/common/worker.h
index 3f700ad353f..55eb440656b 100644
--- a/ydb/library/yql/public/purecalc/common/worker.h
+++ b/ydb/library/yql/public/purecalc/common/worker.h
@@ -164,6 +164,7 @@ namespace NYql {
private:
void FeedToConsumer();
+ NYql::NUdf::IBoxedValue* GetPushStream() const;
public:
void SetConsumer(THolder<IConsumer<const NKikimr::NUdf::TUnboxedValue*>>) override;
diff --git a/ydb/library/yql/public/purecalc/ut/test_mixed_allocators.cpp b/ydb/library/yql/public/purecalc/ut/test_mixed_allocators.cpp
new file mode 100644
index 00000000000..3038b5e4b2a
--- /dev/null
+++ b/ydb/library/yql/public/purecalc/ut/test_mixed_allocators.cpp
@@ -0,0 +1,139 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <ydb/library/yql/minikql/computation/mkql_computation_node_holders.h>
+#include <ydb/library/yql/minikql/mkql_string_util.h>
+
+#include <ydb/library/yql/public/purecalc/io_specs/protobuf/spec.h>
+#include <ydb/library/yql/public/purecalc/ut/protos/test_structs.pb.h>
+
+using namespace NYql::NPureCalc;
+
+namespace {
+ class TStatelessInputSpec : public TInputSpecBase {
+ public:
+ TStatelessInputSpec()
+ : Schemas_({NYT::TNode::CreateList()
+ .Add("StructType")
+ .Add(NYT::TNode::CreateList()
+ .Add(NYT::TNode::CreateList()
+ .Add("InputValue")
+ .Add(NYT::TNode::CreateList()
+ .Add("DataType")
+ .Add("Utf8")
+ )
+ )
+ )
+ })
+ {};
+
+ const TVector<NYT::TNode>& GetSchemas() const override {
+ return Schemas_;
+ }
+
+ private:
+ const TVector<NYT::TNode> Schemas_;
+ };
+
+ class TStatelessInputConsumer : public IConsumer<const NYql::NUdf::TUnboxedValue&> {
+ public:
+ TStatelessInputConsumer(TWorkerHolder<IPushStreamWorker> worker)
+ : Worker_(std::move(worker))
+ {}
+
+ void OnObject(const NYql::NUdf::TUnboxedValue& value) override {
+ with_lock (Worker_->GetScopedAlloc()) {
+ NYql::NUdf::TUnboxedValue* items = nullptr;
+ NYql::NUdf::TUnboxedValue result = Worker_->GetGraph().GetHolderFactory().CreateDirectArrayHolder(1, items);
+
+ items[0] = value;
+
+ Worker_->Push(std::move(result));
+
+ // Clear graph after each object because
+ // values allocated on another allocator and should be released
+ Worker_->GetGraph().Invalidate();
+ }
+ }
+
+ void OnFinish() override {
+ with_lock(Worker_->GetScopedAlloc()) {
+ Worker_->OnFinish();
+ }
+ }
+
+ private:
+ TWorkerHolder<IPushStreamWorker> Worker_;
+ };
+
+ class TStatelessConsumer : public IConsumer<NPureCalcProto::TStringMessage*> {
+ const TString ExpectedData_;
+ const ui64 ExpectedRows_;
+ ui64 RowId_ = 0;
+
+ public:
+ TStatelessConsumer(const TString& expectedData, ui64 expectedRows)
+ : ExpectedData_(expectedData)
+ , ExpectedRows_(expectedRows)
+ {}
+
+ void OnObject(NPureCalcProto::TStringMessage* message) override {
+ UNIT_ASSERT_VALUES_EQUAL_C(ExpectedData_, message->GetX(), RowId_);
+ RowId_++;
+ }
+
+ void OnFinish() override {
+ UNIT_ASSERT_VALUES_EQUAL(ExpectedRows_, RowId_);
+ }
+ };
+}
+
+template <>
+struct TInputSpecTraits<TStatelessInputSpec> {
+ static constexpr bool IsPartial = false;
+ static constexpr bool SupportPushStreamMode = true;
+
+ using TConsumerType = THolder<IConsumer<const NYql::NUdf::TUnboxedValue&>>;
+
+ static TConsumerType MakeConsumer(const TStatelessInputSpec&, TWorkerHolder<IPushStreamWorker> worker) {
+ return MakeHolder<TStatelessInputConsumer>(std::move(worker));
+ }
+};
+
+Y_UNIT_TEST_SUITE(TestMixedAllocators) {
+ Y_UNIT_TEST(TestPushStream) {
+ const auto targetString = "large string >= 14 bytes";
+ const auto factory = MakeProgramFactory();
+ const auto sql = TStringBuilder() << "SELECT InputValue AS X FROM Input WHERE InputValue = \"" << targetString << "\";";
+
+ const auto program = factory->MakePushStreamProgram(
+ TStatelessInputSpec(),
+ TProtobufOutputSpec<NPureCalcProto::TStringMessage>(),
+ sql
+ );
+
+ const ui64 numberRows = 5;
+ const auto inputConsumer = program->Apply(MakeHolder<TStatelessConsumer>(targetString, numberRows));
+ NKikimr::NMiniKQL::TScopedAlloc alloc(__LOCATION__, NKikimr::TAlignedPagePoolCounters(), true, false);
+
+ const auto pushString = [&](TString inputValue) {
+ NYql::NUdf::TUnboxedValue stringValue;
+ with_lock(alloc) {
+ stringValue = NKikimr::NMiniKQL::MakeString(inputValue);
+ alloc.Ref().LockObject(stringValue);
+ }
+
+ inputConsumer->OnObject(stringValue);
+
+ with_lock(alloc) {
+ alloc.Ref().UnlockObject(stringValue);
+ stringValue.Clear();
+ }
+ };
+
+ for (ui64 i = 0; i < numberRows; ++i) {
+ pushString(targetString);
+ pushString("another large string >= 14 bytes");
+ }
+ inputConsumer->OnFinish();
+ }
+}
diff --git a/ydb/library/yql/public/purecalc/ut/ya.make b/ydb/library/yql/public/purecalc/ut/ya.make
index 87f90a25ccf..6f23dcd7f4a 100644
--- a/ydb/library/yql/public/purecalc/ut/ya.make
+++ b/ydb/library/yql/public/purecalc/ut/ya.make
@@ -12,6 +12,7 @@ SRCS(
test_user_data.cpp
test_eval.cpp
test_pool.cpp
+ test_mixed_allocators.cpp
)
PEERDIR(