Skip to content

Commit 34aa381

Browse files
committed
feat(shared-shredding): Expose shared-shredding utilities
1 parent ffbda4f commit 34aa381

15 files changed

Lines changed: 481 additions & 98 deletions
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*
2+
* Copyright 2026-present Alibaba Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#pragma once
18+
19+
#include <cstdint>
20+
#include <map>
21+
#include <memory>
22+
#include <set>
23+
#include <string>
24+
#include <vector>
25+
26+
#include "paimon/arrow/abi.h"
27+
#include "paimon/result.h"
28+
#include "paimon/status.h"
29+
#include "paimon/visibility.h"
30+
31+
namespace paimon {
32+
33+
/// Parsed file-level meta for one shared-shredding MAP column.
34+
struct PAIMON_EXPORT MapSharedShreddingFieldMeta {
35+
/// field_name -> field_id
36+
std::map<std::string, int32_t> name_to_id;
37+
/// field_id -> set of physical column indices S
38+
std::map<int32_t, std::vector<int32_t>> field_to_columns;
39+
/// Set of field_ids that ever spilled into __overflow
40+
std::set<int32_t> overflow_field_set;
41+
/// Number of physical columns K in this file
42+
int32_t num_columns = 0;
43+
/// Maximum row width observed in this file
44+
int32_t max_row_width = 0;
45+
46+
bool operator==(const MapSharedShreddingFieldMeta& other) const {
47+
if (this == &other) {
48+
return true;
49+
}
50+
return name_to_id == other.name_to_id && field_to_columns == other.field_to_columns &&
51+
overflow_field_set == other.overflow_field_set && num_columns == other.num_columns &&
52+
max_row_width == other.max_row_width;
53+
}
54+
};
55+
56+
class PAIMON_EXPORT MapSharedShreddingSchemaUtils {
57+
public:
58+
MapSharedShreddingSchemaUtils() = delete;
59+
~MapSharedShreddingSchemaUtils() = delete;
60+
61+
/// Converts a logical schema to a physical schema by replacing shredding MAP columns
62+
/// with their physical Struct representation.
63+
/// @param logical_schema The original Arrow C schema with MAP<STRING, T> columns.
64+
/// Ownership of schema resources is transferred to this method.
65+
/// @param field_to_num_columns Map from field name to its physical column count K.
66+
/// Each shredding column can have its own width.
67+
/// @return The exported Arrow C schema for file writing.
68+
static Result<std::unique_ptr<::ArrowSchema>> LogicalToPhysicalSchema(
69+
std::unique_ptr<::ArrowSchema> logical_schema,
70+
const std::map<std::string, int32_t>& field_to_num_columns);
71+
72+
/// Attaches shared-shredding metadata to fields in a physical schema.
73+
/// @param physical_schema The Arrow C physical schema whose fields should receive metadata.
74+
/// Ownership of schema resources is transferred to this method.
75+
/// @param field_name_to_meta Map from physical field name to its shared-shredding metadata.
76+
/// @param compression Compression codec name for field_dict serialization.
77+
/// @return A new Arrow C schema with shared-shredding metadata attached to matching fields.
78+
static Result<std::unique_ptr<::ArrowSchema>> AttachMetadataToSchema(
79+
std::unique_ptr<::ArrowSchema> physical_schema,
80+
const std::map<std::string, MapSharedShreddingFieldMeta>& field_name_to_meta,
81+
const std::string& compression);
82+
83+
/// Extracts shared-shredding metadata from a named field in a physical schema.
84+
/// @param physical_schema The Arrow C physical schema that contains the target field.
85+
/// Ownership of schema resources is transferred to this method.
86+
/// @param field_name The physical field name whose metadata should be extracted.
87+
/// @param compression Compression codec name for field_dict deserialization.
88+
/// @return Parsed shared-shredding metadata for the field.
89+
static Result<MapSharedShreddingFieldMeta> ExtractMetadataFromField(
90+
std::unique_ptr<::ArrowSchema> physical_schema, const std::string& field_name,
91+
const std::string& compression);
92+
};
93+
94+
} // namespace paimon

