ProvSQL C/C++ API
Adding support for provenance and uncertainty management to PostgreSQL databases
Loading...
Searching...
No Matches
MMappedUUIDHashTable.h
Go to the documentation of this file.
1/**
2 * @file MMappedUUIDHashTable.h
3 * @brief Open-addressing hash table mapping UUIDs to integers, backed by an mmap file.
4 *
5 * @c MMappedUUIDHashTable provides a persistent hash table that maps
6 * 128-bit UUID keys to sequential unsigned-long integers (used as gate
7 * indices into the @c MMappedVector of @c GateInformation). The table
8 * is stored in a memory-mapped file so that it survives PostgreSQL
9 * restarts and is accessible by multiple processes.
10 *
11 * Design constraints:
12 * - **Append-only**: elements can be added but never removed.
13 * - **Open addressing**: collisions are resolved by linear probing.
14 * - **Trivial hash**: the first 8 bytes of the UUID are reinterpreted as
15 * a 64-bit integer and taken modulo the table capacity. UUIDs are
16 * generated uniformly at random (version 4), so this is effectively
17 * uniform.
18 * - **Automatic growth**: when the load factor exceeds @c MAXIMUM_LOAD_FACTOR
19 * the table is doubled in size and rehashed.
20 *
21 * Access to the table from multiple processes is serialised via the
22 * ProvSQL LWLock in @c provsqlSharedState.
23 */
24#ifndef MMAPPED_UUID_HASH_TABLE_H
25#define MMAPPED_UUID_HASH_TABLE_H
26
27#include <cstddef>
28#include <cstdint>
29#include <utility>
30
31#include "MappedRegion.h"
32
33extern "C" {
34#include "provsql_utils.h"
35}
36
37/**
38 * @brief Persistent open-addressing hash table mapping UUIDs to integers.
39 */
41{
42/** @brief One slot in the hash table: a UUID key and its associated integer value. */
43struct value_t {
44 pg_uuid_t uuid; ///< Key
45 unsigned long value; ///< Associated integer (gate index), or 0 if slot is empty
46};
47
48/**
49 * @brief On-disk layout of the hash table stored in the mmap file.
50 *
51 * The header fields are followed by a flexible array of @c value_t slots.
52 */
53struct table_t {
54 /**
55 * @brief Compute the file size required for a table with @c 2^ls slots.
56 * @param ls Log2 of the desired slot count.
57 * @return Required file size in bytes.
58 */
59 static constexpr std::size_t sizeForLogSize(unsigned ls) {
60 return offsetof(table_t, t) + (1 << ls)*sizeof(value_t);
61 }
62 /**
63 * @brief Compute the log2 of the slot count from the file size.
64 * @param size File size in bytes.
65 * @return Log2 of the number of slots that fit in @p size.
66 */
67 static constexpr unsigned logSizeForSize(std::size_t size) {
68 size -= offsetof(table_t, t);
69 size /= sizeof(value_t);
70 size >>= 1;
71 unsigned log_size=0;
72 while(size) {
73 size >>= 1;
74 ++log_size;
75 }
76 return log_size;
77 }
78 /**
79 * @brief Maximum number of slots in the table (@c 2^log_size).
80 * @return Current capacity (number of available hash-table slots).
81 */
82 constexpr unsigned long capacity() {
83 return 1u << log_size;
84 }
85
86 uint64_t magic; ///< File-type identifier
87 uint16_t version; ///< Format version (currently 1)
88 uint16_t elem_size; ///< sizeof(value_t) at write time
89 uint32_t _reserved; ///< Padding, must be 0
90 unsigned log_size; ///< log2 of the number of slots
91 unsigned long nb_elements; ///< Current number of stored key-value pairs
92 unsigned long next_value; ///< Next integer value to assign to a new UUID
93 value_t t[]; ///< Flexible array of hash-table slots
94};
95
96MappedRegion region; ///< Backing storage (shared mmap, or heap buffer)
97table_t *table; ///< Typed view of @c region.base()
98
99/** @brief Initial log2 capacity (65 536 slots). */
100static constexpr unsigned STARTING_LOG_SIZE=16;
101/** @brief Rehash when this fraction of slots is occupied. */
102static constexpr double MAXIMUM_LOAD_FACTOR=.5;
103
104/**
105 * @brief Compute the starting slot index for UUID @p u.
106 *
107 * Reinterprets the first 8 bytes of @p u as a 64-bit integer and takes
108 * it modulo the current capacity.
109 * @param u UUID to hash.
110 * @return Slot index in [0, capacity).
111 */
112inline unsigned long hash(pg_uuid_t u) const {
113 return *reinterpret_cast<unsigned long*>(&u) % (1 << table->log_size);
114};
115
116/**
117 * @brief Find the slot index of @p u, or @c NOTHING if absent.
118 * @param u UUID to look up.
119 * @return Slot index, or @c NOTHING if @p u is not in the table.
120 */
121unsigned long find(pg_uuid_t u) const;
122/** @brief Double the table capacity and rehash all existing entries. */
123void grow();
124/**
125 * @brief Store the mapping @p u → @p i in the table.
126 * @param u UUID key to store.
127 * @param i Integer value to associate with @p u.
128 */
129void set(pg_uuid_t u, unsigned long i);
130
131public:
132/** @brief Sentinel returned by @c operator[]() when the UUID is not present. */
133static constexpr unsigned long NOTHING=static_cast<unsigned long>(-1);
134
135/**
136 * @brief Open (or create) the mmap-backed hash table.
137 *
138 * @param filename Path to the backing file (created if absent).
139 * @param read_only If @c true, map the file read-only (no new entries
140 * can be inserted).
141 * @param magic Expected magic value for format validation.
142 */
143MMappedUUIDHashTable(const char *filename, bool read_only, uint64_t magic);
144/** @brief Sync and unmap the file. */
146
147/**
148 * @brief Look up the integer index for UUID @p u.
149 *
150 * @param u The UUID to look up.
151 * @return The associated integer, or @c NOTHING if @p u is absent.
152 */
153unsigned long operator[](pg_uuid_t u) const;
154
155/**
156 * @brief Insert UUID @p u, assigning it the next available integer.
157 *
158 * If @p u is already present the existing value is returned without
159 * modification.
160 *
161 * @param u UUID to insert.
162 * @return A pair @c {value, inserted} where @c inserted is @c true if
163 * a new entry was created.
164 */
165std::pair<unsigned long,bool> add(pg_uuid_t u);
166
167/**
168 * @brief Return the number of UUID→integer pairs currently stored.
169 * @return Element count.
170 */
171inline unsigned long nbElements() const {
172 return table->nb_elements;
173}
174
175/**
176 * @brief Flush the backing region to its file (@c MappedRegion::sync()).
177 */
178void sync();
179};
180
181 #endif /* MMAPPED_UUID_HASH_TABLE_H */
File-backed memory region with two interchangeable backends.
void set(pg_uuid_t u, unsigned long i)
Store the mapping u → i in the table.
unsigned long hash(pg_uuid_t u) const
Compute the starting slot index for UUID u.
void grow()
Double the table capacity and rehash all existing entries.
std::pair< unsigned long, bool > add(pg_uuid_t u)
Insert UUID u, assigning it the next available integer.
MMappedUUIDHashTable(const char *filename, bool read_only, uint64_t magic)
Open (or create) the mmap-backed hash table.
static constexpr unsigned STARTING_LOG_SIZE
Initial log2 capacity (65 536 slots).
unsigned long find(pg_uuid_t u) const
Find the slot index of u, or NOTHING if absent.
unsigned long operator[](pg_uuid_t u) const
Look up the integer index for UUID u.
unsigned long nbElements() const
Return the number of UUID→integer pairs currently stored.
~MMappedUUIDHashTable()
Sync and unmap the file.
MappedRegion region
Backing storage (shared mmap, or heap buffer).
void sync()
Flush the backing region to its file (MappedRegion::sync()).
static constexpr unsigned long NOTHING
Sentinel returned by operator[]() when the UUID is not present.
static constexpr double MAXIMUM_LOAD_FACTOR
Rehash when this fraction of slots is occupied.
table_t * table
Typed view of region.base().
Core types, constants, and utilities shared across ProvSQL.
On-disk layout of the hash table stored in the mmap file.
static constexpr unsigned logSizeForSize(std::size_t size)
Compute the log2 of the slot count from the file size.
value_t t[]
Flexible array of hash-table slots.
uint32_t _reserved
Padding, must be 0.
static constexpr std::size_t sizeForLogSize(unsigned ls)
Compute the file size required for a table with 2^ls slots.
uint64_t magic
File-type identifier.
unsigned log_size
log2 of the number of slots
uint16_t elem_size
sizeof(value_t) at write time
unsigned long nb_elements
Current number of stored key-value pairs.
unsigned long next_value
Next integer value to assign to a new UUID.
uint16_t version
Format version (currently 1).
constexpr unsigned long capacity()
Maximum number of slots in the table (2^log_size).
One slot in the hash table: a UUID key and its associated integer value.
unsigned long value
Associated integer (gate index), or 0 if slot is empty.
UUID structure.