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.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +1 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +26 -0
  5. data/examples/example.rb +39 -0
  6. data/ext/rudb/NuDB/include/nudb/CMakeLists.txt +104 -0
  7. data/ext/rudb/NuDB/include/nudb/_experimental/basic_seconds_clock.hpp +200 -0
  8. data/ext/rudb/NuDB/include/nudb/_experimental/chrono_util.hpp +58 -0
  9. data/ext/rudb/NuDB/include/nudb/_experimental/test/fail_file.hpp +343 -0
  10. data/ext/rudb/NuDB/include/nudb/_experimental/test/temp_dir.hpp +73 -0
  11. data/ext/rudb/NuDB/include/nudb/_experimental/test/test_store.hpp +451 -0
  12. data/ext/rudb/NuDB/include/nudb/_experimental/test/xor_shift_engine.hpp +105 -0
  13. data/ext/rudb/NuDB/include/nudb/_experimental/util.hpp +288 -0
  14. data/ext/rudb/NuDB/include/nudb/basic_store.hpp +461 -0
  15. data/ext/rudb/NuDB/include/nudb/concepts.hpp +205 -0
  16. data/ext/rudb/NuDB/include/nudb/context.hpp +144 -0
  17. data/ext/rudb/NuDB/include/nudb/create.hpp +117 -0
  18. data/ext/rudb/NuDB/include/nudb/detail/arena.hpp +296 -0
  19. data/ext/rudb/NuDB/include/nudb/detail/bucket.hpp +473 -0
  20. data/ext/rudb/NuDB/include/nudb/detail/buffer.hpp +86 -0
  21. data/ext/rudb/NuDB/include/nudb/detail/bulkio.hpp +196 -0
  22. data/ext/rudb/NuDB/include/nudb/detail/cache.hpp +236 -0
  23. data/ext/rudb/NuDB/include/nudb/detail/endian.hpp +93 -0
  24. data/ext/rudb/NuDB/include/nudb/detail/field.hpp +265 -0
  25. data/ext/rudb/NuDB/include/nudb/detail/format.hpp +630 -0
  26. data/ext/rudb/NuDB/include/nudb/detail/gentex.hpp +259 -0
  27. data/ext/rudb/NuDB/include/nudb/detail/mutex.hpp +26 -0
  28. data/ext/rudb/NuDB/include/nudb/detail/pool.hpp +243 -0
  29. data/ext/rudb/NuDB/include/nudb/detail/store_base.hpp +45 -0
  30. data/ext/rudb/NuDB/include/nudb/detail/stream.hpp +149 -0
  31. data/ext/rudb/NuDB/include/nudb/detail/xxhash.hpp +328 -0
  32. data/ext/rudb/NuDB/include/nudb/error.hpp +257 -0
  33. data/ext/rudb/NuDB/include/nudb/file.hpp +55 -0
  34. data/ext/rudb/NuDB/include/nudb/impl/basic_store.ipp +785 -0
  35. data/ext/rudb/NuDB/include/nudb/impl/context.ipp +241 -0
  36. data/ext/rudb/NuDB/include/nudb/impl/create.ipp +163 -0
  37. data/ext/rudb/NuDB/include/nudb/impl/error.ipp +175 -0
  38. data/ext/rudb/NuDB/include/nudb/impl/posix_file.ipp +248 -0
  39. data/ext/rudb/NuDB/include/nudb/impl/recover.ipp +209 -0
  40. data/ext/rudb/NuDB/include/nudb/impl/rekey.ipp +248 -0
  41. data/ext/rudb/NuDB/include/nudb/impl/verify.ipp +634 -0
  42. data/ext/rudb/NuDB/include/nudb/impl/visit.ipp +96 -0
  43. data/ext/rudb/NuDB/include/nudb/impl/win32_file.ipp +264 -0
  44. data/ext/rudb/NuDB/include/nudb/native_file.hpp +76 -0
  45. data/ext/rudb/NuDB/include/nudb/nudb.hpp +27 -0
  46. data/ext/rudb/NuDB/include/nudb/posix_file.hpp +228 -0
  47. data/ext/rudb/NuDB/include/nudb/progress.hpp +32 -0
  48. data/ext/rudb/NuDB/include/nudb/recover.hpp +73 -0
  49. data/ext/rudb/NuDB/include/nudb/rekey.hpp +110 -0
  50. data/ext/rudb/NuDB/include/nudb/store.hpp +27 -0
  51. data/ext/rudb/NuDB/include/nudb/type_traits.hpp +63 -0
  52. data/ext/rudb/NuDB/include/nudb/verify.hpp +200 -0
  53. data/ext/rudb/NuDB/include/nudb/version.hpp +21 -0
  54. data/ext/rudb/NuDB/include/nudb/visit.hpp +63 -0
  55. data/ext/rudb/NuDB/include/nudb/win32_file.hpp +246 -0
  56. data/ext/rudb/NuDB/include/nudb/xxhasher.hpp +45 -0
  57. data/ext/rudb/extconf.rb +12 -0
  58. data/ext/rudb/rudb.cpp +234 -0
  59. data/lib/rudb/version.rb +3 -0
  60. data/lib/rudb.rb +1 -0
  61. metadata +104 -0
