Skip to content

Commit e3b0810

Browse files
authored
Merge branch 'main' into main
2 parents 39a973a + 474f76b commit e3b0810

29 files changed

Lines changed: 627 additions & 111 deletions

src/paimon/common/data/blob.cpp

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,19 +33,6 @@ namespace paimon {
3333

3434
class MemoryPool;
3535

36-
Result<std::unique_ptr<Blob>> Blob::FromPath(const std::string& path) {
37-
return FromPath(path, /*offset=*/0, /*length=*/-1);
38-
}
39-
40-
Result<std::unique_ptr<Blob>> Blob::FromPath(const std::string& path, int64_t offset,
41-
int64_t length) {
42-
PAIMON_ASSIGN_OR_RAISE(std::string normalized_path, PathUtil::NormalizePath(path));
43-
PAIMON_ASSIGN_OR_RAISE(std::unique_ptr<BlobDescriptor> descriptor,
44-
BlobDescriptor::Create(normalized_path, offset, length));
45-
auto impl = std::make_unique<Blob::Impl>(std::move(descriptor), descriptor->Uri());
46-
return std::unique_ptr<Blob>(new Blob(std::move(impl)));
47-
}
48-
4936
class Blob::Impl {
5037
public:
5138
Impl(std::unique_ptr<BlobDescriptor>&& descriptor, const std::string& uri)
@@ -68,6 +55,19 @@ class Blob::Impl {
6855
std::string uri_;
6956
};
7057

58+
Result<std::unique_ptr<Blob>> Blob::FromPath(const std::string& path) {
59+
return FromPath(path, /*offset=*/0, /*length=*/-1);
60+
}
61+
62+
Result<std::unique_ptr<Blob>> Blob::FromPath(const std::string& path, int64_t offset,
63+
int64_t length) {
64+
PAIMON_ASSIGN_OR_RAISE(std::string normalized_path, PathUtil::NormalizePath(path));
65+
PAIMON_ASSIGN_OR_RAISE(std::unique_ptr<BlobDescriptor> descriptor,
66+
BlobDescriptor::Create(normalized_path, offset, length));
67+
auto impl = std::make_unique<Blob::Impl>(std::move(descriptor), descriptor->Uri());
68+
return std::unique_ptr<Blob>(new Blob(std::move(impl)));
69+
}
70+
7171
Blob::Blob(std::unique_ptr<Impl>&& impl) : impl_(std::move(impl)) {}
7272
Blob::~Blob() = default;
7373

src/paimon/common/memory/memory_pool.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ void* MemoryPoolImpl::Malloc(uint64_t size, uint64_t alignment) {
5555
return memptr;
5656
}
5757

58-
void* MemoryPoolImpl::Realloc(void* p, size_t old_size, size_t new_size, size_t alignment) {
58+
void* MemoryPoolImpl::Realloc(void* p, size_t old_size, size_t new_size, uint64_t alignment) {
5959
if (alignment == 0) {
6060
void* memptr = ::realloc(p, new_size);
6161
total_allocated_size.fetch_add(new_size - old_size);

src/paimon/core/deletionvectors/deletion_vectors_index_file_test.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ TEST(DeletionVectorsIndexFileTest, Basic) {
3636
FileSystemFactory::Get("local", dir->Str(), {}));
3737
auto path_factory = std::make_shared<MockIndexPathFactory>(dir->Str());
3838
auto pool = GetDefaultPool();
39-
DeletionVectorsIndexFile index_file(fs, path_factory, /*bitmap64=*/false, pool);
39+
auto index_file =
40+
std::make_shared<DeletionVectorsIndexFile>(fs, path_factory, /*bitmap64=*/false, pool);
4041

4142
std::map<std::string, std::shared_ptr<DeletionVector>> input;
4243
RoaringBitmap32 roaring_1;
@@ -50,15 +51,18 @@ TEST(DeletionVectorsIndexFileTest, Basic) {
5051
}
5152
input["dv2"] = std::make_shared<BitmapDeletionVector>(roaring_2);
5253

53-
ASSERT_FALSE(index_file.Bitmap64());
54-
ASSERT_OK_AND_ASSIGN(auto meta, index_file.WriteSingleFile(input));
54+
ASSERT_FALSE(index_file->Bitmap64());
55+
ASSERT_OK_AND_ASSIGN(auto meta, index_file->WriteSingleFile(input));
5556
ASSERT_GT(meta->FileSize(), 0);
57+
ASSERT_OK_AND_ASSIGN(auto size, index_file->FileSize(meta));
58+
ASSERT_EQ(meta->FileSize(), size);
5659
ASSERT_EQ(meta->IndexType(), DeletionVectorsIndexFile::DELETION_VECTORS_INDEX);
5760
ASSERT_EQ(meta->FileName(), "index-0");
61+
ASSERT_FALSE(index_file->IsExternalPath());
5862
ASSERT_EQ(meta->ExternalPath(), std::nullopt);
5963

6064
// Round trip: write then read all deletion vectors from index file.
61-
ASSERT_OK_AND_ASSIGN(auto read_back, index_file.ReadAllDeletionVectors(meta));
65+
ASSERT_OK_AND_ASSIGN(auto read_back, index_file->ReadAllDeletionVectors(meta));
6266
ASSERT_EQ(read_back.size(), input.size());
6367
ASSERT_EQ(read_back.at("dv1")->GetCardinality(), 10);
6468
ASSERT_EQ(read_back.at("dv2")->GetCardinality(), 10);

src/paimon/core/global_index/global_index_write_task.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ Result<std::unique_ptr<BatchReader>> CreateBatchReader(
7979
const std::shared_ptr<MemoryPool>& pool) {
8080
ReadContextBuilder read_context_builder(table_path);
8181
read_context_builder.SetOptions(core_options.ToMap())
82+
.WithFileSystem(core_options.GetFileSystem())
8283
.EnablePrefetch(true)
8384
.WithMemoryPool(pool)
8485
.SetReadSchema({field_name});

src/paimon/core/mergetree/compact/aggregate/field_listagg_agg.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ class FieldListaggAgg : public FieldAggregator {
7979
new_result.append(in_str);
8080
result_ = std::move(new_result);
8181
}
82-
return std::string_view(result_);
82+
return std::string_view{result_};
8383
}
8484

8585
private:

src/paimon/core/mergetree/compact/lookup_merge_tree_compact_rewriter.cpp

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -65,21 +65,23 @@ LookupMergeTreeCompactRewriter<T>::Create(
6565
auto write_schema = SpecialFields::CompleteSequenceAndValueKindField(data_schema);
6666

6767
// TODO(xinyu.lxy): set executor
68-
// TODO(xinyu.lxy): temporarily disabled pre-buffer for parquet, which may cause high memory
69-
// usage during compaction. Will fix via parquet format refactor.
7068
ReadContextBuilder read_context_builder(path_factory_cache->RootPath());
7169
read_context_builder.SetOptions(options.ToMap())
70+
.WithFileSystem(options.GetFileSystem())
7271
.EnablePrefetch(true)
7372
.SetPrefetchMaxParallelNum(1)
7473
.SetPrefetchBatchCount(3)
75-
.WithMemoryPool(pool)
76-
.AddOption("parquet.read.enable-pre-buffer", "false");
74+
.WithMemoryPool(pool);
7775
PAIMON_ASSIGN_OR_RAISE(std::shared_ptr<ReadContext> read_context,
7876
read_context_builder.Finish());
79-
80-
PAIMON_ASSIGN_OR_RAISE(
81-
std::shared_ptr<InternalReadContext> internal_context,
82-
InternalReadContext::Create(read_context, table_schema, options.ToMap()));
77+
// TODO(xinyu.lxy): temporarily disabled pre-buffer for parquet, which may cause high memory
78+
// usage during compaction. Will fix via parquet format refactor.
79+
auto new_options = options.ToMap();
80+
if (new_options.find("parquet.read.enable-pre-buffer") == new_options.end()) {
81+
new_options["parquet.read.enable-pre-buffer"] = "false";
82+
}
83+
PAIMON_ASSIGN_OR_RAISE(std::shared_ptr<InternalReadContext> internal_context,
84+
InternalReadContext::Create(read_context, table_schema, new_options));
8385
PAIMON_ASSIGN_OR_RAISE(
8486
std::shared_ptr<FileStorePathFactory> path_factory,
8587
path_factory_cache->GetOrCreatePathFactory(options.GetFileFormat()->Identifier()));

src/paimon/core/mergetree/compact/merge_tree_compact_rewriter.cpp

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -71,21 +71,23 @@ Result<std::unique_ptr<MergeTreeCompactRewriter>> MergeTreeCompactRewriter::Crea
7171
auto write_schema = SpecialFields::CompleteSequenceAndValueKindField(data_schema);
7272

7373
// TODO(xinyu.lxy): set executor
74-
// TODO(xinyu.lxy): temporarily disabled pre-buffer for parquet, which may cause high memory
75-
// usage during compaction. Will fix via parquet format refactor.
7674
ReadContextBuilder read_context_builder(path_factory_cache->RootPath());
7775
read_context_builder.SetOptions(options.ToMap())
76+
.WithFileSystem(options.GetFileSystem())
7877
.EnablePrefetch(true)
7978
.SetPrefetchMaxParallelNum(1)
8079
.SetPrefetchBatchCount(3)
81-
.WithMemoryPool(pool)
82-
.AddOption("parquet.read.enable-pre-buffer", "false");
80+
.WithMemoryPool(pool);
8381
PAIMON_ASSIGN_OR_RAISE(std::shared_ptr<ReadContext> read_context,
8482
read_context_builder.Finish());
85-
86-
PAIMON_ASSIGN_OR_RAISE(
87-
std::shared_ptr<InternalReadContext> internal_context,
88-
InternalReadContext::Create(read_context, table_schema, options.ToMap()));
83+
// TODO(xinyu.lxy): temporarily disabled pre-buffer for parquet, which may cause high memory
84+
// usage during compaction. Will fix via parquet format refactor.
85+
auto new_options = options.ToMap();
86+
if (new_options.find("parquet.read.enable-pre-buffer") == new_options.end()) {
87+
new_options["parquet.read.enable-pre-buffer"] = "false";
88+
}
89+
PAIMON_ASSIGN_OR_RAISE(std::shared_ptr<InternalReadContext> internal_context,
90+
InternalReadContext::Create(read_context, table_schema, new_options));
8991
PAIMON_ASSIGN_OR_RAISE(
9092
std::shared_ptr<FileStorePathFactory> path_factory,
9193
path_factory_cache->GetOrCreatePathFactory(options.GetFileFormat()->Identifier()));

src/paimon/core/mergetree/compact/merge_tree_compact_rewriter_test.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,38 @@ TEST_F(MergeTreeCompactRewriterTest, TestSimple) {
165165
CheckResult(compact_file_name, fs, table_schema, expected_array);
166166
}
167167

168+
TEST_F(MergeTreeCompactRewriterTest, TestCancel) {
169+
std::string origin_table_path = GetDataDir() + "/orc/pk_table_scan_and_read_mor.db/";
170+
auto table_dir = UniqueTestDirectory::Create("local");
171+
ASSERT_TRUE(TestUtil::CopyDirectory(origin_table_path, table_dir->Str()));
172+
std::string table_path = table_dir->Str() + "/pk_table_scan_and_read_mor";
173+
auto fs = table_dir->GetFileSystem();
174+
175+
SchemaManager schema_manager(fs, table_path);
176+
ASSERT_OK_AND_ASSIGN(auto table_schema, schema_manager.ReadSchema(0));
177+
ASSERT_OK_AND_ASSIGN(auto options, CoreOptions::FromMap(table_schema->Options()));
178+
auto arrow_schema = DataField::ConvertDataFieldsToArrowSchema(table_schema->Fields());
179+
auto dv_factory = [](const std::string&) -> Result<std::shared_ptr<DeletionVector>> {
180+
return std::shared_ptr<DeletionVector>();
181+
};
182+
auto cancellation_controller = std::make_shared<CancellationController>();
183+
auto path_factory_cache =
184+
std::make_shared<FileStorePathFactoryCache>(table_path, table_schema, options, pool_);
185+
ASSERT_OK_AND_ASSIGN(
186+
auto rewriter,
187+
MergeTreeCompactRewriter::Create(
188+
/*bucket=*/1, /*partition=*/BinaryRowGenerator::GenerateRow({10}, pool_.get()),
189+
table_schema, dv_factory, path_factory_cache, options, cancellation_controller, pool_));
190+
191+
ASSERT_OK_AND_ASSIGN(auto runs, GenerateSortedRuns(table_path, table_schema, /*bucket=*/1,
192+
/*partition=*/{{"f1", "10"}}));
193+
194+
// cancel compaction here
195+
cancellation_controller->Cancel();
196+
ASSERT_NOK_WITH_MSG(rewriter->Rewrite(/*output_level=*/5, /*drop_delete=*/true, runs),
197+
"Compaction is cancelled");
198+
}
199+
168200
TEST_F(MergeTreeCompactRewriterTest, TestNotDropDelete) {
169201
std::string origin_table_path = GetDataDir() + "/orc/pk_table_scan_and_read_mor.db/";
170202
auto table_dir = UniqueTestDirectory::Create("local");

src/paimon/core/mergetree/compact/merge_tree_compact_task.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ Status MergeTreeCompactTask::Rewrite(std::vector<std::vector<SortedRun>>* candid
9292
if (candidate->size() == 1) {
9393
const auto& section = (*candidate)[0];
9494
if (section.empty()) {
95-
return Status::OK();
95+
return Status::Invalid("invalid section, section cannot be empty in candidate");
9696
}
9797
if (section.size() == 1) {
9898
for (const auto& file : section[0].Files()) {

src/paimon/core/mergetree/compact/partial_update_merge_function.cpp

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,18 @@ PartialUpdateMergeFunction::CreateFieldAggregators(
265265
return aggregators;
266266
}
267267

268+
void PartialUpdateMergeFunction::Reset() {
269+
current_key_.reset();
270+
meet_insert_ = false;
271+
not_null_column_filled_ = false;
272+
row_ = std::make_unique<GenericRow>(getters_.size());
273+
last_seq_num_ = 0;
274+
for (auto& [_, agg] : field_aggregators_) {
275+
assert(agg);
276+
agg->Reset();
277+
}
278+
}
279+
268280
Status PartialUpdateMergeFunction::Add(KeyValue&& moved_kv) {
269281
// refresh key object to avoid reference overwritten
270282
KeyValue kv = std::move(moved_kv);
@@ -275,33 +287,50 @@ Status PartialUpdateMergeFunction::Add(KeyValue&& moved_kv) {
275287
// In 0.7- versions, the delete records might be written into data file even when
276288
// ignore-delete configured, so ignoreDelete still needs to be checked
277289
if (ignore_delete_) {
290+
if (!not_null_column_filled_) {
291+
InitRowAndHoldData(std::move(kv.value));
292+
not_null_column_filled_ = true;
293+
}
278294
return Status::OK();
279295
}
296+
297+
last_seq_num_ = kv.sequence_number;
298+
280299
if (field_sequence_enabled_) {
300+
// RetractWithSequenceGroup handles InitRow and AddDataHolder internally
281301
PAIMON_RETURN_NOT_OK(RetractWithSequenceGroup(std::move(kv)));
282302
return Status::OK();
283303
}
284304
if (remove_record_on_delete_) {
285305
if (kv.value_kind == RowKind::Delete()) {
286306
current_delete_row_ = true;
287307
row_ = std::make_unique<GenericRow>(getters_.size());
308+
InitRowAndHoldData(std::move(kv.value));
309+
} else if (!not_null_column_filled_) {
310+
InitRowAndHoldData(std::move(kv.value));
311+
not_null_column_filled_ = true;
288312
}
289313
return Status::OK();
290314
}
291315

292316
return Status::Invalid(
293317
"By default, Partial update can not accept delete records, you can choose one of "
294-
"the following solutions:1. Configure ignore-delete to ignore delete records; 2. "
295-
"Configure partial-update.remove-record-on-delete to remove the whole row when "
296-
"receiving delete records; 3. Configure sequence-group to retract partial "
297-
"columns.");
318+
"the following solutions:\n"
319+
"1. Configure 'ignore-delete' to ignore delete records.\n"
320+
"2. Configure 'partial-update.remove-record-on-delete' to remove the whole row "
321+
"when receiving delete records.\n"
322+
"3. Configure 'sequence-group's to retract partial columns. Also configure "
323+
"'partial-update.remove-record-on-sequence-group' to remove the whole row when "
324+
"receiving deleted records of specified sequence group.");
298325
}
299326
last_seq_num_ = kv.sequence_number;
300327
if (field_comparators_.empty()) {
301328
UpdateNonNullFields(std::move(kv));
302329
} else {
303330
UpdateWithSequenceGroup(std::move(kv));
304331
}
332+
meet_insert_ = true;
333+
not_null_column_filled_ = true;
305334
return Status::OK();
306335
}
307336

@@ -356,6 +385,15 @@ void PartialUpdateMergeFunction::UpdateWithSequenceGroup(KeyValue&& kv) {
356385
}
357386

358387
Status PartialUpdateMergeFunction::RetractWithSequenceGroup(KeyValue&& kv) {
388+
// Initialize row with all field values if this is the first record.
389+
// InitRow only reads field values (string_view etc.) from kv.value without taking ownership.
390+
// kv.value remains alive throughout this method, so the views are safe until AddDataHolder
391+
// at the end transfers ownership to row_.
392+
if (!not_null_column_filled_) {
393+
InitRow(*(kv.value));
394+
not_null_column_filled_ = true;
395+
}
396+
359397
std::set<int32_t> updated_sequence_fields;
360398
for (size_t i = 0; i < getters_.size(); ++i) {
361399
auto cmp_iter = field_comparators_.find(i);
@@ -382,6 +420,7 @@ Status PartialUpdateMergeFunction::RetractWithSequenceGroup(KeyValue&& kv) {
382420
sequence_group_partial_delete_.end()) {
383421
current_delete_row_ = true;
384422
row_ = std::make_unique<GenericRow>(getters_.size());
423+
InitRowAndHoldData(std::move(kv.value));
385424
return Status::OK();
386425
} else {
387426
row_->SetField(field_idx, getters_[field_idx](*(kv.value)));
@@ -413,6 +452,18 @@ Status PartialUpdateMergeFunction::RetractWithSequenceGroup(KeyValue&& kv) {
413452
return Status::OK();
414453
}
415454

455+
void PartialUpdateMergeFunction::InitRow(const InternalRow& value) {
456+
for (size_t i = 0; i < getters_.size(); ++i) {
457+
VariantType field = getters_[i](value);
458+
row_->SetField(i, field);
459+
}
460+
}
461+
462+
void PartialUpdateMergeFunction::InitRowAndHoldData(std::unique_ptr<InternalRow>&& value) {
463+
InitRow(*value);
464+
row_->AddDataHolder(std::move(value));
465+
}
466+
416467
bool PartialUpdateMergeFunction::IsEmptySequenceGroup(
417468
const KeyValue& kv, const std::shared_ptr<FieldsComparator>& comparator) const {
418469
for (const auto& field_idx : comparator->CompareFields()) {

0 commit comments

Comments
 (0)