Skip to content

Commit 6facbe5

Browse files
committed
[carnot] Add ClickHouse source and export-sink plan operators
1 parent 40a9b2a commit 6facbe5

11 files changed

Lines changed: 5100 additions & 1282 deletions

File tree

src/carnot/plan/operators.cc

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,10 @@ std::unique_ptr<Operator> Operator::FromProto(const planpb::Operator& pb, int64_
8383
return CreateOperator<UDTFSourceOperator>(id, pb.udtf_source_op());
8484
case planpb::EMPTY_SOURCE_OPERATOR:
8585
return CreateOperator<EmptySourceOperator>(id, pb.empty_source_op());
86+
case planpb::CLICKHOUSE_SOURCE_OPERATOR:
87+
return CreateOperator<ClickHouseSourceOperator>(id, pb.clickhouse_source_op());
88+
case planpb::CLICKHOUSE_EXPORT_SINK_OPERATOR:
89+
return CreateOperator<ClickHouseExportSinkOperator>(id, pb.clickhouse_sink_op());
8690
case planpb::OTEL_EXPORT_SINK_OPERATOR:
8791
return CreateOperator<OTelExportSinkOperator>(id, pb.otel_sink_op());
8892
default:
@@ -709,6 +713,67 @@ StatusOr<table_store::schema::Relation> EmptySourceOperator::OutputRelation(
709713
return r;
710714
}
711715

716+
/**
717+
* ClickHouseSourceOperator implementation.
718+
*/
719+
720+
std::string ClickHouseSourceOperator::DebugString() const {
721+
return absl::Substitute(R"(Op:ClickHouseSource(
722+
host=$0
723+
port=$1
724+
username=$2
725+
batch_size=$3
726+
start_time=$4
727+
end_time=$5
728+
timestamp_column=$6
729+
partition_column=$7
730+
)",
731+
pb_.host(), pb_.port(), pb_.username(), pb_.batch_size(),
732+
pb_.start_time(), pb_.end_time(), pb_.timestamp_column(),
733+
pb_.partition_column());
734+
}
735+
736+
Status ClickHouseSourceOperator::Init(const planpb::ClickHouseSourceOperator& pb) {
737+
pb_ = pb;
738+
is_initialized_ = true;
739+
return Status::OK();
740+
}
741+
742+
StatusOr<table_store::schema::Relation> ClickHouseSourceOperator::OutputRelation(
743+
const table_store::schema::Schema&, const PlanState&,
744+
const std::vector<int64_t>& input_ids) const {
745+
DCHECK(is_initialized_) << "Not initialized";
746+
if (!input_ids.empty()) {
747+
return error::InvalidArgument("Source operator cannot have any inputs");
748+
}
749+
table_store::schema::Relation r;
750+
for (int i = 0; i < pb_.column_types_size(); ++i) {
751+
r.AddColumn(static_cast<types::DataType>(pb_.column_types(i)), pb_.column_names(i));
752+
}
753+
return r;
754+
}
755+
756+
/**
757+
* ClickHouse Export Sink Operator Implementation.
758+
*/
759+
760+
Status ClickHouseExportSinkOperator::Init(const planpb::ClickHouseExportSinkOperator& pb) {
761+
pb_ = pb;
762+
is_initialized_ = true;
763+
return Status::OK();
764+
}
765+
766+
StatusOr<table_store::schema::Relation> ClickHouseExportSinkOperator::OutputRelation(
767+
const table_store::schema::Schema&, const PlanState&, const std::vector<int64_t>&) const {
768+
DCHECK(is_initialized_) << "Not initialized";
769+
// There are no outputs.
770+
return table_store::schema::Relation();
771+
}
772+
773+
std::string ClickHouseExportSinkOperator::DebugString() const {
774+
return absl::Substitute("Op:ClickHouseExportSink(table=$0)", pb_.table_name());
775+
}
776+
712777
/**
713778
* OTel Export Sink Operator Implementation.
714779
*/

src/carnot/plan/operators.h

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,69 @@ class EmptySourceOperator : public Operator {
359359
std::vector<int64_t> column_idxs_;
360360
};
361361

