Skip to content

Commit 3323e42

Browse files
SteNicholasclaude
andcommitted
feat(rest): support rest catalog with database/table operations and snapshot listing
Add a REST catalog implementation selected via the "metastore=rest" option: - HttpClient: blocking libcurl client with exponential-backoff retries (429/503 retried for all methods, transport errors only for idempotent ones, honoring a numeric Retry-After header). - RestApi: HTTP + JSON layer with "/v1/config" option merging (overrides > client options > defaults), "header." options as request headers, paged listing and http-status-to-Status error mapping including the x-request-id. - RestCatalog: database/table operations and snapshot listing, "table-default." option defaults, system/branch table checks and schema conversion with the computed highestFieldId. - Bear token authentication provider. libcurl is used from the system rather than bundled, so the new PAIMON_ENABLE_REST option defaults to OFF like the other optional components with external requirements and is documented alongside them; CI enables it explicitly and installs the libcurl development package. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent cd0d3ce commit 3323e42

31 files changed

Lines changed: 3961 additions & 31 deletions

.github/workflows/build_and_test.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ jobs:
6767
uses: ./.github/actions/setup-ccache
6868
with:
6969
cache-key-prefix: ccache-${{ matrix.name }}
70+
- name: Install dependencies
71+
shell: bash
72+
run: |
73+
sudo apt-get update
74+
sudo apt-get install -y libcurl4-openssl-dev
7075
- name: Install Rust toolchain (tantivy-fts)
7176
if: ${{ !matrix.skip_rust }}
7277
shell: bash

.github/workflows/gcc8_test.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ jobs:
4242
- name: Install dependencies
4343
run: |
4444
apt-get update
45-
DEBIAN_FRONTEND=noninteractive apt-get install -y gcc-8 g++-8 ninja-build git git-lfs tar curl tzdata zip unzip pkg-config build-essential python3-dev gdb sudo
45+
DEBIAN_FRONTEND=noninteractive apt-get install -y gcc-8 g++-8 ninja-build git git-lfs tar curl libcurl4-openssl-dev tzdata zip unzip pkg-config build-essential python3-dev gdb sudo
4646
curl -L -O https://github.com/Kitware/CMake/releases/download/v3.28.3/cmake-3.28.3-linux-x86_64.tar.gz
4747
tar -zxvf cmake-3.28.3-linux-x86_64.tar.gz -C /usr/local --strip-components=1
4848
rm cmake-3.28.3-linux-x86_64.tar.gz

CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,14 @@ option(PAIMON_ENABLE_LUMINA "Whether to enable lumina vector index" OFF)
6363
option(PAIMON_ENABLE_LUCENE "Whether to enable lucene index" OFF)
6464
option(PAIMON_ENABLE_TANTIVY
6565
"Whether to enable tantivy-fulltext global index (Rust FFI, experimental)" OFF)
66+
option(PAIMON_ENABLE_REST "Whether to enable the rest catalog (requires libcurl)" OFF)
6667
if(PAIMON_ENABLE_ORC)
6768
add_definitions(-DPAIMON_ENABLE_ORC)
6869
endif()
70+
if(PAIMON_ENABLE_REST)
71+
find_package(CURL REQUIRED)
72+
add_definitions(-DPAIMON_ENABLE_REST)
73+
endif()
6974
if(PAIMON_ENABLE_AVRO)
7075
add_definitions(-DPAIMON_ENABLE_AVRO)
7176
endif()

ci/scripts/build_paimon.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ CMAKE_ARGS=(
136136
"-DPAIMON_ENABLE_LUMINA=${ENABLE_LUMINA}"
137137
"-DPAIMON_ENABLE_LUCENE=ON"
138138
"-DPAIMON_ENABLE_TANTIVY=${ENABLE_TANTIVY}"
139+
"-DPAIMON_ENABLE_REST=ON"
139140
"-DPAIMON_LINT_GIT_TARGET_COMMIT=${lint_git_target_commit}"
140141
)
141142

