duckdb 0.5.1-dev178.0 → 0.5.1-dev181.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/duckdb.cpp +79 -52
- package/src/duckdb.hpp +4 -2
- package/src/parquet-amalgamation.cpp +37435 -37435
package/package.json
CHANGED
package/src/duckdb.cpp
CHANGED
|
@@ -63253,6 +63253,16 @@ bool DistinctAggregateData::IsDistinct(idx_t index) const {
|
|
|
63253
63253
|
|
|
63254
63254
|
|
|
63255
63255
|
|
|
63256
|
+
//===----------------------------------------------------------------------===//
|
|
63257
|
+
// DuckDB
|
|
63258
|
+
//
|
|
63259
|
+
// duckdb/parallel/base_pipeline_event.hpp
|
|
63260
|
+
//
|
|
63261
|
+
//
|
|
63262
|
+
//===----------------------------------------------------------------------===//
|
|
63263
|
+
|
|
63264
|
+
|
|
63265
|
+
|
|
63256
63266
|
//===----------------------------------------------------------------------===//
|
|
63257
63267
|
// DuckDB
|
|
63258
63268
|
//
|
|
@@ -63326,6 +63336,22 @@ protected:
|
|
|
63326
63336
|
|
|
63327
63337
|
|
|
63328
63338
|
|
|
63339
|
+
namespace duckdb {
|
|
63340
|
+
|
|
63341
|
+
//! A BasePipelineEvent is used as the basis of any event that belongs to a specific pipeline
|
|
63342
|
+
class BasePipelineEvent : public Event {
|
|
63343
|
+
public:
|
|
63344
|
+
BasePipelineEvent(shared_ptr<Pipeline> pipeline);
|
|
63345
|
+
BasePipelineEvent(Pipeline &pipeline);
|
|
63346
|
+
|
|
63347
|
+
//! The pipeline that this event belongs to
|
|
63348
|
+
shared_ptr<Pipeline> pipeline;
|
|
63349
|
+
};
|
|
63350
|
+
|
|
63351
|
+
} // namespace duckdb
|
|
63352
|
+
|
|
63353
|
+
|
|
63354
|
+
|
|
63329
63355
|
namespace duckdb {
|
|
63330
63356
|
|
|
63331
63357
|
PhysicalHashAggregate::PhysicalHashAggregate(ClientContext &context, vector<LogicalType> types,
|
|
@@ -63482,16 +63508,15 @@ void PhysicalHashAggregate::Combine(ExecutionContext &context, GlobalSinkState &
|
|
|
63482
63508
|
}
|
|
63483
63509
|
}
|
|
63484
63510
|
|
|
63485
|
-
class HashAggregateFinalizeEvent : public
|
|
63511
|
+
class HashAggregateFinalizeEvent : public BasePipelineEvent {
|
|
63486
63512
|
public:
|
|
63487
63513
|
HashAggregateFinalizeEvent(const PhysicalHashAggregate &op_p, HashAggregateGlobalState &gstate_p,
|
|
63488
63514
|
Pipeline *pipeline_p)
|
|
63489
|
-
:
|
|
63515
|
+
: BasePipelineEvent(*pipeline_p), op(op_p), gstate(gstate_p) {
|
|
63490
63516
|
}
|
|
63491
63517
|
|
|
63492
63518
|
const PhysicalHashAggregate &op;
|
|
63493
63519
|
HashAggregateGlobalState &gstate;
|
|
63494
|
-
Pipeline *pipeline;
|
|
63495
63520
|
|
|
63496
63521
|
public:
|
|
63497
63522
|
void Schedule() override {
|
|
@@ -64753,15 +64778,14 @@ private:
|
|
|
64753
64778
|
};
|
|
64754
64779
|
|
|
64755
64780
|
// TODO: Create tasks and run these in parallel instead of doing this all in Schedule, single threaded
|
|
64756
|
-
class DistinctAggregateFinalizeEvent : public
|
|
64781
|
+
class DistinctAggregateFinalizeEvent : public BasePipelineEvent {
|
|
64757
64782
|
public:
|
|
64758
64783
|
DistinctAggregateFinalizeEvent(const PhysicalUngroupedAggregate &op_p, UngroupedAggregateGlobalState &gstate_p,
|
|
64759
|
-
Pipeline
|
|
64760
|
-
:
|
|
64784
|
+
Pipeline &pipeline_p, ClientContext &context)
|
|
64785
|
+
: BasePipelineEvent(pipeline_p), op(op_p), gstate(gstate_p), context(context) {
|
|
64761
64786
|
}
|
|
64762
64787
|
const PhysicalUngroupedAggregate &op;
|
|
64763
64788
|
UngroupedAggregateGlobalState &gstate;
|
|
64764
|
-
Pipeline *pipeline;
|
|
64765
64789
|
ClientContext &context;
|
|
64766
64790
|
|
|
64767
64791
|
public:
|
|
@@ -64774,16 +64798,15 @@ public:
|
|
|
64774
64798
|
}
|
|
64775
64799
|
};
|
|
64776
64800
|
|
|
64777
|
-
class DistinctCombineFinalizeEvent : public
|
|
64801
|
+
class DistinctCombineFinalizeEvent : public BasePipelineEvent {
|
|
64778
64802
|
public:
|
|
64779
64803
|
DistinctCombineFinalizeEvent(const PhysicalUngroupedAggregate &op_p, UngroupedAggregateGlobalState &gstate_p,
|
|
64780
|
-
Pipeline
|
|
64781
|
-
:
|
|
64804
|
+
Pipeline &pipeline_p, ClientContext &client)
|
|
64805
|
+
: BasePipelineEvent(pipeline_p), op(op_p), gstate(gstate_p), client(client) {
|
|
64782
64806
|
}
|
|
64783
64807
|
|
|
64784
64808
|
const PhysicalUngroupedAggregate &op;
|
|
64785
64809
|
UngroupedAggregateGlobalState &gstate;
|
|
64786
|
-
Pipeline *pipeline;
|
|
64787
64810
|
ClientContext &client;
|
|
64788
64811
|
|
|
64789
64812
|
public:
|
|
@@ -64799,7 +64822,7 @@ public:
|
|
|
64799
64822
|
SetTasks(move(tasks));
|
|
64800
64823
|
|
|
64801
64824
|
//! Now that all tables are combined, it's time to do the distinct aggregations
|
|
64802
|
-
auto new_event = make_shared<DistinctAggregateFinalizeEvent>(op, gstate, pipeline, client);
|
|
64825
|
+
auto new_event = make_shared<DistinctAggregateFinalizeEvent>(op, gstate, *pipeline, client);
|
|
64803
64826
|
this->InsertEvent(move(new_event));
|
|
64804
64827
|
}
|
|
64805
64828
|
};
|
|
@@ -64828,12 +64851,12 @@ SinkFinalizeType PhysicalUngroupedAggregate::FinalizeDistinct(Pipeline &pipeline
|
|
|
64828
64851
|
}
|
|
64829
64852
|
}
|
|
64830
64853
|
if (any_partitioned) {
|
|
64831
|
-
auto new_event = make_shared<DistinctCombineFinalizeEvent>(*this, gstate,
|
|
64854
|
+
auto new_event = make_shared<DistinctCombineFinalizeEvent>(*this, gstate, pipeline, context);
|
|
64832
64855
|
event.InsertEvent(move(new_event));
|
|
64833
64856
|
} else {
|
|
64834
64857
|
//! Hashtables aren't partitioned, they dont need to be joined first
|
|
64835
64858
|
//! So we can compute the aggregate already
|
|
64836
|
-
auto new_event = make_shared<DistinctAggregateFinalizeEvent>(*this, gstate,
|
|
64859
|
+
auto new_event = make_shared<DistinctAggregateFinalizeEvent>(*this, gstate, pipeline, context);
|
|
64837
64860
|
event.InsertEvent(move(new_event));
|
|
64838
64861
|
}
|
|
64839
64862
|
return SinkFinalizeType::READY;
|
|
@@ -66579,19 +66602,18 @@ private:
|
|
|
66579
66602
|
WindowGlobalHashGroup &hash_group;
|
|
66580
66603
|
};
|
|
66581
66604
|
|
|
66582
|
-
class WindowMergeEvent : public
|
|
66605
|
+
class WindowMergeEvent : public BasePipelineEvent {
|
|
66583
66606
|
public:
|
|
66584
66607
|
WindowMergeEvent(WindowGlobalSinkState &gstate_p, Pipeline &pipeline_p, WindowGlobalHashGroup &hash_group_p)
|
|
66585
|
-
:
|
|
66608
|
+
: BasePipelineEvent(pipeline_p), gstate(gstate_p), hash_group(hash_group_p) {
|
|
66586
66609
|
}
|
|
66587
66610
|
|
|
66588
66611
|
WindowGlobalSinkState &gstate;
|
|
66589
|
-
Pipeline &pipeline;
|
|
66590
66612
|
WindowGlobalHashGroup &hash_group;
|
|
66591
66613
|
|
|
66592
66614
|
public:
|
|
66593
66615
|
void Schedule() override {
|
|
66594
|
-
auto &context = pipeline
|
|
66616
|
+
auto &context = pipeline->GetClientContext();
|
|
66595
66617
|
|
|
66596
66618
|
// Schedule tasks equal to the number of threads, which will each merge multiple partitions
|
|
66597
66619
|
auto &ts = TaskScheduler::GetScheduler(context);
|
|
@@ -66606,7 +66628,7 @@ public:
|
|
|
66606
66628
|
|
|
66607
66629
|
void FinishEvent() override {
|
|
66608
66630
|
hash_group.global_sort->CompleteMergeRound(true);
|
|
66609
|
-
CreateMergeTasks(pipeline, *this, gstate, hash_group);
|
|
66631
|
+
CreateMergeTasks(*pipeline, *this, gstate, hash_group);
|
|
66610
66632
|
}
|
|
66611
66633
|
|
|
66612
66634
|
static void CreateMergeTasks(Pipeline &pipeline, Event &event, WindowGlobalSinkState &state,
|
|
@@ -70941,18 +70963,17 @@ private:
|
|
|
70941
70963
|
bool parallel;
|
|
70942
70964
|
};
|
|
70943
70965
|
|
|
70944
|
-
class HashJoinFinalizeEvent : public
|
|
70966
|
+
class HashJoinFinalizeEvent : public BasePipelineEvent {
|
|
70945
70967
|
public:
|
|
70946
70968
|
HashJoinFinalizeEvent(Pipeline &pipeline_p, HashJoinGlobalSinkState &sink)
|
|
70947
|
-
:
|
|
70969
|
+
: BasePipelineEvent(pipeline_p), sink(sink) {
|
|
70948
70970
|
}
|
|
70949
70971
|
|
|
70950
|
-
Pipeline &pipeline;
|
|
70951
70972
|
HashJoinGlobalSinkState &sink;
|
|
70952
70973
|
|
|
70953
70974
|
public:
|
|
70954
70975
|
void Schedule() override {
|
|
70955
|
-
auto &context = pipeline
|
|
70976
|
+
auto &context = pipeline->GetClientContext();
|
|
70956
70977
|
auto parallel_construct_count =
|
|
70957
70978
|
context.config.verify_parallelism ? STANDARD_VECTOR_SIZE : PARALLEL_CONSTRUCT_COUNT;
|
|
70958
70979
|
|
|
@@ -71019,20 +71040,19 @@ private:
|
|
|
71019
71040
|
JoinHashTable &local_ht;
|
|
71020
71041
|
};
|
|
71021
71042
|
|
|
71022
|
-
class HashJoinPartitionEvent : public
|
|
71043
|
+
class HashJoinPartitionEvent : public BasePipelineEvent {
|
|
71023
71044
|
public:
|
|
71024
71045
|
HashJoinPartitionEvent(Pipeline &pipeline_p, HashJoinGlobalSinkState &sink,
|
|
71025
71046
|
vector<unique_ptr<JoinHashTable>> &local_hts)
|
|
71026
|
-
:
|
|
71047
|
+
: BasePipelineEvent(pipeline_p), sink(sink), local_hts(local_hts) {
|
|
71027
71048
|
}
|
|
71028
71049
|
|
|
71029
|
-
Pipeline &pipeline;
|
|
71030
71050
|
HashJoinGlobalSinkState &sink;
|
|
71031
71051
|
vector<unique_ptr<JoinHashTable>> &local_hts;
|
|
71032
71052
|
|
|
71033
71053
|
public:
|
|
71034
71054
|
void Schedule() override {
|
|
71035
|
-
auto &context = pipeline
|
|
71055
|
+
auto &context = pipeline->GetClientContext();
|
|
71036
71056
|
vector<unique_ptr<Task>> partition_tasks;
|
|
71037
71057
|
partition_tasks.reserve(local_hts.size());
|
|
71038
71058
|
for (auto &local_ht : local_hts) {
|
|
@@ -71045,7 +71065,7 @@ public:
|
|
|
71045
71065
|
void FinishEvent() override {
|
|
71046
71066
|
local_hts.clear();
|
|
71047
71067
|
sink.hash_table->PrepareExternalFinalize();
|
|
71048
|
-
sink.ScheduleFinalize(pipeline, *this);
|
|
71068
|
+
sink.ScheduleFinalize(*pipeline, *this);
|
|
71049
71069
|
}
|
|
71050
71070
|
};
|
|
71051
71071
|
|
|
@@ -74749,21 +74769,20 @@ private:
|
|
|
74749
74769
|
GlobalSortedTable &table;
|
|
74750
74770
|
};
|
|
74751
74771
|
|
|
74752
|
-
class RangeJoinMergeEvent : public
|
|
74772
|
+
class RangeJoinMergeEvent : public BasePipelineEvent {
|
|
74753
74773
|
public:
|
|
74754
74774
|
using GlobalSortedTable = PhysicalRangeJoin::GlobalSortedTable;
|
|
74755
74775
|
|
|
74756
74776
|
public:
|
|
74757
74777
|
RangeJoinMergeEvent(GlobalSortedTable &table_p, Pipeline &pipeline_p)
|
|
74758
|
-
:
|
|
74778
|
+
: BasePipelineEvent(pipeline_p), table(table_p) {
|
|
74759
74779
|
}
|
|
74760
74780
|
|
|
74761
74781
|
GlobalSortedTable &table;
|
|
74762
|
-
Pipeline &pipeline;
|
|
74763
74782
|
|
|
74764
74783
|
public:
|
|
74765
74784
|
void Schedule() override {
|
|
74766
|
-
auto &context = pipeline
|
|
74785
|
+
auto &context = pipeline->GetClientContext();
|
|
74767
74786
|
|
|
74768
74787
|
// Schedule tasks equal to the number of threads, which will each merge multiple partitions
|
|
74769
74788
|
auto &ts = TaskScheduler::GetScheduler(context);
|
|
@@ -74782,7 +74801,7 @@ public:
|
|
|
74782
74801
|
global_sort_state.CompleteMergeRound(true);
|
|
74783
74802
|
if (global_sort_state.sorted_blocks.size() > 1) {
|
|
74784
74803
|
// Multiple blocks remaining: Schedule the next round
|
|
74785
|
-
table.ScheduleMergeTasks(pipeline, *this);
|
|
74804
|
+
table.ScheduleMergeTasks(*pipeline, *this);
|
|
74786
74805
|
}
|
|
74787
74806
|
}
|
|
74788
74807
|
};
|
|
@@ -75170,18 +75189,17 @@ private:
|
|
|
75170
75189
|
OrderGlobalState &state;
|
|
75171
75190
|
};
|
|
75172
75191
|
|
|
75173
|
-
class OrderMergeEvent : public
|
|
75192
|
+
class OrderMergeEvent : public BasePipelineEvent {
|
|
75174
75193
|
public:
|
|
75175
75194
|
OrderMergeEvent(OrderGlobalState &gstate_p, Pipeline &pipeline_p)
|
|
75176
|
-
:
|
|
75195
|
+
: BasePipelineEvent(pipeline_p), gstate(gstate_p) {
|
|
75177
75196
|
}
|
|
75178
75197
|
|
|
75179
75198
|
OrderGlobalState &gstate;
|
|
75180
|
-
Pipeline &pipeline;
|
|
75181
75199
|
|
|
75182
75200
|
public:
|
|
75183
75201
|
void Schedule() override {
|
|
75184
|
-
auto &context = pipeline
|
|
75202
|
+
auto &context = pipeline->GetClientContext();
|
|
75185
75203
|
|
|
75186
75204
|
// Schedule tasks equal to the number of threads, which will each merge multiple partitions
|
|
75187
75205
|
auto &ts = TaskScheduler::GetScheduler(context);
|
|
@@ -75200,7 +75218,7 @@ public:
|
|
|
75200
75218
|
global_sort_state.CompleteMergeRound();
|
|
75201
75219
|
if (global_sort_state.sorted_blocks.size() > 1) {
|
|
75202
75220
|
// Multiple blocks remaining: Schedule the next round
|
|
75203
|
-
PhysicalOrder::ScheduleMergeTasks(pipeline, *this, gstate);
|
|
75221
|
+
PhysicalOrder::ScheduleMergeTasks(*pipeline, *this, gstate);
|
|
75204
75222
|
}
|
|
75205
75223
|
}
|
|
75206
75224
|
};
|
|
@@ -152672,6 +152690,19 @@ unique_ptr<LogicalOperator> TopN::Optimize(unique_ptr<LogicalOperator> op) {
|
|
|
152672
152690
|
} // namespace duckdb
|
|
152673
152691
|
|
|
152674
152692
|
|
|
152693
|
+
namespace duckdb {
|
|
152694
|
+
|
|
152695
|
+
BasePipelineEvent::BasePipelineEvent(shared_ptr<Pipeline> pipeline_p)
|
|
152696
|
+
: Event(pipeline_p->executor), pipeline(move(pipeline_p)) {
|
|
152697
|
+
}
|
|
152698
|
+
|
|
152699
|
+
BasePipelineEvent::BasePipelineEvent(Pipeline &pipeline_p)
|
|
152700
|
+
: Event(pipeline_p.executor), pipeline(pipeline_p.shared_from_this()) {
|
|
152701
|
+
}
|
|
152702
|
+
|
|
152703
|
+
} // namespace duckdb
|
|
152704
|
+
|
|
152705
|
+
|
|
152675
152706
|
|
|
152676
152707
|
|
|
152677
152708
|
|
|
@@ -152791,16 +152822,13 @@ public:
|
|
|
152791
152822
|
|
|
152792
152823
|
|
|
152793
152824
|
|
|
152794
|
-
|
|
152795
152825
|
namespace duckdb {
|
|
152796
152826
|
|
|
152797
|
-
|
|
152827
|
+
//! A PipelineEvent is responsible for scheduling a pipeline
|
|
152828
|
+
class PipelineEvent : public BasePipelineEvent {
|
|
152798
152829
|
public:
|
|
152799
152830
|
PipelineEvent(shared_ptr<Pipeline> pipeline);
|
|
152800
152831
|
|
|
152801
|
-
//! The pipeline that this event belongs to
|
|
152802
|
-
shared_ptr<Pipeline> pipeline;
|
|
152803
|
-
|
|
152804
152832
|
public:
|
|
152805
152833
|
void Schedule() override;
|
|
152806
152834
|
void FinishEvent() override;
|
|
@@ -152928,17 +152956,13 @@ private:
|
|
|
152928
152956
|
|
|
152929
152957
|
|
|
152930
152958
|
|
|
152931
|
-
|
|
152932
152959
|
namespace duckdb {
|
|
152933
152960
|
class Executor;
|
|
152934
152961
|
|
|
152935
|
-
class PipelineFinishEvent : public
|
|
152962
|
+
class PipelineFinishEvent : public BasePipelineEvent {
|
|
152936
152963
|
public:
|
|
152937
152964
|
PipelineFinishEvent(shared_ptr<Pipeline> pipeline);
|
|
152938
152965
|
|
|
152939
|
-
//! The pipeline that this event belongs to
|
|
152940
|
-
shared_ptr<Pipeline> pipeline;
|
|
152941
|
-
|
|
152942
152966
|
public:
|
|
152943
152967
|
void Schedule() override;
|
|
152944
152968
|
void FinishEvent() override;
|
|
@@ -152965,6 +152989,9 @@ Executor &Executor::Get(ClientContext &context) {
|
|
|
152965
152989
|
|
|
152966
152990
|
void Executor::AddEvent(shared_ptr<Event> event) {
|
|
152967
152991
|
lock_guard<mutex> elock(executor_lock);
|
|
152992
|
+
if (cancelled) {
|
|
152993
|
+
return;
|
|
152994
|
+
}
|
|
152968
152995
|
events.push_back(move(event));
|
|
152969
152996
|
}
|
|
152970
152997
|
|
|
@@ -153268,6 +153295,7 @@ void Executor::CancelTasks() {
|
|
|
153268
153295
|
vector<weak_ptr<Pipeline>> weak_references;
|
|
153269
153296
|
{
|
|
153270
153297
|
lock_guard<mutex> elock(executor_lock);
|
|
153298
|
+
cancelled = true;
|
|
153271
153299
|
weak_references.reserve(pipelines.size());
|
|
153272
153300
|
for (auto &pipeline : pipelines) {
|
|
153273
153301
|
weak_references.push_back(weak_ptr<Pipeline>(pipeline));
|
|
@@ -153356,6 +153384,7 @@ PendingExecutionResult Executor::ExecuteTask() {
|
|
|
153356
153384
|
void Executor::Reset() {
|
|
153357
153385
|
lock_guard<mutex> elock(executor_lock);
|
|
153358
153386
|
physical_plan = nullptr;
|
|
153387
|
+
cancelled = false;
|
|
153359
153388
|
owned_plan.reset();
|
|
153360
153389
|
root_executor.reset();
|
|
153361
153390
|
root_pipelines.clear();
|
|
@@ -153790,8 +153819,7 @@ void PipelineCompleteEvent::FinalizeFinish() {
|
|
|
153790
153819
|
|
|
153791
153820
|
namespace duckdb {
|
|
153792
153821
|
|
|
153793
|
-
PipelineEvent::PipelineEvent(shared_ptr<Pipeline> pipeline_p)
|
|
153794
|
-
: Event(pipeline_p->executor), pipeline(move(pipeline_p)) {
|
|
153822
|
+
PipelineEvent::PipelineEvent(shared_ptr<Pipeline> pipeline_p) : BasePipelineEvent(move(pipeline_p)) {
|
|
153795
153823
|
}
|
|
153796
153824
|
|
|
153797
153825
|
void PipelineEvent::Schedule() {
|
|
@@ -154180,8 +154208,7 @@ void PipelineExecutor::EndOperator(PhysicalOperator *op, DataChunk *chunk) {
|
|
|
154180
154208
|
|
|
154181
154209
|
namespace duckdb {
|
|
154182
154210
|
|
|
154183
|
-
PipelineFinishEvent::PipelineFinishEvent(shared_ptr<Pipeline> pipeline_p)
|
|
154184
|
-
: Event(pipeline_p->executor), pipeline(move(pipeline_p)) {
|
|
154211
|
+
PipelineFinishEvent::PipelineFinishEvent(shared_ptr<Pipeline> pipeline_p) : BasePipelineEvent(move(pipeline_p)) {
|
|
154185
154212
|
}
|
|
154186
154213
|
|
|
154187
154214
|
void PipelineFinishEvent::Schedule() {
|
package/src/duckdb.hpp
CHANGED
|
@@ -11,8 +11,8 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
|
|
11
11
|
#pragma once
|
|
12
12
|
#define DUCKDB_AMALGAMATION 1
|
|
13
13
|
#define DUCKDB_AMALGAMATION_EXTENDED 1
|
|
14
|
-
#define DUCKDB_SOURCE_ID "
|
|
15
|
-
#define DUCKDB_VERSION "v0.5.1-
|
|
14
|
+
#define DUCKDB_SOURCE_ID "548692357"
|
|
15
|
+
#define DUCKDB_VERSION "v0.5.1-dev181"
|
|
16
16
|
//===----------------------------------------------------------------------===//
|
|
17
17
|
// DuckDB
|
|
18
18
|
//
|
|
@@ -13034,6 +13034,8 @@ private:
|
|
|
13034
13034
|
atomic<idx_t> completed_pipelines;
|
|
13035
13035
|
//! The total amount of pipelines in the query
|
|
13036
13036
|
idx_t total_pipelines;
|
|
13037
|
+
//! Whether or not execution is cancelled
|
|
13038
|
+
bool cancelled;
|
|
13037
13039
|
|
|
13038
13040
|
//! The adjacent union pipelines of each pipeline
|
|
13039
13041
|
//! Union pipelines have the same sink, but can be run concurrently along with this pipeline
|