Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ARROW-9318: [C++] Parquet encryption key management #8023

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
121 commits
Select commit Hold shift + click to select a range
d060f21
RemoteKmsClient class
thamht4190 Jul 15, 2020
93fb87a
fix build issue
thamht4190 Jul 21, 2020
4c22208
TwoLevelCacheWithExpiration class
thamht4190 Jul 22, 2020
a35c8bb
KeyEncryptionKey class
thamht4190 Jul 22, 2020
cb80ada
KmsClientCache in KeyToolkit
thamht4190 Jul 22, 2020
518b0d0
HadoopFSKeyMaterialStore class
thamht4190 Jul 23, 2020
c3ae5a0
some compile fix
thamht4190 Jul 27, 2020
9d6cac2
KeyMetadata & KeyMaterial
thamht4190 Jul 27, 2020
ec0faf1
FileKeyWrapper
thamht4190 Jul 27, 2020
329f55e
some minor fix
thamht4190 Jul 30, 2020
bf562f7
properties driven (encryption)
thamht4190 Jul 30, 2020
95d12ed
remove HadoopFSKeyMaterialStore
thamht4190 Aug 2, 2020
df41a60
use KeyAccessToken class instead of a string
thamht4190 Aug 2, 2020
bad8a20
remove hadoop config
thamht4190 Aug 2, 2020
9c6ec65
InMemoryKms
thamht4190 Aug 3, 2020
6ecf307
fix issue
thamht4190 Aug 4, 2020
8de430f
FileKeyUpwrapper
thamht4190 Aug 4, 2020
6211f47
fix issue
thamht4190 Aug 6, 2020
398c011
add unit test
thamht4190 Aug 6, 2020
cc1337c
some refinement
thamht4190 Aug 9, 2020
a937848
group common code in unit test for encryption
thamht4190 Aug 9, 2020
4e43f67
some refinement on unit tests
thamht4190 Aug 10, 2020
166e203
add comments
thamht4190 Aug 10, 2020
95a348e
fix issue with mixed wrap_locally
thamht4190 Aug 11, 2020
4802ac4
use std::string instead of std::vector<uint8_t>
thamht4190 Aug 13, 2020
23ad23b
add VaultClient as an example of RemoteKmsClient
thamht4190 Aug 20, 2020
43a6bf2
remove VaultClient since it depends on boost::asio which is not avail…
thamht4190 Aug 22, 2020
2e4ffff
add PARQUET_EXPORT for InMemoryKms
thamht4190 Aug 22, 2020
de5bf5b
add const back to KeyRetriever::GetKey()
thamht4190 Aug 24, 2020
39ab9f0
remove members of FileKeyMaterialStore
thamht4190 Aug 24, 2020
a9589cd
use cache_entry_lifetime with unit
thamht4190 Aug 24, 2020
cd94027
use KeyWithMasterId from key_toolkit.h and remove private FileKeyUnwr…
thamht4190 Aug 24, 2020
a884d2f
some style fix
thamht4190 Aug 24, 2020
f575bba
use camel case for constexpt char[]
thamht4190 Aug 26, 2020
56a028a
add some comments
thamht4190 Aug 28, 2020
aebc6e2
move SplitString() method to arrow/util/string.h
thamht4190 Aug 28, 2020
5163c52
fix compile issue: use constexpr const char[]
thamht4190 Aug 29, 2020
68f38ed
remove default constructor of KeyEncryptionKey, add comment
thamht4190 Aug 29, 2020
414f8ff
use std::string::data()
thamht4190 Aug 29, 2020
bd1616d
fix compile issue conversion from 'size_t' to 'int'
thamht4190 Aug 29, 2020
d97d9aa
rename in_memory_kms.h/cc to test_in_memory_kms.h/cc, rename InMemory…
thamht4190 Aug 29, 2020
2bd4b56
update comment in key_metadata.h
thamht4190 Aug 29, 2020
70e4ecc
use arrow::util::variant at KeyMetadata class
thamht4190 Aug 29, 2020
20622a0
make KeyWithMasterId members const
thamht4190 Sep 3, 2020
772c1dc
use std::unordered_map instead of std::map
thamht4190 Sep 3, 2020
ba933f6
stylish fix
thamht4190 Sep 3, 2020
f81d2a9
use std::unordered_map instead of std::map (2)
thamht4190 Sep 5, 2020
0dc4b32
create json utility to parse and serialize a json object
thamht4190 Sep 8, 2020
9c2e2ae
edit comment
thamht4190 Sep 10, 2020
58195d7
throw an exception if there is a KmsClientFactory registered
thamht4190 Sep 10, 2020
1286379
key management tests write files to a temporary directory
thamht4190 Sep 11, 2020
ce5fa68
move ExpiringCacheEntry class into key_toolkit_internal.h
thamht4190 Sep 11, 2020
9a1e4d3
KeyToolkit as a member of PropertiesDrivenCryptoFactory class
thamht4190 Sep 11, 2020
ddf943c
fix unit test and doxygen
thamht4190 Sep 11, 2020
a932723
move EncryptKeyLocally()/DecryptKeyLocally() to key_toolkit_internal
thamht4190 Sep 11, 2020
8bc599b
make TwoLevelCacheWithExpiration thread-safe
thamht4190 Sep 11, 2020
6430add
missing key_toolkit_internal.cc
thamht4190 Sep 11, 2020
b27e73a
remove ambigious current version in a comment
thamht4190 Sep 11, 2020
1adcd33
use arrow::util::Mutex instread of std::mutex
thamht4190 Sep 11, 2020
f1ba825
include arrow/json/rapidjson_defs.h
thamht4190 Sep 11, 2020
1c0db46
add API to clear cache into PropertiesDrivenCryptoFactory class
thamht4190 Sep 15, 2020
f1b1c43
move KeyWithMasterId to key_toolkit_internal
thamht4190 Sep 15, 2020
2cacbe5
create parquet/encryption folder for encryption sources
thamht4190 Sep 15, 2020
5358ebd
try fixing warning decorated name too long C4503
thamht4190 Sep 15, 2020
d8d33f4
install src/parquet/encryption/*.h as public headers
thamht4190 Sep 16, 2020
9a13021
fix issue with asan
thamht4190 Sep 16, 2020
273952f
unit test for KeyMetadata
thamht4190 Sep 16, 2020
a5f5377
fix build issue with src/parquet/encryption/encryption_internal_nossl.cc
thamht4190 Sep 17, 2020
f2d1bdc
Revert "unit test for KeyMetadata" - KeyMetadata is not a public class
thamht4190 Sep 17, 2020
96d1380
add back "unit test for KeyMetadata", with PARQUET_EXPORT
thamht4190 Sep 16, 2020
716a2ae
unit test for FileKeyWrapper and FileKeyUnwrapper
thamht4190 Sep 17, 2020
216fa4a
Add ConcurrentMap template class and use it in cache
thamht4190 Sep 19, 2020
252e577
Merge remote-tracking branch 'upstream/master' into arrow-9318-encryp…
thamht4190 Sep 22, 2020
f31111e
fix SIGSEGV issue with mutex
thamht4190 Sep 22, 2020
ba9c03a
make RemoteKmsClient thread safe, with some more comments
thamht4190 Sep 22, 2020
ad804f0
unit test for TwoLevelCacheWithExpiration
thamht4190 Sep 23, 2020
53e3c29
remove wrap_locally option from Encryption/DecryptionConfiguration
thamht4190 Sep 23, 2020
f2929fe
Add more test cases into encryption_key_management_test.cc
thamht4190 Sep 24, 2020
2591c04
Update comments with default values in the public APIs
thamht4190 Sep 24, 2020
21e6f07
make unit test of TwoLevelCacheWithExpiration passed
thamht4190 Sep 24, 2020
6574e18
Merge branch 'master' of https://github.com/apache/arrow into arrow-9…
thamht4190 Sep 26, 2020
c528633
fix build issue on msvc
thamht4190 Sep 26, 2020
c6189b0
use ParquetException instead of DCHECK when column_keys.empty()
thamht4190 Sep 26, 2020
3dcb9a0
add unit tests for Encryption/DecryptionConfiguration
thamht4190 Sep 26, 2020
3239761
rename a method name: ConcurrentMap<V>::GetOrAssignIfNotExist
thamht4190 Sep 26, 2020
3171756
some minor fixes
thamht4190 Sep 26, 2020
7fe15c3
remove ARROW_EXPORT from concurrent_map.h
thamht4190 Sep 28, 2020
e5197c3
use std::move() in KeyEncryptionKey constructor
thamht4190 Oct 1, 2020
cfa2db6
some minor style changes
thamht4190 Oct 1, 2020
7c975f9
use seconds instead of ms for cache lifetime
thamht4190 Oct 1, 2020
5e5142a
some style fix, remove some include headers in test_encryption_util.h
thamht4190 Oct 1, 2020
c6f5e3d
add mutex into KeyAccessToken, and remove SetDefaultIfEmpty() method
thamht4190 Oct 1, 2020
94fdfe9
change RemoteKmsClient to LocalWrapKmsClient
thamht4190 Oct 2, 2020
1a3371e
two-level cache: remove RemoveCacheEntriesForToken() and RemoveCacheE…
thamht4190 Oct 2, 2020
863156e
validate the length of master keys fetched from KMS server
thamht4190 Oct 2, 2020
eae9030
some changes in ConcurrentMap
thamht4190 Oct 6, 2020
c713b6f
SplitString() return std::vector<util::string_view>; add some unit tests
thamht4190 Oct 6, 2020
a3e36e8
use PIML in json/object_parser and json/object_writer
thamht4190 Oct 7, 2020
61bb78d
use forward declaration
thamht4190 Oct 7, 2020
cd6a577
add some comments
thamht4190 Oct 7, 2020
275675d
shorten encryption test using generic code
thamht4190 Oct 31, 2020
fb50816
remove Builder pattern from EncryptionConfiguration/DecryptionConfigu…
thamht4190 Oct 31, 2020
ad3e8db
Merge remote-tracking branch 'upstream/master' into arrow-9318-encryp…
thamht4190 Oct 31, 2020
b969e87
remove encryption_ prefix in file names
thamht4190 Feb 20, 2021
d0133b1
remove paraphase comment
thamht4190 Feb 20, 2021
f45915c
Merge remote-tracking branch 'upstream/master' into arrow-9318-encryp…
thamht4190 Feb 21, 2021
22e9d4a
only build key management tool if ARROW_JSON is ON
thamht4190 Feb 22, 2021
b80ff0c
Merge remote-tracking branch 'upstream/master' into arrow-9318-encryp…
thamht4190 Feb 23, 2021
258cd05
fix compile issue
thamht4190 Feb 23, 2021
8e28d43
fix compile issue (2)
thamht4190 Feb 24, 2021
d016457
fix compile issue (3)
thamht4190 Feb 24, 2021
c63f9a2
fix compile issue (4)
thamht4190 Feb 25, 2021
437b7b3
rename PropertiesDrivenCryptoFactory to CryptoFactory
thamht4190 Feb 25, 2021
3b92c32
add comment for CryptoFactory
thamht4190 Feb 25, 2021
273c390
fix warnings treated as errors
thamht4190 Feb 26, 2021
72c961d
fix warnings treated as errors (2)
thamht4190 Feb 26, 2021
c8c5aa2
fix warnings treated as errors
thamht4190 Feb 27, 2021
b06ab26
Some updates
pitrou Mar 10, 2021
4c108f0
Fix cast
pitrou Mar 10, 2021
c828b65
Merge branch 'master' into arrow-9318-encryption-key-management
pitrou Mar 11, 2021
48456d7
Hopefully fix Windows linking error
pitrou Mar 11, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions cpp/cmake_modules/ThirdpartyToolchain.cmake
Expand Up @@ -250,6 +250,10 @@ include_directories(SYSTEM "${THIRDPARTY_DIR}/flatbuffers/include")
# ----------------------------------------------------------------------
# Some EP's require other EP's

if(PARQUET_REQUIRE_ENCRYPTION)
set(ARROW_JSON ON)
endif()

if(ARROW_THRIFT)
set(ARROW_WITH_ZLIB ON)
endif()
Expand Down
2 changes: 2 additions & 0 deletions cpp/src/arrow/CMakeLists.txt
Expand Up @@ -459,6 +459,8 @@ if(ARROW_JSON)
json/chunked_builder.cc
json/chunker.cc
json/converter.cc
json/object_parser.cc
json/object_writer.cc
json/parser.cc
json/reader.cc)
endif()
Expand Down
9 changes: 5 additions & 4 deletions cpp/src/arrow/json/chunked_builder.h
Expand Up @@ -45,21 +45,22 @@ class ARROW_EXPORT ChunkedArrayBuilder {

/// Finish current task group and substitute a new one
virtual Status ReplaceTaskGroup(
const std::shared_ptr<internal::TaskGroup>& task_group) = 0;
const std::shared_ptr<arrow::internal::TaskGroup>& task_group) = 0;

protected:
explicit ChunkedArrayBuilder(const std::shared_ptr<internal::TaskGroup>& task_group)
explicit ChunkedArrayBuilder(
const std::shared_ptr<arrow::internal::TaskGroup>& task_group)
: task_group_(task_group) {}

std::shared_ptr<internal::TaskGroup> task_group_;
std::shared_ptr<arrow::internal::TaskGroup> task_group_;
};

/// create a chunked builder
///
/// if unexpected fields and promotion need to be handled, promotion_graph must be
/// non-null
ARROW_EXPORT Status MakeChunkedArrayBuilder(
const std::shared_ptr<internal::TaskGroup>& task_group, MemoryPool* pool,
const std::shared_ptr<arrow::internal::TaskGroup>& task_group, MemoryPool* pool,
const PromotionGraph* promotion_graph, const std::shared_ptr<DataType>& type,
std::shared_ptr<ChunkedArrayBuilder>* out);

Expand Down
7 changes: 4 additions & 3 deletions cpp/src/arrow/json/chunker.cc
Expand Up @@ -31,13 +31,14 @@
#include "arrow/util/string_view.h"

namespace arrow {
namespace json {

namespace rj = arrow::rapidjson;

using internal::make_unique;
using util::string_view;

namespace json {

namespace rj = arrow::rapidjson;

static size_t ConsumeWhitespace(string_view view) {
#ifdef RAPIDJSON_SIMD
auto data = view.data();
Expand Down
5 changes: 3 additions & 2 deletions cpp/src/arrow/json/converter.cc
Expand Up @@ -32,11 +32,12 @@
#include "arrow/util/value_parsing.h"

namespace arrow {
namespace json {

using internal::checked_cast;
using util::string_view;

namespace json {

template <typename... Args>
Status GenericConversionError(const DataType& type, Args&&... args) {
return Status::Invalid("Failed of conversion of JSON to ", type,
Expand Down Expand Up @@ -126,7 +127,7 @@ class NumericConverter : public PrimitiveConverter {

auto visit_valid = [&](string_view repr) {
value_type value;
if (!internal::ParseValue(numeric_type_, repr.data(), repr.size(), &value)) {
if (!arrow::internal::ParseValue(numeric_type_, repr.data(), repr.size(), &value)) {
return GenericConversionError(*out_type_, ", couldn't parse:", repr);
}

Expand Down
83 changes: 83 additions & 0 deletions cpp/src/arrow/json/object_parser.cc
@@ -0,0 +1,83 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

#include "arrow/json/object_parser.h"
#include "arrow/json/rapidjson_defs.h" // IWYU pragma: keep

#include <rapidjson/document.h>

namespace arrow {
namespace json {
namespace internal {

namespace rj = arrow::rapidjson;

class ObjectParser::Impl {
public:
Status Parse(arrow::util::string_view json) {
document_.Parse(reinterpret_cast<const rj::Document::Ch*>(json.data()),
static_cast<size_t>(json.size()));

if (document_.HasParseError()) {
return Status::Invalid("Json parse error (offset ", document_.GetErrorOffset(),
"): ", document_.GetParseError());
}
if (!document_.IsObject()) {
return Status::TypeError("Not a json object");
}
return Status::OK();
}

Result<std::string> GetString(const char* key) const {
if (!document_.HasMember(key)) {
return Status::KeyError("Key '", key, "' does not exist");
}
if (!document_[key].IsString()) {
return Status::TypeError("Key '", key, "' is not a string");
}
return document_[key].GetString();
}

Result<bool> GetBool(const char* key) const {
if (!document_.HasMember(key)) {
return Status::KeyError("Key '", key, "' does not exist");
}
if (!document_[key].IsBool()) {
return Status::TypeError("Key '", key, "' is not a boolean");
}
return document_[key].GetBool();
}

private:
rj::Document document_;
};

ObjectParser::ObjectParser() : impl_(new ObjectParser::Impl()) {}

ObjectParser::~ObjectParser() = default;

Status ObjectParser::Parse(arrow::util::string_view json) { return impl_->Parse(json); }

Result<std::string> ObjectParser::GetString(const char* key) const {
return impl_->GetString(key);
}

Result<bool> ObjectParser::GetBool(const char* key) const { return impl_->GetBool(key); }

} // namespace internal
} // namespace json
} // namespace arrow
49 changes: 49 additions & 0 deletions cpp/src/arrow/json/object_parser.h
@@ -0,0 +1,49 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

#pragma once

#include <memory>

#include "arrow/result.h"
#include "arrow/util/string_view.h"
#include "arrow/util/visibility.h"

namespace arrow {
namespace json {
namespace internal {

/// This class is a helper to parse a json object from a string.
/// It uses rapidjson::Document in implementation.
class ARROW_EXPORT ObjectParser {
thamht4190 marked this conversation as resolved.
Show resolved Hide resolved
public:
ObjectParser();
~ObjectParser();

Status Parse(arrow::util::string_view json);

Result<std::string> GetString(const char* key) const;
Result<bool> GetBool(const char* key) const;

private:
class Impl;
std::unique_ptr<Impl> impl_;
};

} // namespace internal
} // namespace json
} // namespace arrow
82 changes: 82 additions & 0 deletions cpp/src/arrow/json/object_writer.cc
@@ -0,0 +1,82 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

#include "arrow/json/object_writer.h"
#include "arrow/json/rapidjson_defs.h" // IWYU pragma: keep

#include <rapidjson/document.h>
#include <rapidjson/stringbuffer.h>
#include <rapidjson/writer.h>

namespace rj = arrow::rapidjson;

namespace arrow {
namespace json {
namespace internal {

class ObjectWriter::Impl {
public:
Impl() : root_(rj::kObjectType) {}

void SetString(arrow::util::string_view key, arrow::util::string_view value) {
rj::Document::AllocatorType& allocator = document_.GetAllocator();

rj::Value str_key(key.data(), allocator);
rj::Value str_value(value.data(), allocator);

root_.AddMember(str_key, str_value, allocator);
}

void SetBool(arrow::util::string_view key, bool value) {
rj::Document::AllocatorType& allocator = document_.GetAllocator();

rj::Value str_key(key.data(), allocator);

root_.AddMember(str_key, value, allocator);
}

std::string Serialize() {
rj::StringBuffer buffer;
rj::Writer<rj::StringBuffer> writer(buffer);
root_.Accept(writer);

return buffer.GetString();
}

private:
rj::Document document_;
rj::Value root_;
};

ObjectWriter::ObjectWriter() : impl_(new ObjectWriter::Impl()) {}

ObjectWriter::~ObjectWriter() = default;

void ObjectWriter::SetString(arrow::util::string_view key,
arrow::util::string_view value) {
impl_->SetString(key, value);
}

void ObjectWriter::SetBool(arrow::util::string_view key, bool value) {
impl_->SetBool(key, value);
}

std::string ObjectWriter::Serialize() { return impl_->Serialize(); }

} // namespace internal
} // namespace json
} // namespace arrow
48 changes: 48 additions & 0 deletions cpp/src/arrow/json/object_writer.h
@@ -0,0 +1,48 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

#pragma once

#include <memory>

#include "arrow/util/string_view.h"
#include "arrow/util/visibility.h"

namespace arrow {
namespace json {
namespace internal {

/// This class is a helper to serialize a json object to a string.
/// It uses rapidjson in implementation.
class ARROW_EXPORT ObjectWriter {
thamht4190 marked this conversation as resolved.
Show resolved Hide resolved
public:
ObjectWriter();
~ObjectWriter();

void SetString(arrow::util::string_view key, arrow::util::string_view value);
void SetBool(arrow::util::string_view key, bool value);

std::string Serialize();

private:
class Impl;
std::unique_ptr<Impl> impl_;
};

} // namespace internal
} // namespace json
} // namespace arrow
13 changes: 7 additions & 6 deletions cpp/src/arrow/json/parser.cc
Expand Up @@ -40,15 +40,16 @@
#include "arrow/visitor_inline.h"

namespace arrow {
namespace json {

namespace rj = arrow::rapidjson;

using internal::BitsetStack;
using internal::checked_cast;
using internal::make_unique;
using util::string_view;

namespace json {

namespace rj = arrow::rapidjson;

template <typename... T>
static Status ParseError(T&&... t) {
return Status::Invalid("JSON parse error: ", std::forward<T>(t)...);
Expand All @@ -73,8 +74,8 @@ const std::shared_ptr<const KeyValueMetadata>& Kind::Tag(Kind::type kind) {
return tags[kind];
}

static internal::Trie MakeFromTagTrie() {
internal::TrieBuilder builder;
static arrow::internal::Trie MakeFromTagTrie() {
arrow::internal::TrieBuilder builder;
for (auto kind : {Kind::kNull, Kind::kBoolean, Kind::kNumber, Kind::kString,
Kind::kArray, Kind::kObject}) {
DCHECK_OK(builder.Append(Kind::Name(kind)));
Expand All @@ -85,7 +86,7 @@ static internal::Trie MakeFromTagTrie() {
}

Kind::type Kind::FromTag(const std::shared_ptr<const KeyValueMetadata>& tag) {
static internal::Trie name_to_kind = MakeFromTagTrie();
static arrow::internal::Trie name_to_kind = MakeFromTagTrie();
DCHECK_NE(tag->FindKey("json_kind"), -1);
util::string_view name = tag->value(tag->FindKey("json_kind"));
DCHECK_NE(name_to_kind.Find(name), -1);
Expand Down