Coverage Report

Created: 2026-11-12 08:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/rocksdb/env/unique_id_gen.h
Line
Count
Source
1
//  Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
2
//  This source code is licensed under both the GPLv2 (found in the
3
//  COPYING file in the root directory) and Apache 2.0 License
4
//  (found in the LICENSE.Apache file in the root directory).
5
6
// This file is for functions that generate unique identifiers by
7
// (at least in part) by extracting novel entropy or sources of uniqueness
8
// from the execution environment. (By contrast, random.h is for algorithmic
9
// pseudorandomness.)
10
//
11
// These functions could eventually migrate to public APIs, such as in Env.
12
13
#pragma once
14
15
#include <array>
16
#include <atomic>
17
#include <cstdint>
18
#include <type_traits>
19
20
#include "port/port.h"
21
#include "rocksdb/rocksdb_namespace.h"
22
23
namespace ROCKSDB_NAMESPACE {
24
25
// Generates a new 128-bit identifier that is universally unique
26
// (with high probability) for each call. The result is split into
27
// two 64-bit pieces. This function has NOT been validated for use in
28
// cryptography.
29
//
30
// This is used in generating DB session IDs and by Env::GenerateUniqueId
31
// (used for DB IDENTITY) if the platform does not provide a generator of
32
// RFC 4122 UUIDs or fails somehow. (Set exclude_port_uuid=true if this
33
// function is used as a fallback for GenerateRfcUuid, because no need
34
// trying it again.)
35
void GenerateRawUniqueId(uint64_t* a, uint64_t* b,
36
                         bool exclude_port_uuid = false);
37
38
#ifndef NDEBUG
39
// A version of above with options for challenge testing
40
void TEST_GenerateRawUniqueId(uint64_t* a, uint64_t* b, bool exclude_port_uuid,
41
                              bool exclude_env_details,
42
                              bool exclude_random_device);
43
#endif
44
45
// Generates globally unique ids with lower probability of any collisions
46
// vs. each unique id being independently random (GenerateRawUniqueId).
47
// We call this "semi-structured" because between different
48
// SemiStructuredUniqueIdGen objects, the IDs are separated by random
49
// intervals (unstructured), but within a single SemiStructuredUniqueIdGen
50
// object, the generated IDs are trivially related (structured). See
51
// https://github.com/pdillinger/unique_id for how this improves probability
52
// of no collision. In short, if we have n SemiStructuredUniqueIdGen
53
// objects each generating m IDs, the first collision is expected at
54
// around n = sqrt(2^128 / m), equivalently n * sqrt(m) = 2^64,
55
// rather than n * m = 2^64 for fully random IDs.
56
class SemiStructuredUniqueIdGen {
57
 public:
58
  // Initializes with random starting state (from GenerateRawUniqueId)
59
4
  SemiStructuredUniqueIdGen() { Reset(); }
60
  // Re-initializes, but not thread safe
61
  void Reset();
62
63
  // Assuming no fork(), `lower` is guaranteed unique from one call
64
  // to the next (thread safe).
65
  void GenerateNext(uint64_t* upper, uint64_t* lower);
66
67
  // For generating smaller values. Will cycle through all the possibilities
68
  // before repeating.
69
  template <typename T>
70
0
  T GenerateNext() {
71
0
    static_assert(sizeof(T) <= sizeof(uint64_t));
72
0
    static_assert(std::is_integral_v<T>);
73
0
    uint64_t ignore;
74
0
    uint64_t val;
75
0
    GenerateNext(&ignore, &val);
76
0
    return static_cast<T>(val);
77
0
  }
78
79
0
  uint64_t GetBaseUpper() const { return base_upper_; }
80
81
 private:
82
  uint64_t base_upper_;
83
  uint64_t base_lower_;
84
  std::atomic<uint64_t> counter_;
85
  int64_t saved_process_id_;
86
};
87
88
// A unique id generator that should provide reasonable security against
89
// predicting the output from previous outputs, but is NOT known to be
90
// cryptographically secure. Unlike std::random_device, this is guaranteed
91
// not to block once initialized.
92
class ALIGN_AS(CACHE_LINE_SIZE) UnpredictableUniqueIdGen {
93
 public:
94
  // Initializes with random starting state (from several GenerateRawUniqueId)
95
0
  UnpredictableUniqueIdGen() { Reset(); }
96
  // Re-initializes, but not thread safe
97
  void Reset();
98
99
  // Generate next probabilistically unique value. Thread safe. Uses timing
100
  // information to add to the entropy pool.
101
  void GenerateNext(uint64_t* upper, uint64_t* lower);
102
103
  // Explicitly include given value for entropy pool instead of timing
104
  // information.
105
  void GenerateNextWithEntropy(uint64_t* upper, uint64_t* lower,
106
                               uint64_t extra_entropy);
107
108
#ifndef NDEBUG
109
  struct TEST_ZeroInitialized {};
110
  explicit UnpredictableUniqueIdGen(TEST_ZeroInitialized);
111
  std::atomic<uint64_t>& TEST_counter() { return counter_; }
112
#endif
113
 private:
114
  // 256 bit entropy pool
115
  std::array<std::atomic<uint64_t>, 4> pool_;
116
  // Counter to ensure unique hash inputs
117
  std::atomic<uint64_t> counter_;
118
};
119
120
}  // namespace ROCKSDB_NAMESPACE