Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 12 additions & 9 deletions cmake/modules/SearchInstalledSoftware.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -937,6 +937,13 @@ if (uring)
endif()
endif()

#---Check for libuuid (used by TUUID for cross-process-unique UUIDv1 generation,
# and by the DAOS backend)---------------------------------------------------
if(NOT WIN32)
message(STATUS "Looking for libuuid")
find_package(libuuid)
endif()

#---Check for DAOS----------------------------------------------------------------
if (daos AND daos_mock)
message(FATAL_ERROR "Options `daos` and `daos_mock` are mutually exclusive; only one of them should be specified.")
Expand All @@ -946,16 +953,12 @@ if (testing AND NOT daos AND NOT WIN32)
endif()

if (daos OR daos_mock)
message(STATUS "Looking for libuuid")
if(fail-on-missing)
if(fail-on-missing AND NOT libuuid_FOUND)
find_package(libuuid REQUIRED)
else()
find_package(libuuid)
if(NOT libuuid_FOUND)
message(STATUS "libuuid not found. Disabling DAOS support")
set(daos OFF CACHE BOOL "Disabled (libuuid not found)" FORCE)
set(daos_mock OFF CACHE BOOL "Disabled (libuuid not found)" FORCE)
endif()
elseif(NOT libuuid_FOUND)
message(STATUS "libuuid not found. Disabling DAOS support")
set(daos OFF CACHE BOOL "Disabled (libuuid not found)" FORCE)
set(daos_mock OFF CACHE BOOL "Disabled (libuuid not found)" FORCE)
endif()
endif()
if (daos)
Expand Down
8 changes: 8 additions & 0 deletions core/base/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,14 @@ if(ROOT_NEED_STDCXXFS)
target_link_libraries(Core PRIVATE stdc++fs)
endif()

# Use libuuid's uuid_generate_time() in TUUID when available so that concurrent
# processes on the same host coordinate their clock sequence and cannot collide
# within the same 100ns tick. See root-project/root#22015.
if(libuuid_FOUND)
target_link_libraries(Core PRIVATE uuid::uuid)
target_compile_definitions(Core PRIVATE R__HAS_LIBUUID)
endif()

# This code about the LIB_CORE_NAME define is important for TROOT::GetSharedLibDir()
# On Linux, dl_iterate_phdr reports loaded libraries by their SONAME
# (e.g. libCore.so.6.38), not their full filename (libCore.so.6.38.02).
Expand Down
36 changes: 27 additions & 9 deletions core/base/src/TUUID.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,12 @@ originally used in the Network Computing System (NCS) and
later in the Open Software Foundation's (OSF) Distributed Computing
Environment (DCE).

\note In the way this UUID is constructed, when used outside of
their original concept (NCS), they are actually not Globally unique
and indeed multiple distinct concurrent processes are actually likely
to generate the same UUID. Technically this is because the UUID is
constructed only from the node information and time information.
To make a globally unique number, this needs to be combined with
TProcessUUID.
\note When ROOT is built against `libuuid` (the default on Unix when
it is found at configure time), generation is delegated to
`uuid_generate_time()`, which coordinates the clock sequence across
processes on the same host. Without `libuuid` (e.g. on Windows) the
fallback generator only coordinates within a single process, so
concurrent processes on the same host can produce identical UUIDs.

Structure of universal unique IDs (UUIDs).

Expand Down Expand Up @@ -144,13 +143,31 @@ system clock catches up.
#include <netinet/in.h>
#endif
#include <chrono>

#ifdef R__HAS_LIBUUID
#include <uuid/uuid.h>
#endif

////////////////////////////////////////////////////////////////////////////////
/// Create a UUID.
/// Create a UUID. See the class docs for the libuuid vs. fallback distinction.

TUUID::TUUID()
{
#ifdef R__HAS_LIBUUID
uuid_t buf;
uuid_generate_time(buf);
// libuuid writes RFC 4122 v1 UUIDs in network byte order:
// bytes 0-3 = time_low, 4-5 = time_mid, 6-7 = time_hi_and_version,
// 8 = clock_seq_hi_and_reserved, 9 = clock_seq_low, 10-15 = node.
fTimeLow = (UInt_t(buf[0]) << 24) | (UInt_t(buf[1]) << 16) | (UInt_t(buf[2]) << 8) | UInt_t(buf[3]);
fTimeMid = static_cast<UShort_t>((UShort_t(buf[4]) << 8) | UShort_t(buf[5]));
fTimeHiAndVersion = static_cast<UShort_t>((UShort_t(buf[6]) << 8) | UShort_t(buf[7]));
fClockSeqHiAndReserved = buf[8];
fClockSeqLow = buf[9];
for (int i = 0; i < 6; ++i)
fNode[i] = buf[10 + i];
fUUIDIndex = 1 << 30;
return;
#else
TTHREAD_TLS(uuid_time_t) time_last;
TTHREAD_TLS(UShort_t) clockseq(0);
TTHREAD_TLS(Bool_t) firstTime(kTRUE);
Expand Down Expand Up @@ -189,6 +206,7 @@ TUUID::TUUID()

time_last = timestamp;
fUUIDIndex = 1<<30;
#endif
}

////////////////////////////////////////////////////////////////////////////////
Expand Down