|
19 | 19 |
|
20 | 20 | #include "iceberg/snapshot.h" |
21 | 21 |
|
| 22 | +#include <charconv> |
| 23 | + |
22 | 24 | #include "iceberg/file_io.h" |
23 | 25 | #include "iceberg/manifest/manifest_list.h" |
24 | 26 | #include "iceberg/manifest/manifest_reader.h" |
25 | 27 | #include "iceberg/util/macros.h" |
| 28 | +#include "iceberg/util/string_util.h" |
26 | 29 |
|
27 | 30 | namespace iceberg { |
28 | 31 |
|
@@ -75,6 +78,24 @@ std::optional<std::string_view> Snapshot::operation() const { |
75 | 78 | return std::nullopt; |
76 | 79 | } |
77 | 80 |
|
| 81 | +std::optional<int64_t> Snapshot::FirstRowId() const { |
| 82 | + auto it = summary.find("first-row-id"); |
| 83 | + if (it == summary.end()) { |
| 84 | + return std::nullopt; |
| 85 | + } |
| 86 | + |
| 87 | + return StringUtils::ParseInt<int64_t>(it->second); |
| 88 | +} |
| 89 | + |
| 90 | +std::optional<int64_t> Snapshot::AddedRows() const { |
| 91 | + auto it = summary.find("added-rows"); |
| 92 | + if (it == summary.end()) { |
| 93 | + return std::nullopt; |
| 94 | + } |
| 95 | + |
| 96 | + return StringUtils::ParseInt<int64_t>(it->second); |
| 97 | +} |
| 98 | + |
78 | 99 | bool Snapshot::Equals(const Snapshot& other) const { |
79 | 100 | if (this == &other) { |
80 | 101 | return true; |
@@ -141,4 +162,103 @@ Result<std::span<ManifestFile>> SnapshotCache::DeleteManifests( |
141 | 162 | return std::span<ManifestFile>(cache.first.data() + delete_start, delete_count); |
142 | 163 | } |
143 | 164 |
|
| 165 | +// SnapshotRef::Builder implementation |
| 166 | + |
| 167 | +SnapshotRef::Builder::Builder(SnapshotRefType type, int64_t snapshot_id) |
| 168 | + : type_(type), snapshot_id_(snapshot_id) {} |
| 169 | + |
| 170 | +SnapshotRef::Builder SnapshotRef::Builder::TagBuilder(int64_t snapshot_id) { |
| 171 | + return Builder(SnapshotRefType::kTag, snapshot_id); |
| 172 | +} |
| 173 | + |
| 174 | +SnapshotRef::Builder SnapshotRef::Builder::BranchBuilder(int64_t snapshot_id) { |
| 175 | + return Builder(SnapshotRefType::kBranch, snapshot_id); |
| 176 | +} |
| 177 | + |
| 178 | +SnapshotRef::Builder SnapshotRef::Builder::BuilderFor(int64_t snapshot_id, |
| 179 | + SnapshotRefType type) { |
| 180 | + return Builder(type, snapshot_id); |
| 181 | +} |
| 182 | + |
| 183 | +SnapshotRef::Builder SnapshotRef::Builder::BuilderFrom(const SnapshotRef& ref) { |
| 184 | + Builder builder(ref.type(), ref.snapshot_id); |
| 185 | + if (ref.type() == SnapshotRefType::kBranch) { |
| 186 | + const auto& branch = std::get<SnapshotRef::Branch>(ref.retention); |
| 187 | + builder.min_snapshots_to_keep_ = branch.min_snapshots_to_keep; |
| 188 | + builder.max_snapshot_age_ms_ = branch.max_snapshot_age_ms; |
| 189 | + builder.max_ref_age_ms_ = branch.max_ref_age_ms; |
| 190 | + } else { |
| 191 | + const auto& tag = std::get<SnapshotRef::Tag>(ref.retention); |
| 192 | + builder.max_ref_age_ms_ = tag.max_ref_age_ms; |
| 193 | + } |
| 194 | + return builder; |
| 195 | +} |
| 196 | + |
| 197 | +SnapshotRef::Builder SnapshotRef::Builder::BuilderFrom(const SnapshotRef& ref, |
| 198 | + int64_t snapshot_id) { |
| 199 | + Builder builder(ref.type(), snapshot_id); |
| 200 | + if (ref.type() == SnapshotRefType::kBranch) { |
| 201 | + const auto& branch = std::get<SnapshotRef::Branch>(ref.retention); |
| 202 | + builder.min_snapshots_to_keep_ = branch.min_snapshots_to_keep; |
| 203 | + builder.max_snapshot_age_ms_ = branch.max_snapshot_age_ms; |
| 204 | + builder.max_ref_age_ms_ = branch.max_ref_age_ms; |
| 205 | + } else { |
| 206 | + const auto& tag = std::get<SnapshotRef::Tag>(ref.retention); |
| 207 | + builder.max_ref_age_ms_ = tag.max_ref_age_ms; |
| 208 | + } |
| 209 | + return builder; |
| 210 | +} |
| 211 | + |
| 212 | +SnapshotRef::Builder& SnapshotRef::Builder::MinSnapshotsToKeep( |
| 213 | + std::optional<int32_t> value) { |
| 214 | + if (type_ == SnapshotRefType::kTag && value.has_value()) { |
| 215 | + return AddError(ErrorKind::kInvalidArgument, |
| 216 | + "Tags do not support setting minSnapshotsToKeep"); |
| 217 | + } |
| 218 | + if (value.has_value() && value.value() <= 0) { |
| 219 | + return AddError(ErrorKind::kInvalidArgument, |
| 220 | + "Min snapshots to keep must be greater than 0"); |
| 221 | + } |
| 222 | + min_snapshots_to_keep_ = value; |
| 223 | + return *this; |
| 224 | +} |
| 225 | + |
| 226 | +SnapshotRef::Builder& SnapshotRef::Builder::MaxSnapshotAgeMs( |
| 227 | + std::optional<int64_t> value) { |
| 228 | + if (type_ == SnapshotRefType::kTag && value.has_value()) { |
| 229 | + return AddError(ErrorKind::kInvalidArgument, |
| 230 | + "Tags do not support setting maxSnapshotAgeMs"); |
| 231 | + } |
| 232 | + if (value.has_value() && value.value() <= 0) { |
| 233 | + return AddError(ErrorKind::kInvalidArgument, |
| 234 | + "Max snapshot age must be greater than 0 ms"); |
| 235 | + } |
| 236 | + max_snapshot_age_ms_ = value; |
| 237 | + return *this; |
| 238 | +} |
| 239 | + |
| 240 | +SnapshotRef::Builder& SnapshotRef::Builder::MaxRefAgeMs(std::optional<int64_t> value) { |
| 241 | + if (value.has_value() && value.value() <= 0) { |
| 242 | + return AddError(ErrorKind::kInvalidArgument, |
| 243 | + "Max reference age must be greater than 0"); |
| 244 | + } |
| 245 | + max_ref_age_ms_ = value; |
| 246 | + return *this; |
| 247 | +} |
| 248 | + |
| 249 | +Result<SnapshotRef> SnapshotRef::Builder::Build() const { |
| 250 | + ICEBERG_RETURN_UNEXPECTED(CheckErrors()); |
| 251 | + |
| 252 | + if (type_ == SnapshotRefType::kBranch) { |
| 253 | + return SnapshotRef{ |
| 254 | + .snapshot_id = snapshot_id_, |
| 255 | + .retention = SnapshotRef::Branch{.min_snapshots_to_keep = min_snapshots_to_keep_, |
| 256 | + .max_snapshot_age_ms = max_snapshot_age_ms_, |
| 257 | + .max_ref_age_ms = max_ref_age_ms_}}; |
| 258 | + } else { |
| 259 | + return SnapshotRef{.snapshot_id = snapshot_id_, |
| 260 | + .retention = SnapshotRef::Tag{.max_ref_age_ms = max_ref_age_ms_}}; |
| 261 | + } |
| 262 | +} |
| 263 | + |
144 | 264 | } // namespace iceberg |
0 commit comments