rrudb 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.yardopts +1 -0
- data/LICENSE.txt +22 -0
- data/README.md +26 -0
- data/examples/example.rb +39 -0
- data/ext/rudb/NuDB/include/nudb/CMakeLists.txt +104 -0
- data/ext/rudb/NuDB/include/nudb/_experimental/basic_seconds_clock.hpp +200 -0
- data/ext/rudb/NuDB/include/nudb/_experimental/chrono_util.hpp +58 -0
- data/ext/rudb/NuDB/include/nudb/_experimental/test/fail_file.hpp +343 -0
- data/ext/rudb/NuDB/include/nudb/_experimental/test/temp_dir.hpp +73 -0
- data/ext/rudb/NuDB/include/nudb/_experimental/test/test_store.hpp +451 -0
- data/ext/rudb/NuDB/include/nudb/_experimental/test/xor_shift_engine.hpp +105 -0
- data/ext/rudb/NuDB/include/nudb/_experimental/util.hpp +288 -0
- data/ext/rudb/NuDB/include/nudb/basic_store.hpp +461 -0
- data/ext/rudb/NuDB/include/nudb/concepts.hpp +205 -0
- data/ext/rudb/NuDB/include/nudb/context.hpp +144 -0
- data/ext/rudb/NuDB/include/nudb/create.hpp +117 -0
- data/ext/rudb/NuDB/include/nudb/detail/arena.hpp +296 -0
- data/ext/rudb/NuDB/include/nudb/detail/bucket.hpp +473 -0
- data/ext/rudb/NuDB/include/nudb/detail/buffer.hpp +86 -0
- data/ext/rudb/NuDB/include/nudb/detail/bulkio.hpp +196 -0
- data/ext/rudb/NuDB/include/nudb/detail/cache.hpp +236 -0
- data/ext/rudb/NuDB/include/nudb/detail/endian.hpp +93 -0
- data/ext/rudb/NuDB/include/nudb/detail/field.hpp +265 -0
- data/ext/rudb/NuDB/include/nudb/detail/format.hpp +630 -0
- data/ext/rudb/NuDB/include/nudb/detail/gentex.hpp +259 -0
- data/ext/rudb/NuDB/include/nudb/detail/mutex.hpp +26 -0
- data/ext/rudb/NuDB/include/nudb/detail/pool.hpp +243 -0
- data/ext/rudb/NuDB/include/nudb/detail/store_base.hpp +45 -0
- data/ext/rudb/NuDB/include/nudb/detail/stream.hpp +149 -0
- data/ext/rudb/NuDB/include/nudb/detail/xxhash.hpp +328 -0
- data/ext/rudb/NuDB/include/nudb/error.hpp +257 -0
- data/ext/rudb/NuDB/include/nudb/file.hpp +55 -0
- data/ext/rudb/NuDB/include/nudb/impl/basic_store.ipp +785 -0
- data/ext/rudb/NuDB/include/nudb/impl/context.ipp +241 -0
- data/ext/rudb/NuDB/include/nudb/impl/create.ipp +163 -0
- data/ext/rudb/NuDB/include/nudb/impl/error.ipp +175 -0
- data/ext/rudb/NuDB/include/nudb/impl/posix_file.ipp +248 -0
- data/ext/rudb/NuDB/include/nudb/impl/recover.ipp +209 -0
- data/ext/rudb/NuDB/include/nudb/impl/rekey.ipp +248 -0
- data/ext/rudb/NuDB/include/nudb/impl/verify.ipp +634 -0
- data/ext/rudb/NuDB/include/nudb/impl/visit.ipp +96 -0
- data/ext/rudb/NuDB/include/nudb/impl/win32_file.ipp +264 -0
- data/ext/rudb/NuDB/include/nudb/native_file.hpp +76 -0
- data/ext/rudb/NuDB/include/nudb/nudb.hpp +27 -0
- data/ext/rudb/NuDB/include/nudb/posix_file.hpp +228 -0
- data/ext/rudb/NuDB/include/nudb/progress.hpp +32 -0
- data/ext/rudb/NuDB/include/nudb/recover.hpp +73 -0
- data/ext/rudb/NuDB/include/nudb/rekey.hpp +110 -0
- data/ext/rudb/NuDB/include/nudb/store.hpp +27 -0
- data/ext/rudb/NuDB/include/nudb/type_traits.hpp +63 -0
- data/ext/rudb/NuDB/include/nudb/verify.hpp +200 -0
- data/ext/rudb/NuDB/include/nudb/version.hpp +21 -0
- data/ext/rudb/NuDB/include/nudb/visit.hpp +63 -0
- data/ext/rudb/NuDB/include/nudb/win32_file.hpp +246 -0
- data/ext/rudb/NuDB/include/nudb/xxhasher.hpp +45 -0
- data/ext/rudb/extconf.rb +12 -0
- data/ext/rudb/rudb.cpp +234 -0
- data/lib/rudb/version.rb +3 -0
- data/lib/rudb.rb +1 -0
- metadata +104 -0
@@ -0,0 +1,630 @@
|
|
1
|
+
//
|
2
|
+
// Copyright (c) 2015-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
3
|
+
//
|
4
|
+
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
5
|
+
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
6
|
+
//
|
7
|
+
|
8
|
+
#ifndef NUDB_DETAIL_FORMAT_HPP
|
9
|
+
#define NUDB_DETAIL_FORMAT_HPP
|
10
|
+
|
11
|
+
#include <nudb/error.hpp>
|
12
|
+
#include <nudb/type_traits.hpp>
|
13
|
+
#include <nudb/detail/buffer.hpp>
|
14
|
+
#include <nudb/detail/endian.hpp>
|
15
|
+
#include <nudb/detail/field.hpp>
|
16
|
+
#include <nudb/detail/stream.hpp>
|
17
|
+
#include <boost/assert.hpp>
|
18
|
+
#include <algorithm>
|
19
|
+
#include <array>
|
20
|
+
#include <limits>
|
21
|
+
#include <cstdint>
|
22
|
+
#include <cstring>
|
23
|
+
#include <memory>
|
24
|
+
#include <stdexcept>
|
25
|
+
#include <type_traits>
|
26
|
+
|
27
|
+
namespace nudb {
|
28
|
+
namespace detail {
|
29
|
+
|
30
|
+
// Format of the nudb files:
|
31
|
+
|
32
|
+
/*
|
33
|
+
|
34
|
+
Integer sizes
|
35
|
+
|
36
|
+
block_size less than 32 bits (maybe restrict it to 16 bits)
|
37
|
+
buckets more than 32 bits
|
38
|
+
capacity (same as bucket index)
|
39
|
+
file offsets 63 bits
|
40
|
+
hash up to 64 bits (48 currently)
|
41
|
+
item index less than 32 bits (index of item in bucket)
|
42
|
+
modulus (same as buckets)
|
43
|
+
value size up to 32 bits (or 32-bit builds can't read it)
|
44
|
+
|
45
|
+
*/
|
46
|
+
|
47
|
+
static std::size_t constexpr currentVersion = 2;
|
48
|
+
|
49
|
+
struct dat_file_header
|
50
|
+
{
|
51
|
+
static std::size_t constexpr size =
|
52
|
+
8 + // Type
|
53
|
+
2 + // Version
|
54
|
+
8 + // UID
|
55
|
+
8 + // Appnum
|
56
|
+
2 + // KeySize
|
57
|
+
|
58
|
+
64; // (Reserved)
|
59
|
+
|
60
|
+
char type[8];
|
61
|
+
std::size_t version;
|
62
|
+
std::uint64_t uid;
|
63
|
+
std::uint64_t appnum;
|
64
|
+
nsize_t key_size;
|
65
|
+
};
|
66
|
+
|
67
|
+
struct key_file_header
|
68
|
+
{
|
69
|
+
static std::size_t constexpr size =
|
70
|
+
8 + // Type
|
71
|
+
2 + // Version
|
72
|
+
8 + // UID
|
73
|
+
8 + // Appnum
|
74
|
+
2 + // KeySize
|
75
|
+
|
76
|
+
8 + // Salt
|
77
|
+
8 + // Pepper
|
78
|
+
2 + // BlockSize
|
79
|
+
2 + // LoadFactor
|
80
|
+
|
81
|
+
56; // (Reserved)
|
82
|
+
|
83
|
+
char type[8];
|
84
|
+
std::size_t version;
|
85
|
+
std::uint64_t uid;
|
86
|
+
std::uint64_t appnum;
|
87
|
+
nsize_t key_size;
|
88
|
+
|
89
|
+
std::uint64_t salt;
|
90
|
+
std::uint64_t pepper;
|
91
|
+
nsize_t block_size;
|
92
|
+
std::size_t load_factor;
|
93
|
+
|
94
|
+
// Computed values
|
95
|
+
nkey_t capacity; // Entries per bucket
|
96
|
+
nbuck_t buckets; // Number of buckets
|
97
|
+
nbuck_t modulus; // pow(2,ceil(log2(buckets)))
|
98
|
+
};
|
99
|
+
|
100
|
+
struct log_file_header
|
101
|
+
{
|
102
|
+
static std::size_t constexpr size =
|
103
|
+
8 + // Type
|
104
|
+
2 + // Version
|
105
|
+
8 + // UID
|
106
|
+
8 + // Appnum
|
107
|
+
2 + // KeySize
|
108
|
+
|
109
|
+
8 + // Salt
|
110
|
+
8 + // Pepper
|
111
|
+
2 + // BlockSize
|
112
|
+
|
113
|
+
8 + // KeyFileSize
|
114
|
+
8; // DataFileSize
|
115
|
+
|
116
|
+
char type[8];
|
117
|
+
std::size_t version;
|
118
|
+
std::uint64_t uid;
|
119
|
+
std::uint64_t appnum;
|
120
|
+
nsize_t key_size;
|
121
|
+
std::uint64_t salt;
|
122
|
+
std::uint64_t pepper;
|
123
|
+
nsize_t block_size;
|
124
|
+
noff_t key_file_size;
|
125
|
+
noff_t dat_file_size;
|
126
|
+
};
|
127
|
+
|
128
|
+
// Type used to store hashes in buckets.
|
129
|
+
// This can be smaller than the output
|
130
|
+
// of the hash function.
|
131
|
+
//
|
132
|
+
using f_hash = uint48_t;
|
133
|
+
|
134
|
+
static_assert(field<f_hash>::size <=
|
135
|
+
sizeof(nhash_t), "");
|
136
|
+
|
137
|
+
template<class T>
|
138
|
+
nhash_t
|
139
|
+
make_hash(nhash_t h);
|
140
|
+
|
141
|
+
template<>
|
142
|
+
inline
|
143
|
+
nhash_t
|
144
|
+
make_hash<uint48_t>(nhash_t h)
|
145
|
+
{
|
146
|
+
return(h>>16)&0xffffffffffff;
|
147
|
+
}
|
148
|
+
|
149
|
+
// Returns the hash of a key given the salt.
|
150
|
+
// Note: The hash is expressed in f_hash units
|
151
|
+
//
|
152
|
+
template<class Hasher>
|
153
|
+
inline
|
154
|
+
nhash_t
|
155
|
+
hash(void const* key, nsize_t key_size, std::uint64_t salt)
|
156
|
+
{
|
157
|
+
Hasher h{salt};
|
158
|
+
return make_hash<f_hash>(h(key, key_size));
|
159
|
+
}
|
160
|
+
|
161
|
+
template<class Hasher>
|
162
|
+
inline
|
163
|
+
nhash_t
|
164
|
+
hash(void const* key, nsize_t key_size, Hasher const& h)
|
165
|
+
{
|
166
|
+
return make_hash<f_hash>(h(key, key_size));
|
167
|
+
}
|
168
|
+
|
169
|
+
// Computes pepper from salt
|
170
|
+
//
|
171
|
+
template<class Hasher>
|
172
|
+
std::uint64_t
|
173
|
+
pepper(std::uint64_t salt)
|
174
|
+
{
|
175
|
+
auto const v = to_little_endian(salt);
|
176
|
+
Hasher h{salt};
|
177
|
+
return h(&v, sizeof(v));
|
178
|
+
}
|
179
|
+
|
180
|
+
// Returns the actual size of a bucket.
|
181
|
+
// This can be smaller than the block size.
|
182
|
+
//
|
183
|
+
template<class = void>
|
184
|
+
nsize_t
|
185
|
+
bucket_size(nkey_t capacity)
|
186
|
+
{
|
187
|
+
// Bucket Record
|
188
|
+
return
|
189
|
+
field<std::uint16_t>::size + // Count
|
190
|
+
field<uint48_t>::size + // Spill
|
191
|
+
capacity * (
|
192
|
+
field<uint48_t>::size + // Offset
|
193
|
+
field<uint48_t>::size + // Size
|
194
|
+
field<f_hash>::size); // Hash
|
195
|
+
}
|
196
|
+
|
197
|
+
// Returns the number of entries that fit in a bucket
|
198
|
+
//
|
199
|
+
template<class = void>
|
200
|
+
nkey_t
|
201
|
+
bucket_capacity(nsize_t block_size)
|
202
|
+
{
|
203
|
+
// Bucket Record
|
204
|
+
auto const size =
|
205
|
+
field<std::uint16_t>::size + // Count
|
206
|
+
field<uint48_t>::size; // Spill
|
207
|
+
auto const entry_size =
|
208
|
+
field<uint48_t>::size + // Offset
|
209
|
+
field<uint48_t>::size + // Size
|
210
|
+
field<f_hash>::size; // Hash
|
211
|
+
if(block_size < key_file_header::size ||
|
212
|
+
block_size < size)
|
213
|
+
return 0;
|
214
|
+
auto const n =
|
215
|
+
(block_size - size) / entry_size;
|
216
|
+
BOOST_ASSERT(n <= std::numeric_limits<nkey_t>::max());
|
217
|
+
return static_cast<nkey_t>(std::min<std::size_t>(
|
218
|
+
std::numeric_limits<nkey_t>::max(), n));
|
219
|
+
}
|
220
|
+
|
221
|
+
// Returns the number of bytes occupied by a value record
|
222
|
+
// VFALCO TODO Fix this
|
223
|
+
inline
|
224
|
+
std::size_t
|
225
|
+
value_size(std::size_t size,
|
226
|
+
std::size_t key_size)
|
227
|
+
{
|
228
|
+
// Data Record
|
229
|
+
return
|
230
|
+
field<uint48_t>::size + // Size
|
231
|
+
key_size + // Key
|
232
|
+
size; // Data
|
233
|
+
}
|
234
|
+
|
235
|
+
// Returns the closest power of 2 not less than x
|
236
|
+
template<class T>
|
237
|
+
T
|
238
|
+
ceil_pow2(T x)
|
239
|
+
{
|
240
|
+
static const unsigned long long t[6] = {
|
241
|
+
0xFFFFFFFF00000000ull,
|
242
|
+
0x00000000FFFF0000ull,
|
243
|
+
0x000000000000FF00ull,
|
244
|
+
0x00000000000000F0ull,
|
245
|
+
0x000000000000000Cull,
|
246
|
+
0x0000000000000002ull
|
247
|
+
};
|
248
|
+
|
249
|
+
int y =(((x &(x - 1)) == 0) ? 0 : 1);
|
250
|
+
int j = 32;
|
251
|
+
int i;
|
252
|
+
|
253
|
+
for(i = 0; i < 6; i++) {
|
254
|
+
int k =(((x & t[i]) == 0) ? 0 : j);
|
255
|
+
y += k;
|
256
|
+
x >>= k;
|
257
|
+
j >>= 1;
|
258
|
+
}
|
259
|
+
|
260
|
+
return T{1}<<y;
|
261
|
+
}
|
262
|
+
|
263
|
+
//------------------------------------------------------------------------------
|
264
|
+
|
265
|
+
// Read data file header from stream
|
266
|
+
template<class = void>
|
267
|
+
void
|
268
|
+
read(istream& is, dat_file_header& dh)
|
269
|
+
{
|
270
|
+
read(is, dh.type, sizeof(dh.type));
|
271
|
+
read<std::uint16_t>(is, dh.version);
|
272
|
+
read<std::uint64_t>(is, dh.uid);
|
273
|
+
read<std::uint64_t>(is, dh.appnum);
|
274
|
+
read<std::uint16_t>(is, dh.key_size);
|
275
|
+
std::array<std::uint8_t, 64> reserved;
|
276
|
+
read(is, reserved.data(), reserved.size());
|
277
|
+
}
|
278
|
+
|
279
|
+
// Read data file header from file
|
280
|
+
template<class File>
|
281
|
+
void
|
282
|
+
read(File& f, dat_file_header& dh, error_code& ec)
|
283
|
+
{
|
284
|
+
std::array<std::uint8_t, dat_file_header::size> buf;
|
285
|
+
f.read(0, buf.data(), buf.size(), ec);
|
286
|
+
if(ec)
|
287
|
+
return;
|
288
|
+
istream is(buf);
|
289
|
+
read(is, dh);
|
290
|
+
}
|
291
|
+
|
292
|
+
// Write data file header to stream
|
293
|
+
template<class = void>
|
294
|
+
void
|
295
|
+
write(ostream& os, dat_file_header const& dh)
|
296
|
+
{
|
297
|
+
write(os, "nudb.dat", 8);
|
298
|
+
write<std::uint16_t>(os, dh.version);
|
299
|
+
write<std::uint64_t>(os, dh.uid);
|
300
|
+
write<std::uint64_t>(os, dh.appnum);
|
301
|
+
write<std::uint16_t>(os, dh.key_size);
|
302
|
+
std::array<std::uint8_t, 64> reserved;
|
303
|
+
reserved.fill(0);
|
304
|
+
write(os, reserved.data(), reserved.size());
|
305
|
+
}
|
306
|
+
|
307
|
+
// Write data file header to file
|
308
|
+
template<class File>
|
309
|
+
void
|
310
|
+
write(File& f, dat_file_header const& dh, error_code& ec)
|
311
|
+
{
|
312
|
+
std::array<std::uint8_t, dat_file_header::size> buf;
|
313
|
+
ostream os(buf);
|
314
|
+
write(os, dh);
|
315
|
+
f.write(0, buf.data(), buf.size(), ec);
|
316
|
+
}
|
317
|
+
|
318
|
+
// Read key file header from stream
|
319
|
+
template<class = void>
|
320
|
+
void
|
321
|
+
read(istream& is, noff_t file_size, key_file_header& kh)
|
322
|
+
{
|
323
|
+
read(is, kh.type, sizeof(kh.type));
|
324
|
+
read<std::uint16_t>(is, kh.version);
|
325
|
+
read<std::uint64_t>(is, kh.uid);
|
326
|
+
read<std::uint64_t>(is, kh.appnum);
|
327
|
+
read<std::uint16_t>(is, kh.key_size);
|
328
|
+
read<std::uint64_t>(is, kh.salt);
|
329
|
+
read<std::uint64_t>(is, kh.pepper);
|
330
|
+
read<std::uint16_t>(is, kh.block_size);
|
331
|
+
read<std::uint16_t>(is, kh.load_factor);
|
332
|
+
std::array<std::uint8_t, 56> reserved;
|
333
|
+
read(is, reserved.data(), reserved.size());
|
334
|
+
|
335
|
+
// VFALCO These need to be checked to handle
|
336
|
+
// when the file size is too small
|
337
|
+
kh.capacity = bucket_capacity(kh.block_size);
|
338
|
+
if(file_size > kh.block_size)
|
339
|
+
{
|
340
|
+
if(kh.block_size > 0)
|
341
|
+
kh.buckets = static_cast<nbuck_t>(
|
342
|
+
(file_size - kh.block_size) / kh.block_size);
|
343
|
+
else
|
344
|
+
// VFALCO Corruption or logic error
|
345
|
+
kh.buckets = 0;
|
346
|
+
}
|
347
|
+
else
|
348
|
+
{
|
349
|
+
kh.buckets = 0;
|
350
|
+
}
|
351
|
+
kh.modulus = ceil_pow2(kh.buckets);
|
352
|
+
}
|
353
|
+
|
354
|
+
// Read key file header from file
|
355
|
+
template<class File>
|
356
|
+
void
|
357
|
+
read(File& f, key_file_header& kh, error_code& ec)
|
358
|
+
{
|
359
|
+
std::array<std::uint8_t, key_file_header::size> buf;
|
360
|
+
f.read(0, buf.data(), buf.size(), ec);
|
361
|
+
if(ec)
|
362
|
+
return;
|
363
|
+
istream is{buf};
|
364
|
+
auto const size = f.size(ec);
|
365
|
+
if(ec)
|
366
|
+
return;
|
367
|
+
read(is, size, kh);
|
368
|
+
}
|
369
|
+
|
370
|
+
// Write key file header to stream
|
371
|
+
template<class = void>
|
372
|
+
void
|
373
|
+
write(ostream& os, key_file_header const& kh)
|
374
|
+
{
|
375
|
+
write(os, "nudb.key", 8);
|
376
|
+
write<std::uint16_t>(os, kh.version);
|
377
|
+
write<std::uint64_t>(os, kh.uid);
|
378
|
+
write<std::uint64_t>(os, kh.appnum);
|
379
|
+
write<std::uint16_t>(os, kh.key_size);
|
380
|
+
write<std::uint64_t>(os, kh.salt);
|
381
|
+
write<std::uint64_t>(os, kh.pepper);
|
382
|
+
write<std::uint16_t>(os, kh.block_size);
|
383
|
+
write<std::uint16_t>(os, kh.load_factor);
|
384
|
+
std::array<std::uint8_t, 56> reserved;
|
385
|
+
reserved.fill(0);
|
386
|
+
write(os, reserved.data(), reserved.size());
|
387
|
+
}
|
388
|
+
|
389
|
+
// Write key file header to file
|
390
|
+
template<class File>
|
391
|
+
void
|
392
|
+
write(File& f, key_file_header const& kh, error_code& ec)
|
393
|
+
{
|
394
|
+
buffer buf;
|
395
|
+
buf.reserve(kh.block_size);
|
396
|
+
if(kh.block_size < key_file_header::size)
|
397
|
+
{
|
398
|
+
ec = error::invalid_block_size;
|
399
|
+
return;
|
400
|
+
}
|
401
|
+
std::fill(buf.get(), buf.get() + buf.size(),
|
402
|
+
(unsigned char)0);
|
403
|
+
ostream os{buf.get(), buf.size()};
|
404
|
+
write(os, kh);
|
405
|
+
f.write(0, buf.get(), buf.size(), ec);
|
406
|
+
}
|
407
|
+
|
408
|
+
// Read log file header from stream
|
409
|
+
template<class = void>
|
410
|
+
void
|
411
|
+
read(istream& is, log_file_header& lh)
|
412
|
+
{
|
413
|
+
read(is, lh.type, sizeof(lh.type));
|
414
|
+
read<std::uint16_t>(is, lh.version);
|
415
|
+
read<std::uint64_t>(is, lh.uid);
|
416
|
+
read<std::uint64_t>(is, lh.appnum);
|
417
|
+
read<std::uint16_t>(is, lh.key_size);
|
418
|
+
read<std::uint64_t>(is, lh.salt);
|
419
|
+
read<std::uint64_t>(is, lh.pepper);
|
420
|
+
read<std::uint16_t>(is, lh.block_size);
|
421
|
+
read<std::uint64_t>(is, lh.key_file_size);
|
422
|
+
read<std::uint64_t>(is, lh.dat_file_size);
|
423
|
+
}
|
424
|
+
|
425
|
+
// Read log file header from file
|
426
|
+
template<class File>
|
427
|
+
void
|
428
|
+
read(File& f, log_file_header& lh, error_code& ec)
|
429
|
+
{
|
430
|
+
std::array<std::uint8_t, log_file_header::size> buf;
|
431
|
+
f.read(0, buf.data(), buf.size(), ec);
|
432
|
+
if(ec)
|
433
|
+
return;
|
434
|
+
istream is{buf};
|
435
|
+
read(is, lh);
|
436
|
+
}
|
437
|
+
|
438
|
+
// Write log file header to stream
|
439
|
+
template<class = void>
|
440
|
+
void
|
441
|
+
write(ostream& os, log_file_header const& lh)
|
442
|
+
{
|
443
|
+
write(os, "nudb.log", 8);
|
444
|
+
write<std::uint16_t>(os, lh.version);
|
445
|
+
write<std::uint64_t>(os, lh.uid);
|
446
|
+
write<std::uint64_t>(os, lh.appnum);
|
447
|
+
write<std::uint16_t>(os, lh.key_size);
|
448
|
+
write<std::uint64_t>(os, lh.salt);
|
449
|
+
write<std::uint64_t>(os, lh.pepper);
|
450
|
+
write<std::uint16_t>(os, lh.block_size);
|
451
|
+
write<std::uint64_t>(os, lh.key_file_size);
|
452
|
+
write<std::uint64_t>(os, lh.dat_file_size);
|
453
|
+
}
|
454
|
+
|
455
|
+
// Write log file header to file
|
456
|
+
template<class File>
|
457
|
+
void
|
458
|
+
write(File& f, log_file_header const& lh, error_code& ec)
|
459
|
+
{
|
460
|
+
std::array<std::uint8_t, log_file_header::size> buf;
|
461
|
+
ostream os{buf};
|
462
|
+
write(os, lh);
|
463
|
+
f.write(0, buf.data(), buf.size(), ec);
|
464
|
+
}
|
465
|
+
|
466
|
+
// Verify contents of data file header
|
467
|
+
template<class = void>
|
468
|
+
void
|
469
|
+
verify(dat_file_header const& dh, error_code& ec)
|
470
|
+
{
|
471
|
+
std::string const type{dh.type, 8};
|
472
|
+
if(type != "nudb.dat")
|
473
|
+
{
|
474
|
+
ec = error::not_data_file;
|
475
|
+
return;
|
476
|
+
}
|
477
|
+
if(dh.version != currentVersion)
|
478
|
+
{
|
479
|
+
ec = error::different_version;
|
480
|
+
return;
|
481
|
+
}
|
482
|
+
if(dh.key_size < 1)
|
483
|
+
{
|
484
|
+
ec = error::invalid_key_size;
|
485
|
+
return;
|
486
|
+
}
|
487
|
+
}
|
488
|
+
|
489
|
+
// Verify contents of key file header
|
490
|
+
template<class Hasher>
|
491
|
+
void
|
492
|
+
verify(key_file_header const& kh, error_code& ec)
|
493
|
+
{
|
494
|
+
std::string const type{kh.type, 8};
|
495
|
+
if(type != "nudb.key")
|
496
|
+
{
|
497
|
+
ec = error::not_key_file;
|
498
|
+
return;
|
499
|
+
}
|
500
|
+
if(kh.version != currentVersion)
|
501
|
+
{
|
502
|
+
ec = error::different_version;
|
503
|
+
return;
|
504
|
+
}
|
505
|
+
if(kh.key_size < 1)
|
506
|
+
{
|
507
|
+
ec = error::invalid_key_size;
|
508
|
+
return;
|
509
|
+
}
|
510
|
+
if(kh.pepper != pepper<Hasher>(kh.salt))
|
511
|
+
{
|
512
|
+
ec = error::hash_mismatch;
|
513
|
+
return;
|
514
|
+
}
|
515
|
+
if(kh.load_factor < 1)
|
516
|
+
{
|
517
|
+
ec = error::invalid_load_factor;
|
518
|
+
return;
|
519
|
+
}
|
520
|
+
if(kh.capacity < 1)
|
521
|
+
{
|
522
|
+
ec = error::invalid_capacity;
|
523
|
+
return;
|
524
|
+
}
|
525
|
+
if(kh.buckets < 1)
|
526
|
+
{
|
527
|
+
ec = error::invalid_bucket_count;
|
528
|
+
return;
|
529
|
+
}
|
530
|
+
}
|
531
|
+
|
532
|
+
// Verify contents of log file header
|
533
|
+
template<class Hasher>
|
534
|
+
void
|
535
|
+
verify(log_file_header const& lh, error_code& ec)
|
536
|
+
{
|
537
|
+
std::string const type{lh.type, 8};
|
538
|
+
if(type != "nudb.log")
|
539
|
+
{
|
540
|
+
ec = error::not_log_file;
|
541
|
+
return;
|
542
|
+
}
|
543
|
+
if(lh.version != currentVersion)
|
544
|
+
{
|
545
|
+
ec = error::different_version;
|
546
|
+
return;
|
547
|
+
}
|
548
|
+
if(lh.pepper != pepper<Hasher>(lh.salt))
|
549
|
+
{
|
550
|
+
ec = error::hash_mismatch;
|
551
|
+
return;
|
552
|
+
}
|
553
|
+
if(lh.key_size < 1)
|
554
|
+
{
|
555
|
+
ec = error::invalid_key_size;
|
556
|
+
return;
|
557
|
+
}
|
558
|
+
}
|
559
|
+
|
560
|
+
// Make sure key file and value file headers match
|
561
|
+
template<class Hasher>
|
562
|
+
void
|
563
|
+
verify(dat_file_header const& dh,
|
564
|
+
key_file_header const& kh, error_code& ec)
|
565
|
+
{
|
566
|
+
verify<Hasher>(kh, ec);
|
567
|
+
if(ec)
|
568
|
+
return;
|
569
|
+
if(kh.uid != dh.uid)
|
570
|
+
{
|
571
|
+
ec = error::uid_mismatch;
|
572
|
+
return;
|
573
|
+
}
|
574
|
+
if(kh.appnum != dh.appnum)
|
575
|
+
{
|
576
|
+
ec = error::appnum_mismatch;
|
577
|
+
return;
|
578
|
+
}
|
579
|
+
if(kh.key_size != dh.key_size)
|
580
|
+
{
|
581
|
+
ec = error::key_size_mismatch;
|
582
|
+
return;
|
583
|
+
}
|
584
|
+
}
|
585
|
+
|
586
|
+
// Make sure key file and log file headers match
|
587
|
+
template<class Hasher>
|
588
|
+
void
|
589
|
+
verify(key_file_header const& kh,
|
590
|
+
log_file_header const& lh, error_code& ec)
|
591
|
+
{
|
592
|
+
verify<Hasher>(lh, ec);
|
593
|
+
if(ec)
|
594
|
+
return;
|
595
|
+
if(kh.uid != lh.uid)
|
596
|
+
{
|
597
|
+
ec = error::uid_mismatch;
|
598
|
+
return;
|
599
|
+
}
|
600
|
+
if(kh.appnum != lh.appnum)
|
601
|
+
{
|
602
|
+
ec = error::appnum_mismatch;
|
603
|
+
return;
|
604
|
+
}
|
605
|
+
if(kh.key_size != lh.key_size)
|
606
|
+
{
|
607
|
+
ec = error::key_size_mismatch;
|
608
|
+
return;
|
609
|
+
}
|
610
|
+
if(kh.salt != lh.salt)
|
611
|
+
{
|
612
|
+
ec = error::salt_mismatch;
|
613
|
+
return;
|
614
|
+
}
|
615
|
+
if(kh.pepper != lh.pepper)
|
616
|
+
{
|
617
|
+
ec = error::pepper_mismatch;
|
618
|
+
return;
|
619
|
+
}
|
620
|
+
if(kh.block_size != lh.block_size)
|
621
|
+
{
|
622
|
+
ec = error::block_size_mismatch;
|
623
|
+
return;
|
624
|
+
}
|
625
|
+
}
|
626
|
+
|
627
|
+
} // detail
|
628
|
+
} // nudb
|
629
|
+
|
630
|
+
#endif
|