rrudb 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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