362+
class ClickHouseSourceOperator : public Operator {
363+
public:
364+
explicit ClickHouseSourceOperator(int64_t id)
365+
: Operator(id, planpb::CLICKHOUSE_SOURCE_OPERATOR) {}
366+
~ClickHouseSourceOperator() override = default;
367+
368+
StatusOr<table_store::schema::Relation> OutputRelation(
369+
const table_store::schema::Schema& schema, const PlanState& state,
370+
const std::vector<int64_t>& input_ids) const override;
371+
Status Init(const planpb::ClickHouseSourceOperator& pb);
372+
std::string DebugString() const override;
373+
374+
std::string host() const { return pb_.host(); }
375+
int32_t port() const { return pb_.port(); }
376+
std::string username() const { return pb_.username(); }
377+
std::string password() const { return pb_.password(); }
378+
std::string database() const { return pb_.database(); }
379+
std::string query() const { return pb_.query(); }
380+
int32_t batch_size() const { return pb_.batch_size(); }
381+
bool streaming() const { return pb_.streaming(); }
382+
std::vector<std::string> column_names() const {
383+
return std::vector<std::string>(pb_.column_names().begin(), pb_.column_names().end());
384+
}
385+
std::vector<types::DataType> column_types() const {
386+
std::vector<types::DataType> types;
387+
types.reserve(pb_.column_types_size());
388+
for (const auto& type : pb_.column_types()) {
389+
types.push_back(static_cast<types::DataType>(type));
390+
}
391+
return types;
392+
}
393+
std::string timestamp_column() const { return pb_.timestamp_column(); }
394+
std::string partition_column() const { return pb_.partition_column(); }
395+
int64_t start_time() const { return pb_.start_time(); }
396+
int64_t end_time() const { return pb_.end_time(); }
397+
398+
private:
399+
planpb::ClickHouseSourceOperator pb_;
400+
};
401+
402+
class ClickHouseExportSinkOperator : public Operator {
403+
public:
404+
explicit ClickHouseExportSinkOperator(int64_t id)
405+
: Operator(id, planpb::CLICKHOUSE_EXPORT_SINK_OPERATOR) {}
406+
~ClickHouseExportSinkOperator() override = default;
407+
408+
StatusOr<table_store::schema::Relation> OutputRelation(
409+
const table_store::schema::Schema& schema, const PlanState& state,
410+
const std::vector<int64_t>& input_ids) const override;
411+
Status Init(const planpb::ClickHouseExportSinkOperator& pb);
412+
std::string DebugString() const override;
413+
414+
const planpb::ClickHouseConfig& clickhouse_config() const { return pb_.clickhouse_config(); }
415+
const std::string& table_name() const { return pb_.table_name(); }
416+
const ::google::protobuf::RepeatedPtrField<planpb::ClickHouseExportSinkOperator::ColumnMapping>&
417+
column_mappings() const {
418+
return pb_.column_mappings();
419+
}
420+
421+
private:
422+
planpb::ClickHouseExportSinkOperator pb_;
423+
};
424+
362425
class OTelExportSinkOperator : public Operator {
363426
public:
364427
explicit OTelExportSinkOperator(int64_t id) : Operator(id, planpb::OTEL_EXPORT_SINK_OPERATOR) {}

src/carnot/plan/plan_fragment.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,13 @@ Status PlanFragmentWalker::CallWalkFn(const Operator& op) {
9898
case planpb::OperatorType::OTEL_EXPORT_SINK_OPERATOR:
9999
PX_RETURN_IF_ERROR(CallAs<OTelExportSinkOperator>(on_otel_sink_walk_fn_, op));
100100
break;
101+
case planpb::OperatorType::CLICKHOUSE_SOURCE_OPERATOR:
102+
PX_RETURN_IF_ERROR(CallAs<ClickHouseSourceOperator>(on_clickhouse_source_walk_fn_, op));
103+
break;
104+
case planpb::OperatorType::CLICKHOUSE_EXPORT_SINK_OPERATOR:
105+
PX_RETURN_IF_ERROR(
106+
CallAs<ClickHouseExportSinkOperator>(on_clickhouse_export_sink_walk_fn_, op));
107+
break;
101108
default:
102109
LOG(FATAL) << absl::Substitute("Operator does not exist: $0", magic_enum::enum_name(op_type));
103110
return error::InvalidArgument("Operator does not exist: $0", magic_enum::enum_name(op_type));

src/carnot/plan/plan_fragment.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ class PlanFragmentWalker {
7676
using UDTFSourceWalkFn = std::function<Status(const UDTFSourceOperator&)>;
7777
using EmptySourceWalkFn = std::function<Status(const EmptySourceOperator&)>;
7878
using OTelSinkWalkFn = std::function<Status(const OTelExportSinkOperator&)>;
79+
using ClickHouseSourceWalkFn = std::function<Status(const ClickHouseSourceOperator&)>;
80+
using ClickHouseExportSinkWalkFn = std::function<Status(const ClickHouseExportSinkOperator&)>;
7981

8082
/**
8183
* Register callback for when a memory source operator is encountered.
@@ -181,6 +183,17 @@ class PlanFragmentWalker {
181183
on_otel_sink_walk_fn_ = fn;
182184
return *this;
183185
}
186+
187+
PlanFragmentWalker& OnClickHouseSource(const ClickHouseSourceWalkFn& fn) {
188+
on_clickhouse_source_walk_fn_ = fn;
189+
return *this;
190+
}
191+
192+
PlanFragmentWalker& OnClickHouseExportSink(const ClickHouseExportSinkWalkFn& fn) {
193+
on_clickhouse_export_sink_walk_fn_ = fn;
194+
return *this;
195+
}
196+
184197
/**
185198
* Perform a walk of the plan fragment operators in a topologically-sorted order.
186199
* @param plan_fragment The plan fragment to walk.
@@ -206,6 +219,8 @@ class PlanFragmentWalker {
206219
UDTFSourceWalkFn on_udtf_source_walk_fn_;
207220
EmptySourceWalkFn on_empty_source_walk_fn_;
208221
OTelSinkWalkFn on_otel_sink_walk_fn_;
222+
ClickHouseSourceWalkFn on_clickhouse_source_walk_fn_;
223+
ClickHouseExportSinkWalkFn on_clickhouse_export_sink_walk_fn_;
209224
};
210225

211226
} // namespace plan

0 commit comments

Comments
 (0)