Skip to content

Commit d945409

Browse files
authored
feat: add snapshot, snapshot_info, and table core utilities with tests (#118)
1 parent 0a31601 commit d945409

8 files changed

Lines changed: 1349 additions & 0 deletions

File tree

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
#pragma once
20+
21+
#include <cstdint>
22+
#include <optional>
23+
#include <string>
24+
25+
#include "paimon/visibility.h"
26+
27+
namespace paimon {
28+
29+
/// Plain snapshot metadata returned by Catalog::ListSnapshots().
30+
struct PAIMON_EXPORT SnapshotInfo {
31+
/// Commit kind exposed through the public Catalog API.
32+
enum class PAIMON_EXPORT CommitKind : int8_t {
33+
APPEND,
34+
COMPACT,
35+
OVERWRITE,
36+
ANALYZE,
37+
UNKNOWN,
38+
};
39+
40+
/// Convert a CommitKind to its canonical string representation.
41+
static std::string CommitKindToString(CommitKind kind);
42+
43+
int64_t snapshot_id;
44+
int64_t schema_id;
45+
std::string commit_user;
46+
CommitKind commit_kind;
47+
int64_t time_millis;
48+
std::optional<int64_t> total_record_count;
49+
std::optional<int64_t> delta_record_count;
50+
std::optional<int64_t> watermark;
51+
};
52+
53+
} // namespace paimon

src/paimon/core/snapshot.cpp

Lines changed: 329 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,329 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
#include "paimon/core/snapshot.h"
20+
21+
#include <cassert>
22+
#include <stdexcept>
23+
#include <utility>
24+
25+
#include "paimon/common/utils/rapidjson_util.h"
26+
#include "paimon/fs/file_system.h"
27+
#include "paimon/result.h"
28+
#include "paimon/status.h"
29+
#include "rapidjson/allocators.h"
30+
#include "rapidjson/document.h"
31+
#include "rapidjson/rapidjson.h"
32+
33+
namespace paimon {
34+
35+
const Snapshot::CommitKind Snapshot::CommitKind::Append() {
36+
static const Snapshot::CommitKind commit_kind = Snapshot::CommitKind(0);
37+
return commit_kind;
38+
}
39+
40+
const Snapshot::CommitKind Snapshot::CommitKind::Compact() {
41+
static const Snapshot::CommitKind commit_kind = Snapshot::CommitKind(1);
42+
return commit_kind;
43+
}
44+
45+
const Snapshot::CommitKind Snapshot::CommitKind::Overwrite() {
46+
static const Snapshot::CommitKind commit_kind = Snapshot::CommitKind(2);
47+
return commit_kind;
48+
}
49+
50+
const Snapshot::CommitKind Snapshot::CommitKind::Analyze() {
51+
static const Snapshot::CommitKind commit_kind = Snapshot::CommitKind(3);
52+
return commit_kind;
53+
}
54+
55+
const Snapshot::CommitKind Snapshot::CommitKind::Unknown() {
56+
static const Snapshot::CommitKind commit_kind = Snapshot::CommitKind(-1);
57+
return commit_kind;
58+
}
59+
bool Snapshot::TEST_Equal(const Snapshot& other) const {
60+
if (this == &other) {
61+
return true;
62+
}
63+
64+
if ((base_manifest_list_size_ && !other.base_manifest_list_size_) ||
65+
(!base_manifest_list_size_ && other.base_manifest_list_size_)) {
66+
return false;
67+
}
68+
if ((delta_manifest_list_size_ && !other.delta_manifest_list_size_) ||
69+
(!delta_manifest_list_size_ && other.delta_manifest_list_size_)) {
70+
return false;
71+
}
72+
if ((changelog_manifest_list_ && !other.changelog_manifest_list_) ||
73+
(!changelog_manifest_list_ && other.changelog_manifest_list_)) {
74+
return false;
75+
}
76+
if ((changelog_manifest_list_size_ && !other.changelog_manifest_list_size_) ||
77+
(!changelog_manifest_list_size_ && other.changelog_manifest_list_size_)) {
78+
return false;
79+
}
80+
81+
return version_ == other.version_ && id_ == other.id_ && schema_id_ == other.schema_id_ &&
82+
index_manifest_ == other.index_manifest_ && commit_user_ == other.commit_user_ &&
83+
commit_identifier_ == other.commit_identifier_ && commit_kind_ == other.commit_kind_ &&
84+
log_offsets_ == other.log_offsets_ && total_record_count_ == other.total_record_count_ &&
85+
delta_record_count_ == other.delta_record_count_ &&
86+
changelog_record_count_ == other.changelog_record_count_ &&
87+
watermark_ == other.watermark_ && statistics_ == other.statistics_ &&
88+
properties_ == other.properties_ && next_row_id_ == other.next_row_id_;
89+
}
90+
91+
bool Snapshot::operator==(const Snapshot& other) const {
92+
if (this == &other) {
93+
return true;
94+
}
95+
return version_ == other.version_ && id_ == other.id_ && schema_id_ == other.schema_id_ &&
96+
base_manifest_list_ == other.base_manifest_list_ &&
97+
base_manifest_list_size_ == other.base_manifest_list_size_ &&
98+
delta_manifest_list_ == other.delta_manifest_list_ &&
99+
delta_manifest_list_size_ == other.delta_manifest_list_size_ &&
100+
changelog_manifest_list_ == other.changelog_manifest_list_ &&
101+
changelog_manifest_list_size_ == other.changelog_manifest_list_size_ &&
102+
index_manifest_ == other.index_manifest_ && commit_user_ == other.commit_user_ &&
103+
commit_identifier_ == other.commit_identifier_ && commit_kind_ == other.commit_kind_ &&
104+
time_millis_ == other.time_millis_ && log_offsets_ == other.log_offsets_ &&
105+
total_record_count_ == other.total_record_count_ &&
106+
delta_record_count_ == other.delta_record_count_ &&
107+
changelog_record_count_ == other.changelog_record_count_ &&
108+
watermark_ == other.watermark_ && statistics_ == other.statistics_ &&
109+
properties_ == other.properties_ && next_row_id_ == other.next_row_id_;
110+
}
111+
112+
std::string Snapshot::CommitKind::ToString(const Snapshot::CommitKind& kind) {
113+
switch (kind.value_) {
114+
case 0:
115+
return "APPEND";
116+
case 1:
117+
return "COMPACT";
118+
case 2:
119+
return "OVERWRITE";
120+
case 3:
121+
return "ANALYZE";
122+
default:
123+
assert(false);
124+
return "UNKNOWN";
125+
}
126+
}
127+
Snapshot::CommitKind Snapshot::CommitKind::FromString(const std::string& kind) {
128+
if (kind == "APPEND") {
129+
return Append();
130+
} else if (kind == "COMPACT") {
131+
return Compact();
132+
} else if (kind == "OVERWRITE") {
133+
return Overwrite();
134+
} else if (kind == "ANALYZE") {
135+
return Analyze();
136+
}
137+
assert(false);
138+
return Unknown();
139+
}
140+
141+
Snapshot::Snapshot(const std::optional<int32_t>& version, int64_t id, int64_t schema_id,
142+
const std::string& base_manifest_list,
143+
const std::optional<int64_t>& base_manifest_list_size,
144+
const std::string& delta_manifest_list,
145+
const std::optional<int64_t>& delta_manifest_list_size,
146+
const std::optional<std::string>& changelog_manifest_list,
147+
const std::optional<int64_t>& changelog_manifest_list_size,
148+
const std::optional<std::string>& index_manifest, const std::string& commit_user,
149+
int64_t commit_identifier, CommitKind commit_kind, int64_t time_millis,
150+
const std::optional<std::map<int32_t, int64_t>>& log_offsets,
151+
const std::optional<int64_t>& total_record_count,
152+
const std::optional<int64_t>& delta_record_count,
153+
const std::optional<int64_t>& changelog_record_count,
154+
const std::optional<int64_t>& watermark,
155+
const std::optional<std::string>& statistics,
156+
const std::optional<std::map<std::string, std::string>>& properties,
157+
const std::optional<int64_t>& next_row_id)
158+
: version_(version),
159+
id_(id),
160+
schema_id_(schema_id),
161+
base_manifest_list_(base_manifest_list),
162+
base_manifest_list_size_(base_manifest_list_size),
163+
delta_manifest_list_(delta_manifest_list),
164+
delta_manifest_list_size_(delta_manifest_list_size),
165+
changelog_manifest_list_(changelog_manifest_list),
166+
changelog_manifest_list_size_(changelog_manifest_list_size),
167+
index_manifest_(index_manifest),
168+
commit_user_(commit_user),
169+
commit_identifier_(commit_identifier),
170+
commit_kind_(commit_kind),
171+
time_millis_(time_millis),
172+
log_offsets_(log_offsets),
173+
total_record_count_(total_record_count),
174+
delta_record_count_(delta_record_count),
175+
changelog_record_count_(changelog_record_count),
176+
watermark_(watermark),
177+
statistics_(statistics),
178+
properties_(properties),
179+
next_row_id_(next_row_id) {}
180+
181+
rapidjson::Value Snapshot::ToJson(rapidjson::Document::AllocatorType* allocator) const
182+
noexcept(false) {
183+
rapidjson::Value obj(rapidjson::kObjectType);
184+
obj.AddMember(rapidjson::StringRef(FIELD_VERSION),
185+
RapidJsonUtil::SerializeValue(Version(), allocator).Move(), *allocator);
186+
obj.AddMember(rapidjson::StringRef(FIELD_ID),
187+
RapidJsonUtil::SerializeValue(id_, allocator).Move(), *allocator);
188+
obj.AddMember(rapidjson::StringRef(FIELD_SCHEMA_ID),
189+
RapidJsonUtil::SerializeValue(schema_id_, allocator).Move(), *allocator);
190+
obj.AddMember(rapidjson::StringRef(FIELD_BASE_MANIFEST_LIST),
191+
RapidJsonUtil::SerializeValue(base_manifest_list_, allocator).Move(), *allocator);
192+
if (base_manifest_list_size_) {
193+
obj.AddMember(
194+
rapidjson::StringRef(FIELD_BASE_MANIFEST_LIST_SIZE),
195+
RapidJsonUtil::SerializeValue(base_manifest_list_size_.value(), allocator).Move(),
196+
*allocator);
197+
}
198+
obj.AddMember(rapidjson::StringRef(FIELD_DELTA_MANIFEST_LIST),
199+
RapidJsonUtil::SerializeValue(delta_manifest_list_, allocator).Move(),
200+
*allocator);
201+
if (delta_manifest_list_size_) {
202+
obj.AddMember(rapidjson::StringRef(FIELD_DELTA_MANIFEST_LIST_SIZE),
203+
RapidJsonUtil::SerializeValue(delta_manifest_list_size_, allocator).Move(),
204+
*allocator);
205+
}
206+
obj.AddMember(rapidjson::StringRef(FIELD_CHANGELOG_MANIFEST_LIST),
207+
RapidJsonUtil::SerializeValue(changelog_manifest_list_, allocator).Move(),
208+
*allocator);
209+
if (changelog_manifest_list_size_) {
210+
obj.AddMember(
211+
rapidjson::StringRef(FIELD_CHANGELOG_MANIFEST_LIST_SIZE),
212+
RapidJsonUtil::SerializeValue(changelog_manifest_list_size_, allocator).Move(),
213+
*allocator);
214+
}
215+
if (index_manifest_ != std::nullopt) {
216+
obj.AddMember(rapidjson::StringRef(FIELD_INDEX_MANIFEST),
217+
RapidJsonUtil::SerializeValue(index_manifest_.value(), allocator).Move(),
218+
*allocator);
219+
}
220+
221+
obj.AddMember(rapidjson::StringRef(FIELD_COMMIT_USER),
222+
RapidJsonUtil::SerializeValue(commit_user_, allocator).Move(), *allocator);
223+
obj.AddMember(rapidjson::StringRef(FIELD_COMMIT_IDENTIFIER),
224+
RapidJsonUtil::SerializeValue(commit_identifier_, allocator).Move(), *allocator);
225+
obj.AddMember(
226+
rapidjson::StringRef(FIELD_COMMIT_KIND),
227+
RapidJsonUtil::SerializeValue(Snapshot::CommitKind::ToString(commit_kind_), allocator)
228+
.Move(),
229+
*allocator);
230+
231+
obj.AddMember(rapidjson::StringRef(FIELD_TIME_MILLIS),
232+
RapidJsonUtil::SerializeValue(time_millis_, allocator).Move(), *allocator);
233+
if (log_offsets_ != std::nullopt) {
234+
obj.AddMember(rapidjson::StringRef(FIELD_LOG_OFFSETS),
235+
RapidJsonUtil::SerializeValue(log_offsets_.value(), allocator).Move(),
236+
*allocator);
237+
}
238+
obj.AddMember(rapidjson::StringRef(FIELD_TOTAL_RECORD_COUNT),
239+
RapidJsonUtil::SerializeValue(total_record_count_.value(), allocator).Move(),
240+
*allocator);
241+
obj.AddMember(rapidjson::StringRef(FIELD_DELTA_RECORD_COUNT),
242+
RapidJsonUtil::SerializeValue(delta_record_count_.value(), allocator).Move(),
243+
*allocator);
244+
245+
if (changelog_record_count_ != std::nullopt) {
246+
obj.AddMember(
247+
rapidjson::StringRef(FIELD_CHANGELOG_RECORD_COUNT),
248+
RapidJsonUtil::SerializeValue(changelog_record_count_.value(), allocator).Move(),
249+
*allocator);
250+
}
251+
252+
if (watermark_ != std::nullopt) {
253+
obj.AddMember(rapidjson::StringRef(FIELD_WATERMARK),
254+
RapidJsonUtil::SerializeValue(watermark_.value(), allocator).Move(),
255+
*allocator);
256+
}
257+
258+
if (statistics_ != std::nullopt) {
259+
obj.AddMember(rapidjson::StringRef(FIELD_STATISTICS),
260+
RapidJsonUtil::SerializeValue(statistics_.value(), allocator).Move(),
261+
*allocator);
262+
}
263+
if (properties_ != std::nullopt) {
264+
obj.AddMember(rapidjson::StringRef(FIELD_PROPERTIES),
265+
RapidJsonUtil::SerializeValue(properties_.value(), allocator).Move(),
266+
*allocator);
267+
}
268+
if (next_row_id_ != std::nullopt) {
269+
obj.AddMember(rapidjson::StringRef(FIELD_NEXT_ROW_ID),
270+
RapidJsonUtil::SerializeValue(next_row_id_.value(), allocator).Move(),
271+
*allocator);
272+
}
273+
274+
return obj;
275+
}
276+
277+
void Snapshot::FromJson(const rapidjson::Value& obj) noexcept(false) {
278+
version_ = RapidJsonUtil::DeserializeKeyValue<int32_t>(obj, FIELD_VERSION, -1);
279+
id_ = RapidJsonUtil::DeserializeKeyValue<int64_t>(obj, FIELD_ID);
280+
schema_id_ = RapidJsonUtil::DeserializeKeyValue<int64_t>(obj, FIELD_SCHEMA_ID);
281+
base_manifest_list_ =
282+
RapidJsonUtil::DeserializeKeyValue<std::string>(obj, FIELD_BASE_MANIFEST_LIST);
283+
base_manifest_list_size_ = RapidJsonUtil::DeserializeKeyValue<std::optional<int64_t>>(
284+
obj, FIELD_BASE_MANIFEST_LIST_SIZE);
285+
delta_manifest_list_ =
286+
RapidJsonUtil::DeserializeKeyValue<std::string>(obj, FIELD_DELTA_MANIFEST_LIST);
287+
delta_manifest_list_size_ = RapidJsonUtil::DeserializeKeyValue<std::optional<int64_t>>(
288+
obj, FIELD_DELTA_MANIFEST_LIST_SIZE);
289+
changelog_manifest_list_ = RapidJsonUtil::DeserializeKeyValue<std::optional<std::string>>(
290+
obj, FIELD_CHANGELOG_MANIFEST_LIST);
291+
changelog_manifest_list_size_ = RapidJsonUtil::DeserializeKeyValue<std::optional<int64_t>>(
292+
obj, FIELD_CHANGELOG_MANIFEST_LIST_SIZE);
293+
index_manifest_ =
294+
RapidJsonUtil::DeserializeKeyValue<std::optional<std::string>>(obj, FIELD_INDEX_MANIFEST);
295+
commit_user_ = RapidJsonUtil::DeserializeKeyValue<std::string>(obj, FIELD_COMMIT_USER);
296+
commit_identifier_ = RapidJsonUtil::DeserializeKeyValue<int64_t>(obj, FIELD_COMMIT_IDENTIFIER);
297+
commit_kind_ = Snapshot::CommitKind::FromString(
298+
RapidJsonUtil::DeserializeKeyValue<std::string>(obj, FIELD_COMMIT_KIND));
299+
if (commit_kind_ == Snapshot::CommitKind::Unknown()) {
300+
throw std::invalid_argument("deserialize CommitKind failed");
301+
}
302+
time_millis_ = RapidJsonUtil::DeserializeKeyValue<int64_t>(obj, FIELD_TIME_MILLIS);
303+
log_offsets_ = RapidJsonUtil::DeserializeKeyValue<std::optional<std::map<int32_t, int64_t>>>(
304+
obj, FIELD_LOG_OFFSETS);
305+
total_record_count_ =
306+
RapidJsonUtil::DeserializeKeyValue<std::optional<int64_t>>(obj, FIELD_TOTAL_RECORD_COUNT);
307+
delta_record_count_ =
308+
RapidJsonUtil::DeserializeKeyValue<std::optional<int64_t>>(obj, FIELD_DELTA_RECORD_COUNT);
309+
changelog_record_count_ = RapidJsonUtil::DeserializeKeyValue<std::optional<int64_t>>(
310+
obj, FIELD_CHANGELOG_RECORD_COUNT);
311+
watermark_ = RapidJsonUtil::DeserializeKeyValue<std::optional<int64_t>>(obj, FIELD_WATERMARK);
312+
statistics_ =
313+
RapidJsonUtil::DeserializeKeyValue<std::optional<std::string>>(obj, FIELD_STATISTICS);
314+
properties_ =
315+
RapidJsonUtil::DeserializeKeyValue<std::optional<std::map<std::string, std::string>>>(
316+
obj, FIELD_PROPERTIES);
317+
next_row_id_ =
318+
RapidJsonUtil::DeserializeKeyValue<std::optional<int64_t>>(obj, FIELD_NEXT_ROW_ID);
319+
}
320+
321+
Result<Snapshot> Snapshot::FromPath(const std::shared_ptr<FileSystem>& fs,
322+
const std::string& path) {
323+
std::string json_str;
324+
PAIMON_RETURN_NOT_OK(fs->ReadFile(path, &json_str));
325+
PAIMON_ASSIGN_OR_RAISE(Snapshot snapshot, Snapshot::FromJsonString(json_str));
326+
return snapshot;
327+
}
328+
329+
} // namespace paimon

0 commit comments

Comments
 (0)