Skip to content

Commit 3c4e463

Browse files
committed
Implement random access header and sequential body file and map.
1 parent 566e769 commit 3c4e463

File tree

9 files changed

+226
-111
lines changed

9 files changed

+226
-111
lines changed

include/bitcoin/database/file/utilities.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,9 @@ BCD_API bool copy_directory(const path& from, const path& to) NOEXCEPT;
7272
BCD_API code copy_directory_ex(const path& from, const path& to) NOEXCEPT;
7373

7474
/// File descriptor functions (for memory mapping).
75-
BCD_API int open(const path& filename) NOEXCEPT;
76-
BCD_API code open_ex(int& file_descriptor, const path& filename) NOEXCEPT;
75+
BCD_API int open(const path& filename, bool random=true) NOEXCEPT;
76+
BCD_API code open_ex(int& file_descriptor, const path& filename,
77+
bool random=true) NOEXCEPT;
7778
BCD_API bool close(int file_descriptor) NOEXCEPT;
7879
BCD_API code close_ex(int file_descriptor) NOEXCEPT;
7980
BCD_API bool size(size_t& out, int file_descriptor) NOEXCEPT;

include/bitcoin/database/impl/store.ipp

Lines changed: 39 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@
3131
namespace libbitcoin {
3232
namespace database {
3333

34+
constexpr auto random = true;
35+
constexpr auto sequential = false;
36+
3437
BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
3538

3639
// public
@@ -134,85 +137,85 @@ CLASS::store(const settings& config) NOEXCEPT
134137
// Archive.
135138
// ------------------------------------------------------------------------
136139

137-
header_head_(head(config.path / schema::dir::heads, schema::archive::header)),
138-
header_body_(body(config.path, schema::archive::header), config.header_size, config.header_rate),
140+
header_head_(head(config.path / schema::dir::heads, schema::archive::header), 1, 0, random),
141+
header_body_(body(config.path, schema::archive::header), config.header_size, config.header_rate, sequential),
139142
header(header_head_, header_body_, config.header_buckets),
140143

141-
input_head_(head(config.path / schema::dir::heads, schema::archive::input)),
142-
input_body_(body(config.path, schema::archive::input), config.input_size, config.input_rate),
144+
input_head_(head(config.path / schema::dir::heads, schema::archive::input), 1, 0, random),
145+
input_body_(body(config.path, schema::archive::input), config.input_size, config.input_rate, sequential),
143146
input(input_head_, input_body_),
144147

145-
output_head_(head(config.path / schema::dir::heads, schema::archive::output)),
146-
output_body_(body(config.path, schema::archive::output), config.output_size, config.output_rate),
148+
output_head_(head(config.path / schema::dir::heads, schema::archive::output), 1, 0, random),
149+
output_body_(body(config.path, schema::archive::output), config.output_size, config.output_rate, sequential),
147150
output(output_head_, output_body_),
148151

149-
point_head_(head(config.path / schema::dir::heads, schema::archive::point)),
150-
point_body_(body(config.path, schema::archive::point), config.point_size, config.point_rate),
152+
point_head_(head(config.path / schema::dir::heads, schema::archive::point), 1, 0, random),
153+
point_body_(body(config.path, schema::archive::point), config.point_size, config.point_rate, sequential),
151154
point(point_head_, point_body_, config.point_buckets),
152155

153-
ins_head_(head(config.path / schema::dir::heads, schema::archive::ins)),
154-
ins_body_(body(config.path, schema::archive::ins), config.ins_size, config.ins_rate),
156+
ins_head_(head(config.path / schema::dir::heads, schema::archive::ins), 1, 0, random),
157+
ins_body_(body(config.path, schema::archive::ins), config.ins_size, config.ins_rate, sequential),
155158
ins(ins_head_, ins_body_),
156159

157-
outs_head_(head(config.path / schema::dir::heads, schema::archive::outs)),
158-
outs_body_(body(config.path, schema::archive::outs), config.outs_size, config.outs_rate),
160+
outs_head_(head(config.path / schema::dir::heads, schema::archive::outs), 1, 0, random),
161+
outs_body_(body(config.path, schema::archive::outs), config.outs_size, config.outs_rate, sequential),
159162
outs(outs_head_, outs_body_),
160163

161-
tx_head_(head(config.path / schema::dir::heads, schema::archive::tx)),
162-
tx_body_(body(config.path, schema::archive::tx), config.tx_size, config.tx_rate),
164+
tx_head_(head(config.path / schema::dir::heads, schema::archive::tx), 1, 0, random),
165+
tx_body_(body(config.path, schema::archive::tx), config.tx_size, config.tx_rate, sequential),
163166
tx(tx_head_, tx_body_, config.tx_buckets),
164167

165-
txs_head_(head(config.path / schema::dir::heads, schema::archive::txs)),
166-
txs_body_(body(config.path, schema::archive::txs), config.txs_size, config.txs_rate),
168+
txs_head_(head(config.path / schema::dir::heads, schema::archive::txs), 1, 0, random),
169+
txs_body_(body(config.path, schema::archive::txs), config.txs_size, config.txs_rate, sequential),
167170
txs(txs_head_, txs_body_, config.txs_buckets),
168171

169172
// Indexes.
170173
// ------------------------------------------------------------------------
171174

172-
candidate_head_(head(config.path / schema::dir::heads, schema::indexes::candidate)),
173-
candidate_body_(body(config.path, schema::indexes::candidate), config.candidate_size, config.candidate_rate),
175+
candidate_head_(head(config.path / schema::dir::heads, schema::indexes::candidate), 1, 0, random),
176+
candidate_body_(body(config.path, schema::indexes::candidate), config.candidate_size, config.candidate_rate, sequential),
174177
candidate(candidate_head_, candidate_body_),
175178

176-
confirmed_head_(head(config.path / schema::dir::heads, schema::indexes::confirmed)),
177-
confirmed_body_(body(config.path, schema::indexes::confirmed), config.confirmed_size, config.confirmed_rate),
179+
confirmed_head_(head(config.path / schema::dir::heads, schema::indexes::confirmed), 1, 0, random),
180+
confirmed_body_(body(config.path, schema::indexes::confirmed), config.confirmed_size, config.confirmed_rate, sequential),
178181
confirmed(confirmed_head_, confirmed_body_),
179182

180-
strong_tx_head_(head(config.path / schema::dir::heads, schema::indexes::strong_tx)),
181-
strong_tx_body_(body(config.path, schema::indexes::strong_tx), config.strong_tx_size, config.strong_tx_rate),
183+
strong_tx_head_(head(config.path / schema::dir::heads, schema::indexes::strong_tx), 1, 0, random),
184+
strong_tx_body_(body(config.path, schema::indexes::strong_tx), config.strong_tx_size, config.strong_tx_rate, sequential),
182185
strong_tx(strong_tx_head_, strong_tx_body_, config.strong_tx_buckets),
183186

184187
// Caches.
185188
// ------------------------------------------------------------------------
186189

187-
duplicate_head_(head(config.path / schema::dir::heads, schema::caches::duplicate)),
188-
duplicate_body_(body(config.path, schema::caches::duplicate), config.duplicate_size, config.duplicate_rate),
190+
duplicate_head_(head(config.path / schema::dir::heads, schema::caches::duplicate), 1, 0, random),
191+
duplicate_body_(body(config.path, schema::caches::duplicate), config.duplicate_size, config.duplicate_rate, sequential),
189192
duplicate(duplicate_head_, duplicate_body_, config.duplicate_buckets),
190193

191-
prevout_head_(head(config.path / schema::dir::heads, schema::caches::prevout)),
192-
prevout_body_(body(config.path, schema::caches::prevout), config.prevout_size, config.prevout_rate),
194+
prevout_head_(head(config.path / schema::dir::heads, schema::caches::prevout), 1, 0, random),
195+
prevout_body_(body(config.path, schema::caches::prevout), config.prevout_size, config.prevout_rate, sequential),
193196
prevout(prevout_head_, prevout_body_, config.prevout_buckets),
194197

195-
validated_bk_head_(head(config.path / schema::dir::heads, schema::caches::validated_bk)),
196-
validated_bk_body_(body(config.path, schema::caches::validated_bk), config.validated_bk_size, config.validated_bk_rate),
198+
validated_bk_head_(head(config.path / schema::dir::heads, schema::caches::validated_bk), 1, 0, random),
199+
validated_bk_body_(body(config.path, schema::caches::validated_bk), config.validated_bk_size, config.validated_bk_rate, sequential),
197200
validated_bk(validated_bk_head_, validated_bk_body_, config.validated_bk_buckets),
198201

199-
validated_tx_head_(head(config.path / schema::dir::heads, schema::caches::validated_tx)),
200-
validated_tx_body_(body(config.path, schema::caches::validated_tx), config.validated_tx_size, config.validated_tx_rate),
202+
validated_tx_head_(head(config.path / schema::dir::heads, schema::caches::validated_tx), 1, 0, random),
203+
validated_tx_body_(body(config.path, schema::caches::validated_tx), config.validated_tx_size, config.validated_tx_rate, sequential),
201204
validated_tx(validated_tx_head_, validated_tx_body_, config.validated_tx_buckets),
202205

203206
// Optionals.
204207
// ------------------------------------------------------------------------
205208

206-
address_head_(head(config.path / schema::dir::heads, schema::optionals::address)),
207-
address_body_(body(config.path, schema::optionals::address), config.address_size, config.address_rate),
209+
address_head_(head(config.path / schema::dir::heads, schema::optionals::address), 1, 0, random),
210+
address_body_(body(config.path, schema::optionals::address), config.address_size, config.address_rate, sequential),
208211
address(address_head_, address_body_, config.address_buckets),
209212

210-
filter_bk_head_(head(config.path / schema::dir::heads, schema::optionals::filter_bk)),
211-
filter_bk_body_(body(config.path, schema::optionals::filter_bk), config.filter_bk_size, config.filter_bk_rate),
213+
filter_bk_head_(head(config.path / schema::dir::heads, schema::optionals::filter_bk), 1, 0, random),
214+
filter_bk_body_(body(config.path, schema::optionals::filter_bk), config.filter_bk_size, config.filter_bk_rate, sequential),
212215
filter_bk(filter_bk_head_, filter_bk_body_, config.filter_bk_buckets),
213216

214-
filter_tx_head_(head(config.path / schema::dir::heads, schema::optionals::filter_tx)),
215-
filter_tx_body_(body(config.path, schema::optionals::filter_tx), config.filter_tx_size, config.filter_tx_rate),
217+
filter_tx_head_(head(config.path / schema::dir::heads, schema::optionals::filter_tx), 1, 0, random),
218+
filter_tx_body_(body(config.path, schema::optionals::filter_tx), config.filter_tx_size, config.filter_tx_rate, sequential),
216219
filter_tx(filter_tx_head_, filter_tx_body_, config.filter_tx_buckets),
217220

218221
// Locks.

include/bitcoin/database/memory/map.hpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ class BCD_API map
4343
DELETE_COPY_MOVE(map);
4444

4545
map(const std::filesystem::path& filename, size_t minimum=1,
46-
size_t expansion=0) NOEXCEPT;
46+
size_t expansion=0, bool random=true) NOEXCEPT;
4747

4848
/// Destruct for debug assertion only.
4949
virtual ~map() NOEXCEPT;
@@ -136,10 +136,14 @@ class BCD_API map
136136
bool resize_(size_t size) NOEXCEPT;
137137
bool finalize_(size_t size) NOEXCEPT;
138138

139+
////void log(auto kind) NOEXCEPT;
140+
////void log(auto kind, auto extra) NOEXCEPT;
141+
139142
// Constants.
140143
const std::filesystem::path filename_;
141144
const size_t minimum_;
142145
const size_t expansion_;
146+
const bool random_;
143147

144148
// Protected by remap_mutex.
145149
// requires remap_mutex_ exclusive lock for write.

src/file/utilities.cpp

Lines changed: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -242,29 +242,62 @@ code copy_directory_ex(const path& from, const path& to) NOEXCEPT
242242

243243
// File descriptor functions required for memory mapping.
244244

245-
int open(const path& filename) NOEXCEPT
245+
#if defined(HAVE_MSC) || !defined(HAVE_APPLE)
246+
#define MSC_OR_NOAPPLE(parameter) parameter
247+
#else
248+
#define MSC_OR_NOAPPLE(parameter)
249+
#endif
250+
251+
int open(const path& filename, bool MSC_OR_NOAPPLE(random)) NOEXCEPT
246252
{
247253
const auto path = system::to_extended_path(filename);
248254
int file_descriptor{};
249255

250-
// _wsopen_s and open set errno on failure.
251-
// _wsopen_s and wstring do not throw (but are unannotated).
252256
#if defined(HAVE_MSC)
253-
// sets file_descriptor = -1 on error.
254-
_wsopen_s(&file_descriptor, path.c_str(),
255-
O_RDWR | _O_BINARY | _O_RANDOM, _SH_DENYWR, _S_IREAD | _S_IWRITE);
257+
// _wsopen_s and wstring do not throw (but are unannotated).
258+
// sets file_descriptor = -1 and errno on error.
259+
const auto access = (random ? _O_RANDOM : _O_SEQUENTIAL);
260+
::_wsopen_s(&file_descriptor, path.c_str(),
261+
O_RDWR | _O_BINARY | access, _SH_DENYWR, _S_IREAD | _S_IWRITE);
256262
#else
257-
// returns -1 on failure.
258-
file_descriptor = ::open(path.c_str(),
259-
O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
260-
#endif
263+
// open sets errno on failure.
264+
file_descriptor = ::open(path.c_str(), O_RDWR, S_IRUSR | S_IWUSR);
265+
266+
#if !defined(HAVE_APPLE)
267+
if (file_descriptor != -1)
268+
{
269+
// _O_RANDOM equivalent, posix_fadvise returns error on failure.
270+
const auto advice = random ? POSIX_FADV_RANDOM : POSIX_FADV_SEQUENTIAL;
271+
const auto result = ::posix_fadvise(file_descriptor, 0, 0, advice);
272+
if (!is_zero(result))
273+
{
274+
close(file_descriptor);
275+
file_descriptor = -1;
276+
errno = result;
277+
}
278+
else
279+
{
280+
// _SH_DENYWR equivalent.
281+
const struct flock lock{ F_WRLCK, SEEK_SET, 0, 0 };
282+
if (::fcntl(file_descriptor, F_SETLK, &lock) == -1)
283+
{
284+
const auto last = errno;
285+
close(file_descriptor);
286+
file_descriptor = -1;
287+
errno = last;
288+
}
289+
}
290+
}
291+
#endif // !HAVE_APPLE
292+
#endif // HAVE_MSC
293+
261294
return file_descriptor;
262295
}
263296

264-
code open_ex(int& file_descriptor, const path& filename) NOEXCEPT
297+
code open_ex(int& file_descriptor, const path& filename, bool random) NOEXCEPT
265298
{
266299
system::error::clear_errno();
267-
file_descriptor = open(filename);
300+
file_descriptor = open(filename, random);
268301
return system::error::get_errno();
269302
}
270303

0 commit comments

Comments
 (0)