/src/rocksdb/env/unique_id_gen.h
Line | Count | Source (jump to first uncovered line) |
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 | 2 | 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, val; |
74 | 0 | GenerateNext(&ignore, &val); |
75 | 0 | return static_cast<T>(val); |
76 | 0 | } |
77 | | |
78 | 0 | uint64_t GetBaseUpper() const { return base_upper_; } |
79 | | |
80 | | private: |
81 | | uint64_t base_upper_; |
82 | | uint64_t base_lower_; |
83 | | std::atomic<uint64_t> counter_; |
84 | | int64_t saved_process_id_; |
85 | | }; |
86 | | |
87 | | // A unique id generator that should provide reasonable security against |
88 | | // predicting the output from previous outputs, but is NOT known to be |
89 | | // cryptographically secure. Unlike std::random_device, this is guaranteed |
90 | | // not to block once initialized. |
91 | | class ALIGN_AS(CACHE_LINE_SIZE) UnpredictableUniqueIdGen { |
92 | | public: |
93 | | // Initializes with random starting state (from several GenerateRawUniqueId) |
94 | 0 | UnpredictableUniqueIdGen() { Reset(); } |
95 | | // Re-initializes, but not thread safe |
96 | | void Reset(); |
97 | | |
98 | | // Generate next probabilistically unique value. Thread safe. Uses timing |
99 | | // information to add to the entropy pool. |
100 | | void GenerateNext(uint64_t* upper, uint64_t* lower); |
101 | | |
102 | | // Explicitly include given value for entropy pool instead of timing |
103 | | // information. |
104 | | void GenerateNextWithEntropy(uint64_t* upper, uint64_t* lower, |
105 | | uint64_t extra_entropy); |
106 | | |
107 | | #ifndef NDEBUG |
108 | | struct TEST_ZeroInitialized {}; |
109 | | explicit UnpredictableUniqueIdGen(TEST_ZeroInitialized); |
110 | | std::atomic<uint64_t>& TEST_counter() { return counter_; } |
111 | | #endif |
112 | | private: |
113 | | // 256 bit entropy pool |
114 | | std::array<std::atomic<uint64_t>, 4> pool_; |
115 | | // Counter to ensure unique hash inputs |
116 | | std::atomic<uint64_t> counter_; |
117 | | }; |
118 | | |
119 | | } // namespace ROCKSDB_NAMESPACE |