blob: abee76958e7f993c04c2503e94b8b8735e043fe6 [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include "paimon/core/operation/commit/commit_scanner.h"
#include <cstdint>
#include <map>
#include <memory>
#include <optional>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
#include "paimon/common/utils/binary_row_partition_computer.h"
#include "paimon/core/core_options.h"
#include "paimon/core/manifest/file_kind.h"
#include "paimon/core/manifest/index_manifest_file.h"
#include "paimon/core/manifest/manifest_entry.h"
#include "paimon/core/manifest/manifest_file_meta.h"
#include "paimon/core/operation/commit/overwrite_changes_provider.h"
#include "paimon/core/operation/file_store_scan.h"
#include "paimon/core/table/bucket_mode.h"
#include "paimon/scan_context.h"
namespace paimon {
CommitScanner::CommitScanner(const std::shared_ptr<SnapshotManager>& snapshot_manager,
const std::shared_ptr<SchemaManager>& schema_manager,
const std::shared_ptr<ManifestList>& manifest_list,
const std::shared_ptr<ManifestFile>& manifest_file,
const std::shared_ptr<IndexManifestFile>& index_manifest_file,
const std::shared_ptr<TableSchema>& table_schema,
const std::shared_ptr<arrow::Schema>& schema,
const CoreOptions& core_options,
const std::shared_ptr<Executor>& executor,
const std::shared_ptr<MemoryPool>& pool,
const BinaryRowPartitionComputer* partition_computer,
ScanSupplier scan_supplier)
: snapshot_manager_(snapshot_manager),
schema_manager_(schema_manager),
manifest_list_(manifest_list),
manifest_file_(manifest_file),
index_manifest_file_(index_manifest_file),
table_schema_(table_schema),
schema_(schema),
core_options_(core_options),
executor_(executor),
pool_(pool),
partition_computer_(partition_computer),
scan_supplier_(std::move(scan_supplier)) {}
Result<std::vector<std::map<std::string, std::string>>> CommitScanner::ToPartitionFilters(
const std::vector<BinaryRow>& changed_partitions) const {
std::vector<std::map<std::string, std::string>> partition_filters;
partition_filters.reserve(changed_partitions.size());
for (const BinaryRow& changed_partition : changed_partitions) {
std::vector<std::pair<std::string, std::string>> part_values;
PAIMON_ASSIGN_OR_RAISE(part_values,
partition_computer_->GeneratePartitionVector(changed_partition));
std::map<std::string, std::string> partition_filter;
for (const auto& [key, value] : part_values) {
partition_filter[key] = value;
}
partition_filters.push_back(std::move(partition_filter));
}
return partition_filters;
}
Result<std::vector<ManifestEntry>> CommitScanner::ReadAllEntriesFromChangedPartitions(
const Snapshot& snapshot, const std::vector<BinaryRow>& changed_partitions) const {
if (changed_partitions.empty()) {
return std::vector<ManifestEntry>{};
}
std::vector<std::map<std::string, std::string>> partition_filters;
PAIMON_ASSIGN_OR_RAISE(partition_filters, ToPartitionFilters(changed_partitions));
PAIMON_ASSIGN_OR_RAISE(std::unique_ptr<FileStoreScan> scan,
NewScan(partition_filters, /*for_overwrite=*/false));
PAIMON_ASSIGN_OR_RAISE(std::shared_ptr<FileStoreScan::RawPlan> plan,
scan->WithSnapshot(snapshot)->WithKind(ScanMode::ALL)->CreatePlan());
return plan->Files();
}
Result<std::vector<ManifestEntry>> CommitScanner::ReadIncrementalEntries(
const Snapshot& snapshot, const std::vector<BinaryRow>& changed_partitions) const {
if (changed_partitions.empty()) {
return std::vector<ManifestEntry>{};
}
std::unordered_set<BinaryRow> changed_partition_set(changed_partitions.begin(),
changed_partitions.end());
std::vector<ManifestFileMeta> delta_manifests;
PAIMON_RETURN_NOT_OK(manifest_list_->ReadDeltaManifests(snapshot, &delta_manifests));
std::vector<ManifestEntry> incremental_entries;
for (const ManifestFileMeta& manifest_meta : delta_manifests) {
std::vector<ManifestEntry> manifest_entries;
PAIMON_RETURN_NOT_OK(
manifest_file_->Read(manifest_meta.FileName(), /*filter=*/nullptr, &manifest_entries));
for (const ManifestEntry& entry : manifest_entries) {
if (changed_partition_set.find(entry.Partition()) != changed_partition_set.end()) {
incremental_entries.push_back(entry);
}
}
}
return incremental_entries;
}
Result<std::vector<ManifestEntry>> CommitScanner::ReadAllEntriesFromPartitions(
const Snapshot& snapshot,
const std::vector<std::map<std::string, std::string>>& partitions) const {
PAIMON_ASSIGN_OR_RAISE(std::unique_ptr<FileStoreScan> scan,
NewScan(partitions, /*for_overwrite=*/false));
PAIMON_ASSIGN_OR_RAISE(std::shared_ptr<FileStoreScan::RawPlan> plan,
scan->WithSnapshot(snapshot)->WithKind(ScanMode::ALL)->CreatePlan());
return plan->Files();
}
Result<std::unique_ptr<FileStoreScan>> CommitScanner::NewScan(
const std::vector<std::map<std::string, std::string>>& partitions, bool for_overwrite) const {
auto scan_filter = std::make_shared<ScanFilter>(/*predicate=*/nullptr, partitions,
/*bucket_filter=*/std::nullopt);
if (!scan_supplier_) {
return Status::Invalid("CommitScanner requires non-empty scan supplier.");
}
PAIMON_ASSIGN_OR_RAISE(std::unique_ptr<FileStoreScan> scan, scan_supplier_(scan_filter));
if (for_overwrite && core_options_.GetBucket() != BucketModeDefine::POSTPONE_BUCKET) {
scan->OnlyReadRealBuckets();
}
return scan;
}
Result<std::vector<IndexManifestEntry>> CommitScanner::ReadAllIndexEntriesFromPartitions(
const Snapshot& snapshot,
const std::vector<std::map<std::string, std::string>>& partitions) const {
std::vector<IndexManifestEntry> index_entries;
if (!snapshot.IndexManifest()) {
return index_entries;
}
auto filter = [this, &partitions](const IndexManifestEntry& entry) -> Result<bool> {
if (partitions.empty()) {
return true;
}
std::vector<std::pair<std::string, std::string>> part_values;
PAIMON_ASSIGN_OR_RAISE(part_values,
partition_computer_->GeneratePartitionVector(entry.partition));
std::map<std::string, std::string> partition;
for (const auto& [key, value] : part_values) {
partition[key] = value;
}
for (const auto& partition_spec : partitions) {
bool matched = true;
for (const auto& [key, value] : partition_spec) {
auto iter = partition.find(key);
if (iter == partition.end() || iter->second != value) {
matched = false;
break;
}
}
if (matched) {
return true;
}
}
return false;
};
PAIMON_RETURN_NOT_OK(
index_manifest_file_->Read(snapshot.IndexManifest().value(), filter, &index_entries));
return index_entries;
}
std::shared_ptr<CommitChangesProvider> CommitScanner::OverwriteChangesProvider(
const std::vector<std::map<std::string, std::string>>& partitions,
const std::vector<ManifestEntry>& changes,
const std::vector<IndexManifestEntry>& index_entries) const {
return std::make_shared<paimon::OverwriteChangesProvider>(
changes, index_entries,
[this, partitions](const Snapshot& snapshot) -> Result<std::vector<ManifestEntry>> {
PAIMON_ASSIGN_OR_RAISE(std::unique_ptr<FileStoreScan> scan,
NewScan(partitions, /*for_overwrite=*/true));
PAIMON_ASSIGN_OR_RAISE(
std::shared_ptr<FileStoreScan::RawPlan> plan,
scan->WithSnapshot(snapshot)->WithKind(ScanMode::ALL)->CreatePlan());
return plan->Files();
},
[this, partitions](const Snapshot& snapshot) {
return ReadAllIndexEntriesFromPartitions(snapshot, partitions);
});
}
Result<std::unordered_map<BinaryRow, int32_t>> CommitScanner::ReadTotalBuckets(
const Snapshot& snapshot, const std::vector<BinaryRow>& changed_partitions) const {
std::unordered_map<BinaryRow, int32_t> total_buckets;
if (changed_partitions.empty()) {
return total_buckets;
}
PAIMON_ASSIGN_OR_RAISE(std::vector<ManifestEntry> entries,
ReadAllEntriesFromChangedPartitions(snapshot, changed_partitions));
std::unordered_set<BinaryRow> remaining_partitions(changed_partitions.begin(),
changed_partitions.end());
for (const ManifestEntry& entry : entries) {
if (remaining_partitions.empty()) {
break;
}
if (!(entry.Kind() == FileKind::Add()) || entry.TotalBuckets() <= 0) {
continue;
}
if (remaining_partitions.erase(entry.Partition()) > 0) {
total_buckets.emplace(entry.Partition(), entry.TotalBuckets());
}
}
return total_buckets;
}
} // namespace paimon