Skip to content

Commit

Permalink
Remove random_label in favor of uuid. (#4709)
Browse files Browse the repository at this point in the history
The random label work broke the python tests because it can generate the
same URI under certain conditions.

---
TYPE: NO_HISTORY
DESC: Remove random_label in favor of uuid.
  • Loading branch information
KiterLuc authored Feb 9, 2024
1 parent 17bcc85 commit 2f03f0c
Show file tree
Hide file tree
Showing 12 changed files with 388 additions and 10 deletions.
1 change: 1 addition & 0 deletions tiledb/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ set(TILEDB_CORE_SOURCES
${TILEDB_CORE_INCLUDE_DIR}/tiledb/sm/misc/tdb_time.cc
${TILEDB_CORE_INCLUDE_DIR}/tiledb/sm/misc/types.cc
${TILEDB_CORE_INCLUDE_DIR}/tiledb/sm/misc/utils.cc
${TILEDB_CORE_INCLUDE_DIR}/tiledb/sm/misc/uuid.cc
${TILEDB_CORE_INCLUDE_DIR}/tiledb/sm/misc/win_constants.cc
${TILEDB_CORE_INCLUDE_DIR}/tiledb/sm/query/ast/query_ast.cc
${TILEDB_CORE_INCLUDE_DIR}/tiledb/sm/query/deletes_and_updates/deletes_and_updates.cc
Expand Down
1 change: 1 addition & 0 deletions tiledb/sm/array/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ commence(object_library array)
baseline
fragment
generic_tile_io
uuid
vfs
)
if(TILEDB_STATS)
Expand Down
5 changes: 3 additions & 2 deletions tiledb/sm/array_schema/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ commence(object_library attribute)
constants
filter_pipeline
range
stringx)
stringx
uuid)
conclude(object_library)

#
Expand All @@ -62,7 +63,7 @@ conclude(object_library)
#
commence(object_library enumeration)
this_target_sources(enumeration.cc)
this_target_object_libraries(buffer constants seedable_global_PRNG)
this_target_object_libraries(buffer constants uuid)
conclude(object_library)

#
Expand Down
8 changes: 5 additions & 3 deletions tiledb/sm/array_schema/enumeration.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
#include <iostream>
#include <sstream>

#include "tiledb/common/random/random_label.h"
#include "tiledb/sm/misc/uuid.h"

#include "enumeration.h"

Expand Down Expand Up @@ -71,8 +71,10 @@ Enumeration::Enumeration(
}

if (path_name_.empty()) {
path_name_ = "__" + tiledb::common::random_label() + "_" +
std::to_string(constants::enumerations_version);
std::string tmp_uuid;
throw_if_not_ok(uuid::generate_uuid(&tmp_uuid, false));
path_name_ =
"__" + tmp_uuid + "_" + std::to_string(constants::enumerations_version);
}

if (path_name.find("/") != std::string::npos) {
Expand Down
16 changes: 16 additions & 0 deletions tiledb/sm/misc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,22 @@ commence(object_library time)
this_target_sources(tdb_time.cc)
conclude(object_library)

#
# `uuid` object library
#
commence(object_library uuid)
this_target_sources(uuid.cc)
this_target_object_libraries(baseline)
if(WIN32)
this_target_link_libraries(rpcrt4)
else()
find_package(OpenSSL_EP REQUIRED)
this_target_link_libraries(OpenSSL::Crypto)
endif()
conclude(object_library)

add_test_subdirectory()

#
# `mgc_dict.*` tests are declared in this directory for the moment.
#
Expand Down
3 changes: 2 additions & 1 deletion tiledb/sm/misc/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
include(unit_test)

commence(unit_test misc)
this_target_object_libraries(math)
this_target_object_libraries(math uuid)
this_target_link_libraries(tiledb_test_support_lib)
# change to `this_target_include_directories` when available
target_include_directories(unit_misc PRIVATE "${CMAKE_SOURCE_DIR}")
Expand All @@ -36,5 +36,6 @@ commence(unit_test misc)
unit_hilbert.cc
unit_integral_type_casts.cc
unit_math.cc
unit_uuid.cc
)
conclude(unit_test)
34 changes: 34 additions & 0 deletions tiledb/sm/misc/test/compile_uuid_main.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/**
* @file compile_uuid_main.cc
*
* @section LICENSE
*
* The MIT License
*
* @copyright Copyright (c) 2021 TileDB, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#include "../uuid.h"

int main() {
(void)tiledb::sm::uuid::generate_uuid(nullptr, false);
return 0;
}
87 changes: 87 additions & 0 deletions tiledb/sm/misc/test/unit_uuid.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/**
* @file unit_uuid.cc
*
* @section LICENSE
*
* The MIT License
*
* @copyright Copyright (c) 2018-2022 TileDB, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @section DESCRIPTION
*
* Tests the UUID utility functions.
*/

#include <test/support/tdb_catch.h>
#include <set>
#include <thread>
#include <vector>

#include "tiledb/sm/global_state/global_state.h"
#include "tiledb/sm/misc/uuid.h"

using namespace tiledb::sm;

std::mutex catch2_macro_mutex;

// A thread-safe variant of the REQUIRE macro.
#define REQUIRE_SAFE(a) \
{ \
std::lock_guard<std::mutex> lock(catch2_macro_mutex); \
REQUIRE(a); \
}

void cancel_all_tasks(StorageManager*) {
}

