blob: cf01fe894948713d64e71bbe05e982deb4bf21bb [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 "iceberg/incremental_append_scan.h"
#include <algorithm>
#include <iterator>
#include <unordered_set>
#include <utility>
#include "iceberg/manifest/manifest_entry.h"
#include "iceberg/manifest/manifest_group.h"
#include "iceberg/snapshot.h"
#include "iceberg/table_metadata.h"
#include "iceberg/util/macros.h"
#include "iceberg/util/snapshot_util.h"
namespace iceberg {
Result<std::unique_ptr<IncrementalAppendScan>> IncrementalAppendScan::Make(
std::shared_ptr<TableMetadata> metadata, std::shared_ptr<Schema> schema,
std::shared_ptr<FileIO> io, internal::TableScanContext context) {
ICEBERG_PRECHECK(metadata != nullptr, "Table metadata cannot be null");
ICEBERG_PRECHECK(schema != nullptr, "Schema cannot be null");
ICEBERG_PRECHECK(io != nullptr, "FileIO cannot be null");
return std::unique_ptr<IncrementalAppendScan>(new IncrementalAppendScan(
std::move(metadata), std::move(schema), std::move(io), std::move(context)));
}
Result<std::vector<std::shared_ptr<FileScanTask>>> IncrementalAppendScan::PlanFiles()
const {
return ResolvePlanFiles<FileScanTask>(*this);
}
Result<std::vector<std::shared_ptr<FileScanTask>>> IncrementalAppendScan::PlanFiles(
std::optional<int64_t> from_snapshot_id_exclusive,
int64_t to_snapshot_id_inclusive) const {
ICEBERG_ASSIGN_OR_RAISE(
auto ancestors_snapshots,
SnapshotUtil::AncestorsBetween(*metadata_, to_snapshot_id_inclusive,
from_snapshot_id_exclusive));
std::vector<std::shared_ptr<Snapshot>> append_snapshots;
std::ranges::copy_if(ancestors_snapshots, std::back_inserter(append_snapshots),
[](const auto& snapshot) {
return snapshot != nullptr &&
snapshot->Operation().has_value() &&
snapshot->Operation().value() == DataOperation::kAppend;
});
if (append_snapshots.empty()) {
return std::vector<std::shared_ptr<FileScanTask>>{};
}
std::unordered_set<int64_t> snapshot_ids;
std::ranges::transform(append_snapshots,
std::inserter(snapshot_ids, snapshot_ids.end()),
[](const auto& snapshot) { return snapshot->snapshot_id; });
std::unordered_set<ManifestFile> data_manifests;
for (const auto& snapshot : append_snapshots) {
SnapshotReader snapshot_reader(snapshot.get());
ICEBERG_ASSIGN_OR_RAISE(auto manifests, snapshot_reader.DataManifests(io_));
std::ranges::copy_if(
manifests, std::inserter(data_manifests, data_manifests.end()),
[&snapshot_ids](const ManifestFile& manifest) {
return manifest.added_snapshot_id.has_value() &&
snapshot_ids.contains(manifest.added_snapshot_id.value());
});
}
if (data_manifests.empty()) {
return std::vector<std::shared_ptr<FileScanTask>>{};
}
TableMetadataCache metadata_cache(metadata_.get());
ICEBERG_ASSIGN_OR_RAISE(auto specs_by_id, metadata_cache.GetPartitionSpecsById());
ICEBERG_ASSIGN_OR_RAISE(
auto manifest_group,
ManifestGroup::Make(
io_, schema_, specs_by_id,
std::vector<ManifestFile>(data_manifests.begin(), data_manifests.end()), {}));
manifest_group->CaseSensitive(context_.case_sensitive)
.Select(ScanColumns())
.FilterData(filter())
.FilterManifestEntries([&snapshot_ids](const ManifestEntry& entry) {
return entry.snapshot_id.has_value() &&
snapshot_ids.contains(entry.snapshot_id.value()) &&
entry.status == ManifestStatus::kAdded;
})
.IgnoreDeleted()
.ColumnsToKeepStats(context_.columns_to_keep_stats)
.PlanWith(context_.plan_executor);
if (context_.ignore_residuals) {
manifest_group->IgnoreResiduals();
}
return std::move(*manifest_group).PlanFiles();
}
} // namespace iceberg