Skip to content

Commit 8f2f7ca

Browse files
committed
ct/l0: Add object path utility for random prefix
Signed-off-by: Oren Leiman <oren.leiman@redpanda.com>
1 parent d66342c commit 8f2f7ca

3 files changed

Lines changed: 64 additions & 0 deletions

File tree

src/v/cloud_topics/object_utils.cc

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,33 @@ object_path_factory::level_zero_path_to_epoch(std::string_view key) {
8383
return cluster_epoch(epoch);
8484
}
8585

86+
std::expected<decltype(object_id::prefix), std::string>
87+
object_path_factory::level_zero_path_to_prefix(std::string_view key) {
88+
// find the level zero prefix and chop it off
89+
auto name = key;
90+
auto it = name.find(level_zero_data_dir_str);
91+
if (it == std::string_view::npos) {
92+
return std::unexpected(
93+
fmt::format("L0 object name missing prefix: {}", key));
94+
}
95+
name.remove_prefix(it + std::strlen(level_zero_data_dir_str));
96+
97+
if (name.size() < prefix_digits + 1) {
98+
return std::unexpected(
99+
fmt::format("L0 object name is too short: {}", key));
100+
}
101+
name = name.substr(0, prefix_digits);
102+
name.remove_suffix(name.size() - prefix_digits);
103+
104+
// parse the prefix into a uint16_t
105+
decltype(object_id::prefix) pfx{0};
106+
auto res = std::from_chars(name.data(), name.data() + name.size(), pfx);
107+
if (res.ptr != name.data() + name.size() || res.ec != std::errc{}) {
108+
return std::unexpected(
109+
fmt::format("L0 object name has invalid prefix: {}", key));
110+
}
111+
112+
return pfx;
113+
}
114+
86115
} // namespace cloud_topics

src/v/cloud_topics/object_utils.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ class object_path_factory {
3636
*/
3737
static std::expected<cluster_epoch, std::string>
3838
level_zero_path_to_epoch(std::string_view);
39+
40+
static std::expected<decltype(object_id::prefix), std::string>
41+
level_zero_path_to_prefix(std::string_view);
3942
};
4043

4144
} // namespace cloud_topics

src/v/cloud_topics/tests/object_utils_test.cc

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,35 @@ TEST(ObjectPathFactory, LevelZeroParseEpoch) {
7070
"L0 object name has invalid epoch: "
7171
"level_zero/data/000/00000X0000000010042/asdfasdf");
7272
}
73+
74+
TEST(ObjectPathFactory, LevelZeroParsePrefix) {
75+
EXPECT_EQ(
76+
cloud_topics::object_path_factory::level_zero_path_to_prefix(
77+
"level_zero/data/123/"),
78+
123);
79+
80+
EXPECT_EQ(
81+
cloud_topics::object_path_factory::level_zero_path_to_prefix(
82+
"level_zero/data/123/000000000000010042/"),
83+
123);
84+
85+
EXPECT_EQ(
86+
cloud_topics::object_path_factory::level_zero_path_to_prefix(
87+
"level_asdf_zero/data/000/000000000000010042/asdfasdf")
88+
.error(),
89+
"L0 object name missing prefix: "
90+
"level_asdf_zero/data/000/000000000000010042/asdfasdf");
91+
92+
EXPECT_EQ(
93+
cloud_topics::object_path_factory::level_zero_path_to_prefix(
94+
"level_zero/data/00/")
95+
.error(),
96+
"L0 object name is too short: level_zero/data/00/");
97+
98+
EXPECT_EQ(
99+
cloud_topics::object_path_factory::level_zero_path_to_prefix(
100+
"level_zero/data/0X0/0000000000000010042/asdfasdf")
101+
.error(),
102+
"L0 object name has invalid prefix: "
103+
"level_zero/data/0X0/0000000000000010042/asdfasdf");
104+
}

0 commit comments

Comments
 (0)