src/paimon/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ set(PAIMON_COMMON_SRCS
139139
common/utils/crc32c.cpp
140140
common/utils/decimal_utils.cpp
141141
common/data/shredding/map_shared_shredding_utils.cpp
142+
common/data/shredding/map_shared_shredding_schema_utils.cpp
142143
common/data/shredding/map_shared_shredding_context.cpp
143144
common/data/shredding/map_shared_shredding_batch_converter.cpp
144145
common/data/shredding/map_shared_shredding_column_allocator.cpp
@@ -547,6 +548,7 @@ if(PAIMON_BUILD_TESTS)
547548
common/utils/threadsafe_queue_test.cpp
548549
common/utils/generic_lru_cache_test.cpp
549550
common/data/shredding/map_shared_shredding_utils_test.cpp
551+
common/data/shredding/map_shared_shredding_schema_utils_test.cpp
550552
common/data/shredding/map_shared_shredding_batch_converter_test.cpp
551553
common/data/shredding/lru_map_shared_shredding_column_allocator_test.cpp
552554
common/data/shredding/plain_map_shared_shredding_column_allocator_test.cpp

src/paimon/common/data/shredding/map_shared_shredding_batch_converter.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,9 @@ Result<std::shared_ptr<MapSharedShreddingBatchConverter>> MapSharedShreddingBatc
6565
const std::shared_ptr<MapSharedShreddingContext>& context, const CoreOptions& options,
6666
const std::shared_ptr<MemoryPool>& pool) {
6767
std::map<std::string, int32_t> field_to_num_columns = context->ComputeNextK();
68-
std::shared_ptr<arrow::Schema> physical_schema =
69-
MapSharedShreddingUtils::LogicalToPhysicalSchema(logical_schema, field_to_num_columns);
68+
PAIMON_ASSIGN_OR_RAISE(
69+
std::shared_ptr<arrow::Schema> physical_schema,
70+
MapSharedShreddingUtils::LogicalToPhysicalSchema(logical_schema, field_to_num_columns));
7071
std::vector<ColumnContext> contexts;
7172
std::vector<std::string> shredding_field_names;
7273
contexts.reserve(field_to_num_columns.size());

src/paimon/common/data/shredding/map_shared_shredding_file_reader_test.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,8 @@ class MapSharedShreddingFileReaderTest : public ::testing::Test {
7171
const MapSharedShreddingFieldMeta& meta) const {
7272
std::map<std::string, int32_t> field_to_num_columns = {{"tags", 2}};
7373
auto physical_schema =
74-
MapSharedShreddingUtils::LogicalToPhysicalSchema(logical_schema_, field_to_num_columns);
74+
MapSharedShreddingUtils::LogicalToPhysicalSchema(logical_schema_, field_to_num_columns)
75+
.value();
7576
auto metadata = std::make_shared<arrow::KeyValueMetadata>();
7677
EXPECT_OK(MapSharedShreddingUtils::SerializeMetadata(
7778
meta, MapSharedShreddingDefine::kDefaultDictCompression, metadata.get()));
@@ -458,8 +459,8 @@ TEST_F(MapSharedShreddingFileReaderTest, TestListValue) {
458459
meta.max_row_width = 3;
459460

460461
std::map<std::string, int32_t> field_to_num_columns = {{"tags", 2}};
461-
auto physical_schema =
462-
MapSharedShreddingUtils::LogicalToPhysicalSchema(logical_schema, field_to_num_columns);
462+
ASSERT_OK_AND_ASSIGN(auto physical_schema, MapSharedShreddingUtils::LogicalToPhysicalSchema(
463+
logical_schema, field_to_num_columns));
463464
auto metadata = std::make_shared<arrow::KeyValueMetadata>();
464465
ASSERT_OK(MapSharedShreddingUtils::SerializeMetadata(
465466
meta, MapSharedShreddingDefine::kDefaultDictCompression, metadata.get()));
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/*
2+
* Copyright 2026-present Alibaba Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include "paimon/data/shredding/map_shared_shredding_schema_utils.h"
18+
19+
#include "arrow/c/bridge.h"
20+
#include "arrow/type.h"
21+
#include "arrow/util/key_value_metadata.h"
22+
#include "fmt/format.h"
23+
#include "paimon/common/data/shredding/map_shared_shredding_utils.h"
24+
#include "paimon/common/utils/arrow/status_utils.h"
25+
26+
namespace paimon {
27+
28+
Result<std::unique_ptr<::ArrowSchema>> MapSharedShreddingSchemaUtils::LogicalToPhysicalSchema(
29+
std::unique_ptr<::ArrowSchema> logical_schema,
30+
const std::map<std::string, int32_t>& field_to_num_columns) {
31+
if (!logical_schema) {
32+
return Status::Invalid("logical schema is null");
33+
}
34+
PAIMON_ASSIGN_OR_RAISE_FROM_ARROW(std::shared_ptr<arrow::Schema> arrow_logical_schema,
35+
arrow::ImportSchema(logical_schema.get()));
36+
PAIMON_ASSIGN_OR_RAISE(std::shared_ptr<arrow::Schema> physical_schema,
37+
MapSharedShreddingUtils::LogicalToPhysicalSchema(arrow_logical_schema,
38+
field_to_num_columns));
39+
auto c_schema = std::make_unique<::ArrowSchema>();
40+
PAIMON_RETURN_NOT_OK_FROM_ARROW(arrow::ExportSchema(*physical_schema, c_schema.get()));
41+
return c_schema;
42+
}
43+
44+
Result<std::unique_ptr<::ArrowSchema>> MapSharedShreddingSchemaUtils::AttachMetadataToSchema(
45+
std::unique_ptr<::ArrowSchema> physical_schema,
46+
const std::map<std::string, MapSharedShreddingFieldMeta>& field_name_to_meta,
47+
const std::string& compression) {
48+
if (!physical_schema) {
49+
return Status::Invalid("physical schema is null");
50+
}
51+
PAIMON_ASSIGN_OR_RAISE_FROM_ARROW(std::shared_ptr<arrow::Schema> arrow_physical_schema,
52+
arrow::ImportSchema(physical_schema.get()));
53+
54+
arrow::FieldVector updated_fields = arrow_physical_schema->fields();
55+
for (const auto& [field_name, field_meta] : field_name_to_meta) {
56+
int32_t field_index = arrow_physical_schema->GetFieldIndex(field_name);
57+
if (field_index < 0) {
58+
return Status::Invalid(fmt::format(
59+
"Shared-shredding field '{}' not found in physical schema.", field_name));
60+
}
61+
62+
const auto& field = arrow_physical_schema->field(field_index);
63+
auto metadata = field->metadata() ? field->metadata()->Copy()
64+
: std::make_shared<arrow::KeyValueMetadata>();
65+
PAIMON_RETURN_NOT_OK(
66+
MapSharedShreddingUtils::SerializeMetadata(field_meta, compression, metadata.get()));
67+
updated_fields[field_index] = field->WithMetadata(metadata);
68+
}
69+
70+
auto updated_schema =
71+
arrow::schema(std::move(updated_fields), arrow_physical_schema->metadata());
72+
auto c_schema = std::make_unique<::ArrowSchema>();
73+
PAIMON_RETURN_NOT_OK_FROM_ARROW(arrow::ExportSchema(*updated_schema, c_schema.get()));
74+
return c_schema;
75+
}
76+
77+
Result<MapSharedShreddingFieldMeta> MapSharedShreddingSchemaUtils::ExtractMetadataFromField(
78+
std::unique_ptr<::ArrowSchema> physical_schema, const std::string& field_name,
79+
const std::string& compression) {
80+
if (!physical_schema) {
81+
return Status::Invalid("physical schema is null");
82+
}
83+
PAIMON_ASSIGN_OR_RAISE_FROM_ARROW(std::shared_ptr<arrow::Schema> arrow_physical_schema,
84+
arrow::ImportSchema(physical_schema.get()));
85+
const auto& field = arrow_physical_schema->GetFieldByName(field_name);
86+
if (!field) {
87+
return Status::Invalid(
88+
fmt::format("Shared-shredding field '{}' not found in physical schema.", field_name));
89+
}
90+
91+
auto metadata =
92+
field->metadata() ? field->metadata()->Copy() : std::shared_ptr<arrow::KeyValueMetadata>();
93+
return MapSharedShreddingUtils::DeserializeMetadata(metadata, compression);
94+
}
95+
96+
} // namespace paimon

0 commit comments

Comments
 (0)