TEST_CASE("UUID: Test generate", "[uuid]") {
SECTION("- Serial") {
std::string uuid0, uuid1, uuid2;
REQUIRE(uuid::generate_uuid(&uuid0).ok());
REQUIRE(uuid0.length() == 36);
REQUIRE(uuid::generate_uuid(&uuid1).ok());
REQUIRE(uuid1.length() == 36);
REQUIRE(uuid0 != uuid1);

REQUIRE(uuid::generate_uuid(&uuid2, false).ok());
REQUIRE(uuid2.length() == 32);
}

SECTION("- Threaded") {
const unsigned nthreads = 20;
std::vector<std::string> uuids(nthreads);
std::vector<std::thread> threads;
for (unsigned i = 0; i < nthreads; i++) {
threads.emplace_back([&uuids, i]() {
std::string& uuid = uuids[i];
REQUIRE_SAFE(uuid::generate_uuid(&uuid).ok());
REQUIRE_SAFE(uuid.length() == 36);
});
}
for (auto& t : threads) {
t.join();
}
// Check uniqueness
std::set<std::string> uuid_set;
uuid_set.insert(uuids.begin(), uuids.end());
REQUIRE(uuid_set.size() == uuids.size());
}
}
174 changes: 174 additions & 0 deletions tiledb/sm/misc/uuid.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
/**
* @file uuid.cc
*
* @section LICENSE
*
* The MIT License
*
* @copyright Copyright (c) 2018-2023 TileDB, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @section DESCRIPTION
*
* This file defines a platform-independent UUID generator.
*/

#include <mutex>
#include <vector>

#include "tiledb/sm/misc/uuid.h"

#ifdef _WIN32
#include <Rpc.h>
#else
#include <openssl/err.h>
#include <openssl/rand.h>
#include <cstdio>
#endif

using namespace tiledb::common;

namespace tiledb::sm::uuid {

/** Mutex to guard UUID generation. */
static std::mutex uuid_mtx;

#ifdef _WIN32

/**
* Generate a UUID using Win32 RPC API.
*/
Status generate_uuid_win32(std::string* uuid_str) {
if (uuid_str == nullptr)
return Status_UtilsError("Null UUID string argument");

UUID uuid;
RPC_STATUS rc = UuidCreate(&uuid);
if (rc != RPC_S_OK)
return Status_UtilsError("Unable to generate Win32 UUID: creation error");

char* buf = nullptr;
rc = UuidToStringA(&uuid, reinterpret_cast<RPC_CSTR*>(&buf));
if (rc != RPC_S_OK)
return Status_UtilsError(
"Unable to generate Win32 UUID: string conversion error");

*uuid_str = std::string(buf);

rc = RpcStringFreeA(reinterpret_cast<RPC_CSTR*>(&buf));
if (rc != RPC_S_OK)
return Status_UtilsError("Unable to generate Win32 UUID: free error");

return Status::Ok();
}

#else

/**
* Generate a UUID using OpenSSL.
*
* Initially from: https://gist.github.com/kvelakur/9069c9896577c3040030
* "Generating a Version 4 UUID using OpenSSL"
*/
Status generate_uuid_openssl(std::string* uuid_str) {
if (uuid_str == nullptr)
return Status_UtilsError("Null UUID string argument");

union {
struct {
uint32_t time_low;
uint16_t time_mid;
uint16_t time_hi_and_version;
uint8_t clk_seq_hi_res;
uint8_t clk_seq_low;
uint8_t node[6];
};
uint8_t __rnd[16];
} uuid;

int rc = RAND_bytes(uuid.__rnd, sizeof(uuid));
if (rc < 1) {
char err_msg[256];
ERR_error_string_n(ERR_get_error(), err_msg, sizeof(err_msg));
return Status_UtilsError(
"Cannot generate random bytes with OpenSSL: " + std::string(err_msg));
}

// Refer Section 4.2 of RFC-4122
// https://tools.ietf.org/html/rfc4122#section-4.2
uuid.clk_seq_hi_res = (uint8_t)((uuid.clk_seq_hi_res & 0x3F) | 0x80);
uuid.time_hi_and_version =
(uint16_t)((uuid.time_hi_and_version & 0x0FFF) | 0x4000);

// Format the UUID as a string.
char buf[128];
rc = snprintf(
buf,
sizeof(buf),
"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
uuid.time_low,
uuid.time_mid,
uuid.time_hi_and_version,
uuid.clk_seq_hi_res,
uuid.clk_seq_low,
uuid.node[0],
uuid.node[1],
uuid.node[2],
uuid.node[3],
uuid.node[4],
uuid.node[5]);

if (rc < 0)
return Status_UtilsError("Error formatting UUID string");

*uuid_str = std::string(buf);

return Status::Ok();
}

#endif

Status generate_uuid(std::string* uuid, bool hyphenate) {
if (uuid == nullptr)
return Status_UtilsError("Null UUID string argument");

std::string uuid_str;
{
// OpenSSL is not threadsafe, so grab a lock here. We are locking in the
// Windows case as well just to be careful.
std::unique_lock<std::mutex> lck(uuid_mtx);
#ifdef _WIN32
RETURN_NOT_OK(generate_uuid_win32(&uuid_str));
#else
RETURN_NOT_OK(generate_uuid_openssl(&uuid_str));
#endif
}

uuid->clear();
for (unsigned i = 0; i < uuid_str.length(); i++) {
if (uuid_str[i] == '-' && !hyphenate)
continue;
uuid->push_back(uuid_str[i]);
}

return Status::Ok();
}

} // namespace tiledb::sm::uuid
Loading

0 comments on commit 2f03f0c

Please sign in to comment.