docs/source/building.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ boolean flags to ``cmake``.
147147
* ``-DPAIMON_ENABLE_AVRO=ON``: Apache Avro libraries and Paimon integration
148148
* ``-DPAIMON_ENABLE_JINDO=ON``: Support for Alibaba Jindo filesystems
149149
* ``-DPAIMON_ENABLE_LUMINA=ON``: Support for Lumina vector index, lumina is only supported on gcc9 or higher.
150+
* ``-DPAIMON_ENABLE_REST=ON``: Support for the REST catalog (``metastore=rest``), requires the libcurl development package.
150151

151152
Third-party dependency source
152153
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

include/paimon/defs.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,20 @@ struct PAIMON_EXPORT Options {
112112
/// Default value is local.
113113
static const char FILE_SYSTEM[];
114114

115+
/// "metastore" - Metastore of the paimon catalog.
116+
/// Supported values are "filesystem" (default) and "rest".
117+
static const char METASTORE[];
118+
119+
/// "uri" - Server url of the REST catalog. Only used when METASTORE is "rest".
120+
static const char URI[];
121+
122+
/// "token" - Token of the "bear" token provider of the REST catalog.
123+
static const char TOKEN[];
124+
125+
/// "token.provider" - Authentication provider of the REST catalog.
126+
/// Currently only "bear" is supported.
127+
static const char TOKEN_PROVIDER[];
128+
115129
/// "target-file-size" - Target size of a file. primary key table: the default value is 128 MB.
116130
/// append table: the default value is 256 MB.
117131
static const char TARGET_FILE_SIZE[];

src/paimon/CMakeLists.txt

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,20 @@ set(PAIMON_CORE_SRCS
395395
core/utils/special_field_ids.cpp
396396
core/utils/tag_manager.cpp)
397397

398+
set(PAIMON_REST_LINK_LIBS)
399+
if(PAIMON_ENABLE_REST)
400+
list(APPEND
401+
PAIMON_CORE_SRCS
402+
rest/http_client.cpp
403+
rest/resource_paths.cpp
404+
rest/rest_api.cpp
405+
rest/rest_auth.cpp
406+
rest/rest_catalog.cpp
407+
rest/rest_messages.cpp
408+
rest/rest_util.cpp)
409+
set(PAIMON_REST_LINK_LIBS CURL::libcurl)
410+
endif()
411+
398412
add_paimon_lib(paimon
399413
SOURCES
400414
${PAIMON_COMMON_SRCS}
@@ -408,6 +422,7 @@ add_paimon_lib(paimon
408422
xxhash
409423
Threads::Threads
410424
RapidJSON
425+
${PAIMON_REST_LINK_LIBS}
411426
STATIC_LINK_LIBS
412427
arrow
413428
tbb
@@ -417,6 +432,7 @@ add_paimon_lib(paimon
417432
xxhash
418433
Threads::Threads
419434
RapidJSON
435+
${PAIMON_REST_LINK_LIBS}
420436
SHARED_LINK_FLAGS
421437
${PAIMON_VERSION_SCRIPT_FLAGS})
422438

@@ -855,4 +871,18 @@ if(PAIMON_BUILD_TESTS)
855871
target_compile_definitions(paimon-fs-test PRIVATE PAIMON_ENABLE_NETWORK_TESTS)
856872
endif()
857873

874+
if(PAIMON_ENABLE_REST)
875+
add_paimon_test(rest_test
876+
SOURCES
877+
rest/http_client_test.cpp
878+
rest/mock_rest_server.cpp
879+
rest/rest_catalog_test.cpp
880+
rest/rest_messages_test.cpp
881+
STATIC_LINK_LIBS
882+
paimon_shared
883+
test_utils_static
884+
${TEST_STATIC_LINK_LIBS}
885+
${GTEST_LINK_TOOLCHAIN})
886+
endif()
887+
858888
endif()

src/paimon/common/defs.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ const char Options::BUCKET[] = "bucket";
3131
const char Options::BUCKET_KEY[] = "bucket-key";
3232
const char Options::FILE_FORMAT[] = "file.format";
3333
const char Options::FILE_SYSTEM[] = "file-system";
34+
const char Options::METASTORE[] = "metastore";
35+
const char Options::URI[] = "uri";
36+
const char Options::TOKEN[] = "token";
37+
const char Options::TOKEN_PROVIDER[] = "token.provider";
3438
const char Options::TARGET_FILE_SIZE[] = "target-file-size";
3539
const char Options::BLOB_TARGET_FILE_SIZE[] = "blob.target-file-size";
3640
const char Options::BLOB_SPLIT_BY_FILE_SIZE[] = "blob.split-by-file-size";

src/paimon/core/catalog/catalog.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,13 @@
1818

1919
#include <utility>
2020

21+
#include "paimon/common/utils/string_utils.h"
2122
#include "paimon/core/catalog/file_system_catalog.h"
2223
#include "paimon/core/core_options.h"
24+
#include "paimon/defs.h"
25+
#ifdef PAIMON_ENABLE_REST
26+
#include "paimon/rest/rest_catalog.h"
27+
#endif
2328

2429
namespace paimon {
2530

@@ -31,6 +36,22 @@ const char Catalog::DB_LOCATION_PROP[] = "location";
3136
Result<std::unique_ptr<Catalog>> Catalog::Create(const std::string& root_path,
3237
const std::map<std::string, std::string>& options,
3338
const std::shared_ptr<FileSystem>& file_system) {
39+
std::string metastore = "filesystem";
40+
auto metastore_iter = options.find(Options::METASTORE);
41+
if (metastore_iter != options.end()) {
42+
metastore = StringUtils::ToLowerCase(metastore_iter->second);
43+
}
44+
if (metastore == "rest") {
45+
#ifdef PAIMON_ENABLE_REST
46+
return RestCatalog::Create(root_path, options, file_system);
47+
#else
48+
return Status::NotImplemented(
49+
"the rest catalog requires building paimon with PAIMON_ENABLE_REST=ON");
50+
#endif
51+
}
52+
if (metastore != "filesystem") {
53+
return Status::Invalid("unsupported metastore: ", metastore);
54+
}
3455
PAIMON_ASSIGN_OR_RAISE(CoreOptions core_options, CoreOptions::FromMap(options, file_system));
3556
return std::make_unique<FileSystemCatalog>(core_options.GetFileSystem(), root_path);
3657
}

src/paimon/core/catalog/file_system_catalog.cpp

Lines changed: 1 addition & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -491,24 +491,6 @@ Status FileSystemCatalog::RenameTable(const Identifier& from_table, const Identi
491491
return Status::OK();
492492
}
493493

494-
namespace {
495-
SnapshotInfo::CommitKind ConvertCommitKind(Snapshot::CommitKind internal) {
496-
if (internal == Snapshot::CommitKind::Append()) {
497-
return SnapshotInfo::CommitKind::APPEND;
498-
}
499-
if (internal == Snapshot::CommitKind::Compact()) {
500-
return SnapshotInfo::CommitKind::COMPACT;
501-
}
502-
if (internal == Snapshot::CommitKind::Overwrite()) {
503-
return SnapshotInfo::CommitKind::OVERWRITE;
504-
}
505-
if (internal == Snapshot::CommitKind::Analyze()) {
506-
return SnapshotInfo::CommitKind::ANALYZE;
507-
}
508-
return SnapshotInfo::CommitKind::UNKNOWN;
509-
}
510-
} // namespace
511-
512494
Result<std::vector<SnapshotInfo>> FileSystemCatalog::ListSnapshots(
513495
const Identifier& identifier, const std::string& branch) const {
514496
PAIMON_ASSIGN_OR_RAISE(bool exists, TableExists(identifier));
@@ -523,20 +505,9 @@ Result<std::vector<SnapshotInfo>> FileSystemCatalog::ListSnapshots(
523505

524506
std::vector<SnapshotInfo> result;
525507
result.reserve(snapshots.size());
526-
527508
for (const auto& snap : snapshots) {
528-
SnapshotInfo info;
529-
info.snapshot_id = snap.Id();
530-
info.schema_id = snap.SchemaId();
531-
info.commit_user = snap.CommitUser();
532-
info.commit_kind = ConvertCommitKind(snap.GetCommitKind());
533-
info.time_millis = snap.TimeMillis();
534-
info.total_record_count = snap.TotalRecordCount();
535-
info.delta_record_count = snap.DeltaRecordCount();
536-
info.watermark = snap.Watermark();
537-
result.push_back(std::move(info));
509+
result.push_back(snap.ToSnapshotInfo());
538510
}
539-
540511
return result;
541512
}
542513

0 commit comments

Comments
 (0)