@@ -0,0 +1,241 @@
1
+ //
2
+ // Copyright (c) 2019 Miguel Portilla (miguelportilla64 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_IMPL_CONTEXT_IPP
9
+ #define NUDB_IMPL_CONTEXT_IPP
10
+
11
+ #include <nudb/detail/store_base.hpp>
12
+
13
+ namespace nudb {
14
+
15
+ context::
16
+ ~context() noexcept (false)
17
+ {
18
+ stop_all();
19
+ std::lock_guard<std::mutex> lock(m_);
20
+ if(! waiting_.empty() || ! flushing_.empty())
21
+ throw std::logic_error("All databases haven't been closed");
22
+ }
23
+
24
+ void
25
+ context::
26
+ start()
27
+ {
28
+ std::lock_guard<std::mutex> lock(m_);
29
+ if(! stop_ && ! t_.joinable())
30
+ t_ = std::thread(&context::run, this);
31
+ }
32
+
33
+ void
34
+ context::
35
+ stop_all()
36
+ {
37
+ std::unique_lock<std::mutex> lock(m_);
38
+ if(stop_)
39
+ return;
40
+ stop_ = true;
41
+ cv_f_.notify_all();
42
+ cv_w_.notify_all();
43
+ cv_w_.wait(lock,
44
+ [&]
45
+ {
46
+ return num_threads_ == 0;
47
+ });
48
+ if(t_.joinable())
49
+ {
50
+ lock.unlock();
51
+ t_.join();
52
+ lock.lock();
53
+ }
54
+ stop_ = false;
55
+ }
56
+
57
+ void
58
+ context::
59
+ run()
60
+ {
61
+ bool const first = [&]
62
+ {
63
+ std::lock_guard<std::mutex> lock(m_);
64
+ return ++num_threads_ == 1;
65
+ }();
66
+
67
+ auto when = clock_type::now();
68
+ for(;;)
69
+ {
70
+ {
71
+ std::unique_lock<std::mutex> lock(m_);
72
+ if(stop_)
73
+ break;
74
+ if(first)
75
+ {
76
+ auto const status = cv_f_.wait_until(
77
+ lock, when + std::chrono::seconds{1});
78
+ if(stop_)
79
+ break;
80
+ if(status == std::cv_status::timeout && ! waiting_.empty())
81
+ {
82
+ // Move everything in waiting_ to flushing_
83
+ for(auto store = waiting_.head_; store;
84
+ store = store->next_)
85
+ store->state_ = store_base::state::flushing;
86
+ flushing_.splice(waiting_);
87
+ }
88
+
89
+ when = clock_type::now();
90
+ if(flushing_.empty())
91
+ continue;
92
+ cv_f_.notify_all();
93
+ }
94
+ else
95
+ {
96
+ cv_f_.wait(lock,
97
+ [this]
98
+ {
99
+ return ! flushing_.empty() || stop_;
100
+ });
101
+ if(stop_)
102
+ break;
103
+ }
104
+ }
105
+
106
+ // process everything in flushing_
107
+ for(;;)
108
+ if(! flush_one())
109
+ break;
110
+ }
111
+
112
+ std::lock_guard<std::mutex> lock(m_);
113
+ --num_threads_;
114
+ cv_w_.notify_all();
115
+ }
116
+
117
+ void
118
+ context::
119
+ insert(store_base& store)
120
+ {
121
+ std::lock_guard<std::mutex> lock(m_);
122
+ store.state_ = store_base::state::waiting;
123
+ waiting_.push_back(&store);
124
+ cv_w_.notify_all();
125
+ }
126
+
127
+ void
128
+ context::
129
+ erase(store_base& store)
130
+ {
131
+ using state = store_base::state;
132
+ std::unique_lock<std::mutex> lock(m_);
133
+ switch(store.state_)
134
+ {
135
+ case state::waiting:
136
+ waiting_.erase(&store);
137
+ cv_w_.notify_all();
138
+ break;
139
+ case state::flushing:
140
+ flushing_.erase(&store);
141
+ break;
142
+ case state::intermediate:
143
+ cv_w_.wait(lock,
144
+ [&]
145
+ {
146
+ return store.state_ != state::intermediate;
147
+ });
148
+ if(store.state_ == state::flushing)
149
+ {
150
+ flushing_.erase(&store);
151
+ }
152
+ else if(store.state_ == state::waiting)
153
+ {
154
+ waiting_.erase(&store);
155
+ cv_w_.notify_all();
156
+ }
157
+ break;
158
+ case state::none:
159
+ return;
160
+ }
161
+ store.state_ = state::none;
162
+ }
163
+
164
+ bool
165
+ context::
166
+ flush_one()
167
+ {
168
+ store_base* store;
169
+ {
170
+ std::lock_guard<std::mutex> lock(m_);
171
+ if(flushing_.empty())
172
+ return false;
173
+ store = flushing_.head_;
174
+ store->state_ = store_base::state::intermediate;
175
+ flushing_.erase(store);
176
+ }
177
+
178
+ store->flush();
179
+
180
+ std::lock_guard<std::mutex> lock(m_);
181
+ store->state_ = store_base::state::waiting;
182
+ waiting_.push_back(store);
183
+ cv_w_.notify_all();
184
+ return true;
185
+ }
186
+
187
+ void
188
+ context::list::
189
+ push_back(store_base* node)
190
+ {
191
+ node->next_ = nullptr;
192
+ node->prev_ = tail_;
193
+ if(tail_)
194
+ tail_->next_ = node;
195
+ tail_ = node;
196
+ if(!head_)
197
+ head_ = node;
198
+ }
199
+
200
+ void
201
+ context::list::
202
+ erase(store_base* node)
203
+ {
204
+ if(node->next_)
205
+ node->next_->prev_ = node->prev_;
206
+ else // node == tail_
207
+ tail_ = node->prev_;
208
+
209
+ if(node->prev_)
210
+ node->prev_->next_ = node->next_;
211
+ else // node == head_
212
+ head_ = node->next_;
213
+
214
+ node->next_ = nullptr;
215
+ node->prev_ = nullptr;
216
+ }
217
+
218
+ void
219
+ context::list::
220
+ splice(list& right)
221
+ {
222
+ if(right.empty())
223
+ return;
224
+ if(empty())
225
+ {
226
+ head_ = right.head_;
227
+ tail_ = right.tail_;
228
+ }
229
+ else
230
+ {
231
+ right.head_->prev_ = tail_;
232
+ tail_->next_ = right.head_;
233
+ tail_ = right.tail_;
234
+ }
235
+ right.head_ = nullptr;
236
+ right.tail_ = nullptr;
237
+ }
238
+
239
+ } // nudb
240
+
241
+ #endif
@@ -0,0 +1,163 @@
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_IMPL_CREATE_IPP
9
+ #define NUDB_IMPL_CREATE_IPP
10
+
11
+ #include <nudb/concepts.hpp>
12
+ #include <nudb/native_file.hpp>
13
+ #include <nudb/detail/bucket.hpp>
14
+ #include <nudb/detail/format.hpp>
15
+ #include <algorithm>
16
+ #include <cstring>
17
+ #include <random>
18
+ #include <stdexcept>
19
+ #include <utility>
20
+
21
+ namespace nudb {
22
+
23
+ namespace detail {
24
+
25
+ template<class = void>
26
+ std::uint64_t
27
+ make_uid()
28
+ {
29
+ std::random_device rng;
30
+ std::mt19937_64 gen {rng()};
31
+ std::uniform_int_distribution <std::size_t> dist;
32
+ return dist(gen);
33
+ }
34
+
35
+ } // detail
36
+
37
+ template<class>
38
+ std::uint64_t
39
+ make_salt()
40
+ {
41
+ std::random_device rng;
42
+ std::mt19937_64 gen {rng()};
43
+ std::uniform_int_distribution <std::size_t> dist;
44
+ return dist(gen);
45
+ }
46
+
47
+ template<
48
+ class Hasher,
49
+ class File,
50
+ class... Args
51
+ >
52
+ void
53
+ create(
54
+ path_type const& dat_path,
55
+ path_type const& key_path,
56
+ path_type const& log_path,
57
+ std::uint64_t appnum,
58
+ std::uint64_t salt,
59
+ nsize_t key_size,
60
+ nsize_t blockSize,
61
+ float load_factor,
62
+ error_code& ec,
63
+ Args&&... args)
64
+ {
65
+ static_assert(is_File<File>::value,
66
+ "File requirements not met");
67
+
68
+ using namespace detail;
69
+ if(key_size < 1)
70
+ {
71
+ ec = error::invalid_key_size;
72
+ return;
73
+ }
74
+ if(blockSize > field<std::uint16_t>::max)
75
+ {
76
+ ec = error::invalid_block_size;
77
+ return;
78
+ }
79
+ if(load_factor <= 0.f || load_factor >= 1.f)
80
+ {
81
+ ec = error::invalid_load_factor;
82
+ return;
83
+ }
84
+ auto const capacity =
85
+ bucket_capacity(blockSize);
86
+ if(capacity < 1)
87
+ {
88
+ ec = error::invalid_block_size;
89
+ return;
90
+ }
91
+ bool edf = false;
92
+ bool ekf = false;
93
+ bool elf = false;
94
+ {
95
+ File df(args...);
96
+ File kf(args...);
97
+ File lf(args...);
98
+ df.create(file_mode::append, dat_path, ec);
99
+ if(ec)
100
+ goto fail;
101
+ edf = true;
102
+ kf.create(file_mode::append, key_path, ec);
103
+ if(ec)
104
+ goto fail;
105
+ ekf = true;
106
+ lf.create(file_mode::append, log_path, ec);
107
+ if(ec)
108
+ goto fail;
109
+ elf = true;
110
+ dat_file_header dh;
111
+ dh.version = currentVersion;
112
+ dh.uid = make_uid();
113
+ dh.appnum = appnum;
114
+ dh.key_size = key_size;
115
+
116
+ key_file_header kh;
117
+ kh.version = currentVersion;
118
+ kh.uid = dh.uid;
119
+ kh.appnum = appnum;
120
+ kh.key_size = key_size;
121
+ kh.salt = salt;
122
+ kh.pepper = pepper<Hasher>(salt);
123
+ kh.block_size = blockSize;
124
+ kh.load_factor = std::min<std::size_t>(
125
+ static_cast<std::size_t>(
126
+ 65536.0 * load_factor), 65535);
127
+ write(df, dh, ec);
128
+ if(ec)
129
+ goto fail;
130
+ write(kf, kh, ec);
131
+ if(ec)
132
+ goto fail;
133
+ buffer buf{blockSize};
134
+ std::memset(buf.get(), 0, blockSize);
135
+ bucket b(blockSize, buf.get(), empty);
136
+ b.write(kf, blockSize, ec);
137
+ if(ec)
138
+ goto fail;
139
+ // VFALCO Leave log file empty?
140
+ df.sync(ec);
141
+ if(ec)
142
+ goto fail;
143
+ kf.sync(ec);
144
+ if(ec)
145
+ goto fail;
146
+ lf.sync(ec);
147
+ if(ec)
148
+ goto fail;
149
+ // Success
150
+ return;
151
+ }
152
+ fail:
153
+ if(edf)
154
+ erase_file(dat_path);
155
+ if(ekf)
156
+ erase_file(key_path);
157
+ if(elf)
158
+ erase_file(log_path);
159
+ }
160
+
161
+ } // nudb
162
+
163
+ #endif
@@ -0,0 +1,175 @@
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_IMPL_ERROR_IPP
9
+ #define NUDB_IMPL_ERROR_IPP
10
+
11
+ namespace nudb {
12
+
13
+ inline
14
+ error_category const&
15
+ nudb_category()
16
+ {
17
+ struct cat_t : public error_category
18
+ {
19
+ char const*
20
+ name() const noexcept override
21
+ {
22
+ return "nudb";
23
+ }
24
+
25
+ std::string
26
+ message(int ev) const override
27
+ {
28
+ switch(static_cast<error>(ev))
29
+ {
30
+ default:
31
+ case error::key_not_found:
32
+ return "key not found";
33
+
34
+ case error::key_exists:
35
+ return "key already exists";
36
+
37
+ case error::short_read:
38
+ return "short read";
39
+
40
+ case error::log_file_exists:
41
+ return "a log file exists";
42
+
43
+ case error::no_key_file:
44
+ return "no key file";
45
+
46
+ case error::too_many_buckets:
47
+ return "too many buckets";
48
+
49
+ case error::not_data_file:
50
+ return "not a data file";
51
+
52
+ case error::not_key_file:
53
+ return "not a key file";
54
+
55
+ case error::not_log_file:
56
+ return "not a log file";
57
+
58
+ case error::different_version:
59
+ return "different version";
60
+
61
+ case error::invalid_key_size:
62
+ return "invalid key size";
63
+
64
+ case error::invalid_block_size:
65
+ return "invalid block size";
66
+
67
+ case error::short_key_file:
68
+ return "short key file";
69
+
70
+ case error::short_bucket:
71
+ return "short bucket";
72
+
73
+ case error::short_spill:
74
+ return "short spill";
75
+
76
+ case error::short_data_record:
77
+ return "short data record";
78
+
79
+ case error::short_value:
80
+ return "short value";
81
+
82
+ case error::hash_mismatch:
83
+ return "hash mismatch";
84
+
85
+ case error::invalid_load_factor:
86
+ return "invalid load factor";
87
+
88
+ case error::invalid_capacity:
89
+ return "invalid capacity";
90
+
91
+ case error::invalid_bucket_count:
92
+ return "invalid bucket count";
93
+
94
+ case error::invalid_bucket_size:
95
+ return "invalid_bucket_size";
96
+
97
+ case error::incomplete_data_file_header:
98
+ return "incomplete data file header";
99
+
100
+ case error::incomplete_key_file_header:
101
+ return "incomplete key file header";
102
+
103
+ case error::invalid_log_record:
104
+ return "invalid log record";
105
+
106
+ case error::invalid_log_spill:
107
+ return "invalid spill in log";
108
+
109
+ case error::invalid_log_offset:
110
+ return "invalid offset in log";
111
+
112
+ case error::invalid_log_index:
113
+ return "invalid index in log";
114
+
115
+ case error::invalid_spill_size:
116
+ return "invalid size in spill";
117
+
118
+ case error::uid_mismatch:
119
+ return "uid mismatch";
120
+
121
+ case error::appnum_mismatch:
122
+ return "appnum mismatch";
123
+
124
+ case error::key_size_mismatch:
125
+ return "key size mismatch";
126
+
127
+ case error::salt_mismatch:
128
+ return "salt mismatch";
129
+
130
+ case error::pepper_mismatch:
131
+ return "pepper mismatch";
132
+
133
+ case error::block_size_mismatch:
134
+ return "block size mismatch";
135
+
136
+ case error::orphaned_value:
137
+ return "orphaned value";
138
+
139
+ case error::missing_value:
140
+ return "missing value";
141
+
142
+ case error::size_mismatch:
143
+ return "size mismatch";
144
+
145
+ case error::duplicate_value:
146
+ return "duplicate value";
147
+ }
148
+ }
149
+
150
+ error_condition
151
+ default_error_condition(int ev) const noexcept override
152
+ {
153
+ return error_condition{ev, *this};
154
+ }
155
+
156
+ bool
157
+ equivalent(int ev,
158
+ error_condition const& ec) const noexcept override
159
+ {
160
+ return ec.value() == ev && &ec.category() == this;
161
+ }
162
+
163
+ bool
164
+ equivalent(error_code const& ec, int ev) const noexcept override
165
+ {
166
+ return ec.value() == ev && &ec.category() == this;
167
+ }
168
+ };
169
+ static cat_t const cat{};
170
+ return cat;
171
+ }
172
+
173
+ } // nudb
174
+
175
+ #endif