Skip to content

Commit 54e3625

Browse files
committed
feat: implement initial MemoryCatalog functionality with namespace and table support
1 parent a5bcd45 commit 54e3625

File tree

6 files changed

+627
-0
lines changed

6 files changed

+627
-0
lines changed

src/iceberg/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ set(ICEBERG_INCLUDES "$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/src>"
1919
"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src>")
2020
set(ICEBERG_SOURCES
2121
arrow_c_data_internal.cc
22+
catalog/memory_catalog.cc
2223
demo.cc
2324
json_internal.cc
2425
schema.cc
Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
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,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
#include "iceberg/catalog/memory_catalog.h"
21+
22+
#include "iceberg/exception.h"
23+
#include "iceberg/table.h"
24+
25+
namespace iceberg {
26+
27+
MemoryCatalog::MemoryCatalog(std::shared_ptr<FileIO> file_io,
28+
std::optional<std::string> warehouse_location)
29+
: file_io_(std::move(file_io)),
30+
warehouse_location_(std::move(warehouse_location)),
31+
root_container_(std::make_unique<NamespaceContainer>()) {}
32+
33+
void MemoryCatalog::Initialize(
34+
const std::string& name,
35+
const std::unordered_map<std::string, std::string>& properties) {
36+
catalog_name_ = name;
37+
properties_ = properties;
38+
}
39+
40+
std::string_view MemoryCatalog::name() const { return catalog_name_; }
41+
42+
Result<std::vector<TableIdentifier>> MemoryCatalog::ListTables(
43+
const Namespace& ns) const {
44+
std::unique_lock lock(mutex_);
45+
const auto& table_names = root_container_->ListTables(ns);
46+
std::vector<TableIdentifier> table_idents;
47+
table_idents.reserve(table_names.size());
48+
std::ranges::transform(
49+
table_names, std::back_inserter(table_idents),
50+
[&ns](auto const& table_name) { return TableIdentifier(ns, table_name); });
51+
return table_idents;
52+
}
53+
54+
Result<std::unique_ptr<Table>> MemoryCatalog::CreateTable(
55+
const TableIdentifier& identifier, const Schema& schema, const PartitionSpec& spec,
56+
const std::string& location,
57+
const std::unordered_map<std::string, std::string>& properties) {
58+
throw IcebergError("not implemented");
59+
}
60+
61+
Result<std::unique_ptr<Table>> MemoryCatalog::UpdateTable(
62+
const TableIdentifier& identifier,
63+
const std::vector<std::unique_ptr<UpdateRequirement>>& requirements,
64+
const std::vector<std::unique_ptr<MetadataUpdate>>& updates) {
65+
throw IcebergError("not implemented");
66+
}
67+
68+
Result<std::shared_ptr<Transaction>> MemoryCatalog::StageCreateTable(
69+
const TableIdentifier& identifier, const Schema& schema, const PartitionSpec& spec,
70+
const std::string& location,
71+
const std::unordered_map<std::string, std::string>& properties) {
72+
throw IcebergError("not implemented");
73+
}
74+
75+
bool MemoryCatalog::TableExists(const TableIdentifier& identifier) const {
76+
std::unique_lock lock(mutex_);
77+
return root_container_->TableExists(identifier);
78+
}
79+
80+
bool MemoryCatalog::DropTable(const TableIdentifier& identifier, bool purge) {
81+
std::unique_lock lock(mutex_);
82+
// TODO: Delete all metadata files if purge is true.
83+
return root_container_->UnregisterTable(identifier);
84+
}
85+
86+
Result<std::shared_ptr<Table>> MemoryCatalog::LoadTable(
87+
const TableIdentifier& identifier) const {
88+
throw IcebergError("not implemented");
89+
}
90+
91+
Result<std::shared_ptr<Table>> MemoryCatalog::RegisterTable(
92+
const TableIdentifier& identifier, const std::string& metadata_file_location) {
93+
std::unique_lock lock(mutex_);
94+
if (!root_container_->NamespaceExists(identifier.ns)) {
95+
return unexpected<Error>({.kind = ErrorKind::kNoSuchNamespace,
96+
.message = "table namespace does not exist"});
97+
}
98+
if (!root_container_->RegisterTable(identifier, metadata_file_location)) {
99+
return unexpected<Error>(
100+
{.kind = ErrorKind::kUnknownError, .message = "The registry failed."});
101+
}
102+
return LoadTable(identifier);
103+
}
104+
105+
std::unique_ptr<TableBuilder> MemoryCatalog::BuildTable(const TableIdentifier& identifier,
106+
const Schema& schema) const {
107+
throw IcebergError("not implemented");
108+
}
109+
110+
/// Implementation of NamespaceContainer
111+
NamespaceContainer* NamespaceContainer::GetNamespaceContainer(
112+
NamespaceContainer* root, const Namespace& namespace_ident) {
113+
return GetNamespaceContainerImpl(root, namespace_ident);
114+
}
115+
116+
const NamespaceContainer* NamespaceContainer::GetNamespaceContainer(
117+
const NamespaceContainer* root, const Namespace& namespace_ident) {
118+
return GetNamespaceContainerImpl(root, namespace_ident);
119+
}
120+
121+
bool NamespaceContainer::NamespaceExists(const Namespace& namespace_ident) const {
122+
return GetNamespaceContainer(this, namespace_ident) != nullptr;
123+
}
124+
125+
std::vector<std::string> NamespaceContainer::ListChildrenNamespaces(
126+
const std::optional<Namespace>& parent_namespace_ident) const {
127+
auto container = this;
128+
if (parent_namespace_ident.has_value()) {
129+
container = GetNamespaceContainer(this, *parent_namespace_ident);
130+
if (!container) return {};
131+
}
132+
133+
std::vector<std::string> names;
134+
names.reserve(container->children_.size());
135+
std::ranges::transform(container->children_, std::back_inserter(names),
136+
[](const auto& pair) { return pair.first; });
137+
return names;
138+
}
139+
140+
bool NamespaceContainer::CreateNamespace(
141+
const Namespace& namespace_ident,
142+
const std::unordered_map<std::string, std::string>& properties) {
143+
auto container = this;
144+
bool newly_created = false;
145+
146+
for (const auto& part_level : namespace_ident.levels) {
147+
if (auto it = container->children_.find(part_level);
148+
it == container->children_.end()) {
149+
container->children_[part_level] = std::make_unique<NamespaceContainer>();
150+
container = container->children_[part_level].get();
151+
newly_created = true;
152+
} else {
153+
container = it->second.get();
154+
}
155+
}
156+
157+
if (!newly_created) return false;
158+
159+
container->properties_ = properties;
160+
return true;
161+
}
162+
163+
bool NamespaceContainer::DeleteNamespace(const Namespace& namespace_ident) {
164+
if (namespace_ident.levels.empty()) return false;
165+
166+
auto parent_namespace_ident = namespace_ident;
167+
const auto to_delete = parent_namespace_ident.levels.back();
168+
parent_namespace_ident.levels.pop_back();
169+
170+
auto* parent = GetNamespaceContainer(this, parent_namespace_ident);
171+
if (!parent) return false;
172+
173+
auto it = parent->children_.find(to_delete);
174+
if (it == parent->children_.end()) return false;
175+
176+
const auto& target = *it->second;
177+
if (!target.children_.empty() || !target.table_metadata_locations_.empty()) {
178+
return false;
179+
}
180+
181+
return parent->children_.erase(to_delete) > 0;
182+
}
183+
184+
std::optional<std::unordered_map<std::string, std::string>>
185+
NamespaceContainer::GetProperties(const Namespace& namespace_ident) const {
186+
const auto container = GetNamespaceContainer(this, namespace_ident);
187+
if (!container) return std::nullopt;
188+
return container->properties_;
189+
}
190+
191+
bool NamespaceContainer::ReplaceProperties(
192+
const Namespace& namespace_ident,
193+
const std::unordered_map<std::string, std::string>& properties) {
194+
const auto container = GetNamespaceContainer(this, namespace_ident);
195+
if (!container) return false;
196+
container->properties_ = properties;
197+
return true;
198+
}
199+
200+
std::vector<std::string> NamespaceContainer::ListTables(
201+
const Namespace& namespace_ident) const {
202+
const auto container = GetNamespaceContainer(this, namespace_ident);
203+
if (!container) return {};
204+
205+
std::vector<std::string> table_names;
206+
table_names.reserve(container->table_metadata_locations_.size());
207+
208+
std::ranges::transform(container->table_metadata_locations_,
209+
std::back_inserter(table_names),
210+
[](const auto& pair) { return pair.first; });
211+
212+
std::ranges::sort(table_names);
213+
214+
return table_names;
215+
}
216+
217+
bool NamespaceContainer::RegisterTable(TableIdentifier const& table_ident,
218+
const std::string& metadata_location) {
219+
const auto container = GetNamespaceContainer(this, table_ident.ns);
220+
if (!container) return false;
221+
if (container->table_metadata_locations_.contains(table_ident.name)) return false;
222+
container->table_metadata_locations_[table_ident.name] = metadata_location;
223+
return true;
224+
}
225+
226+
bool NamespaceContainer::UnregisterTable(TableIdentifier const& table_ident) {
227+
const auto container = GetNamespaceContainer(this, table_ident.ns);
228+
if (!container) return false;
229+
return container->table_metadata_locations_.erase(table_ident.name) > 0;
230+
}
231+
232+
bool NamespaceContainer::TableExists(TableIdentifier const& table_ident) const {
233+
const auto container = GetNamespaceContainer(this, table_ident.ns);
234+
if (!container) return false;
235+
return container->table_metadata_locations_.contains(table_ident.name);
236+
}
237+
238+
std::optional<std::string> NamespaceContainer::GetTableMetadataLocation(
239+
TableIdentifier const& table_ident) const {
240+
const auto container = GetNamespaceContainer(this, table_ident.ns);
241+
if (!container) return std::nullopt;
242+
const auto it = container->table_metadata_locations_.find(table_ident.name);
243+
if (it == container->table_metadata_locations_.end()) return std::nullopt;
244+
return it->second;
245+
}
246+
} // namespace iceberg

0 commit comments

Comments
 (0)