40 namespace section_detail {
41 inline constexpr std::uint16_t
version = 2;
68 inline std::uint64_t
align(std::uint64_t value)
noexcept {
69 return (value + 7) & ~std::uint64_t{7};
71 inline void zero(std::span<std::byte const> bytes,
char const * message) {
72 for (
auto byte : bytes)
if (
byte != std::byte{0})
throw std::invalid_argument(message);
74 inline unsigned hex_value(
char c)
noexcept {
return unsigned(c <=
'9' ? c -
'0' : c -
'a' + 10); }
75 inline void put_id(std::span<std::byte> bytes, std::size_t at,
object_id const &
id) {
76 auto const & text =
id.hex();
77 if (text.size() != 32)
throw std::invalid_argument(
"invalid Everett section object identity");
78 if (at > bytes.size() || 16 > bytes.size() - at)
79 throw std::out_of_range(
"Everett section identity position");
80 for (std::size_t i = 0; i != 16; ++i)
84 constexpr char hex[] =
"0123456789abcdef";
85 std::string text(32,
'0');
86 for (std::size_t i = 0; i != 16; ++i) {
87 auto byte = std::to_integer<unsigned>(bytes[at + i]);
88 text[2 * i] = hex[
byte >> 4];
89 text[2 * i + 1] = hex[
byte & 15];
93 inline std::span<std::byte const>
section(std::span<std::byte const> body,
94 directory const & layout, std::size_t slot) {
95 if (slot >= layout.
count)
throw std::out_of_range(
"Everett section slot");
96 auto const & part = layout.
sections[slot];
97 if (part.offset > body.size() || part.length > body.size() - part.offset)
98 throw std::invalid_argument(
"Everett section exceeds body");
99 return body.subspan(
static_cast<std::size_t
>(part.offset),
static_cast<std::size_t
>(part.length));
105 result.
count = index ? 9 : 5;
108 if (body.size() > std::numeric_limits<std::uint64_t>::max() - 7)
109 throw std::invalid_argument(
"Everett section container extent overflows");
110 if (body.size() < result.
bytes)
throw std::invalid_argument(
"truncated Everett section directory");
112 throw std::invalid_argument(
"Everett section container must occupy complete bytes");
113 auto magic = index ?
"IX02" :
"KV02";
114 for (
unsigned i = 0; i != 4; ++i)
115 if (std::to_integer<unsigned>(body[i]) !=
unsigned(magic[i]))
116 throw std::invalid_argument(
"unexpected Everett section magic");
118 throw std::invalid_argument(
"unsupported Everett section directory");
125 if (target > 1)
throw std::invalid_argument(
"invalid Everett target flag");
126 zero(body.subspan(34, 6),
"nonzero Everett directory reserved bytes");
127 zero(body.subspan(96, 16),
"nonzero Everett directory reserved bytes");
130 throw std::invalid_argument(
"borrowed records exceed virtual count");
133 else zero(body.subspan(64, 32),
"absent Everett target must encode zero");
134 }
else zero(body.subspan(33, 15),
"nonzero Everett directory reserved bytes");
135 std::uint64_t end = result.
bytes;
136 for (std::size_t i = 0; i != result.
count; ++i) {
139 if (part.offset !=
align(end) || part.offset > body.size() || part.length > body.size() - part.offset)
140 throw std::invalid_argument(
"noncanonical Everett section range");
141 end = part.offset + part.length;
144 if (end != body.size())
throw std::invalid_argument(
"trailing Everett section bytes");
148 std::size_t end = layout.
bytes;
149 for (std::size_t i = 0; i != layout.
count; ++i) {
150 auto const & part = layout.
sections[i];
151 zero(body.subspan(end,
static_cast<std::size_t
>(part.offset) - end),
"nonzero Everett section alignment padding");
152 end =
static_cast<std::size_t
>(part.offset + part.length);
157 auto metadata = profile_detail::initial_metadata<P, Role>();
159 metadata.extent = layout.
extent;
164 auto part = [&](std::size_t slot) {
return section(body, layout, slot); };
171 result.validate_offset_metadata();
175 if (actual.
size() != expected.size())
throw std::invalid_argument(message);
176 for (std::size_t i = 0; i != expected.size(); ++i)
177 if (actual[i] != expected[i])
throw std::invalid_argument(message);
181 auto const & metadata = view.
metadata();
183 std::vector<std::uint64_t> residuals;
185 if (groups == std::numeric_limits<std::uint64_t>::max() || groups + 1 > residuals.max_size())
186 throw std::length_error(
"Everett scan offset count");
187 residuals.reserve(
static_cast<std::size_t
>(groups + 1));
189 std::uint64_t at = 0, previous_units = 0;
191 for (std::uint64_t ordinal = 0; ordinal != metadata.record_count; ++ordinal) {
192 std::uint64_t retained;
193 if (ordinal % P::codec_block_size == 0) {
195 if (stride > at)
throw std::invalid_argument(
"Everett fixed values exceed physical position");
196 residuals.push_back(at - stride);
197 retained = profile_detail::read_count<P>(data, at);
198 if (retained > previous_units)
199 throw std::invalid_argument(
"Everett profile absolute prefix exceeds predecessor");
201 auto backspace = profile_detail::read_backspace<P>(data, at);
202 if (backspace > previous_units)
throw std::invalid_argument(
"Everett profile backspace exceeds predecessor");
203 retained = previous_units - backspace;
205 auto suffix = profile_detail::read_count<P>(data, at);
206 auto values = metadata.common_value_width ? *metadata.common_value_width : profile_detail::read_count<P>(data, at);
211 if (start_bits > data.
size() || suffix_bits > data.
size() - start_bits ||
212 value_bits > data.
size() - start_bits - suffix_bits)
213 throw std::invalid_argument(
"truncated Everett profile record");
218 if (retained < previous_units) {
219 if (!suffix)
throw std::invalid_argument(
"Everett profile key precedes its predecessor");
223 throw std::invalid_argument(
"Everett profile keys are not sorted");
224 if (after == before) {
225 auto order = compare_bits<typename P::architecture>(previous.
view().
subview(retained_bits + P::bits_per_unit,
226 previous.
view().
size() - retained_bits - P::bits_per_unit),
227 data.
subview(start_bits + P::bits_per_unit, suffix_bits - P::bits_per_unit));
228 if (order > 0)
throw std::invalid_argument(
"Everett profile keys are not sorted");
230 throw std::invalid_argument(
"Everett native profile keys must be unique");
233 throw std::invalid_argument(
"Everett native profile keys must be unique");
237 previous_units = length;
239 if (at != metadata.extent || previous_units != metadata.terminal_key_units)
240 throw std::invalid_argument(
"Everett terminal profile extent or length mismatch");
242 if (stride > at)
throw std::invalid_argument(
"Everett fixed payload exceeds extent");
243 residuals.push_back(at - stride);
244 auto expected = elias_fano::build<typename P::architecture>(residuals);
245 if (expected.universe != offsets.universe() || expected.low_width != offsets.low_width())
246 throw std::invalid_argument(
"noncanonical Everett Elias-Fano parameters");
247 equal_words(offsets.low_words(), expected.low,
"Everett Elias-Fano low words mismatch");
248 equal_words(offsets.high_words(), expected.high,
"Everett Elias-Fano high words mismatch");
249 equal_words(offsets.sparse_words(), expected.sparse,
"Everett Elias-Fano sparse words mismatch");
250 auto actual_samples = offsets.samples();
251 if (actual_samples.size() != expected.samples.size())
throw std::invalid_argument(
"Everett Elias-Fano sample count mismatch");
252 for (std::size_t i = 0; i != expected.samples.size(); ++i) {
253 auto a = actual_samples[i];
254 auto b = expected.samples[i];
255 if (a.first != b.first || a.sparse != b.sparse)
throw std::invalid_argument(
"Everett Elias-Fano sample mismatch");
273 if (
this != &other) {
284 std::vector<std::span<std::
byte const>>
chunks() const & {
286 std::vector<std::span<std::byte const>> result;
287 result.reserve(2 *
sections_.size() + 1);
292 if (gap) result.push_back(std::span(
zero_).first(
static_cast<std::size_t
>(gap)));
293 result.push_back(section);
294 end += gap + section.size();
298 std::vector<std::span<std::byte const>>
chunks() const && = delete;
301 std::vector<std::byte> body;
302 auto size = file_detail::body_bytes<P>(
header_.extent);
303 if (size > body.max_size())
throw std::length_error(
"Everett section body too large");
304 body.reserve(
static_cast<std::size_t
>(size));
305 for (
auto chunk :
chunks()) body.insert(body.end(), chunk.begin(), chunk.end());
317 std::optional<blob_identity>);
319 std::optional<blob_identity>);
322 if (!
directory_size_)
throw std::logic_error(
"Everett section encoding has no source");
325 std::array<std::byte, section_detail::index_directory_bytes>
directory_{};
331 void words(std::span<std::uint64_t const> values) {
332 if constexpr (std::endian::native == std::endian::little)
sections_.push_back(std::as_bytes(values));
334 auto & bytes =
converted_.emplace_back(values.size() << 3);
335 for (std::size_t i = 0; i != values.size(); ++i)
file_detail::put(bytes, (i << 3), 8, values[i]);
339 void samples(std::span<elias_fano_sample const> values) {
342 if constexpr (std::endian::native == std::endian::little)
sections_.push_back(std::as_bytes(values));
344 auto & bytes =
converted_.emplace_back(values.size() << 4);
345 for (std::size_t i = 0; i != values.size(); ++i) {
356 auto const & metadata = array.
metadata();
358 header_.common_value_width = metadata.common_value_width;
359 header_.policy_value_width = metadata.policy_fixed_values
360 ? std::optional(metadata.policy_value_width) : std::nullopt;
366 template <
class Index>
void index(Index
const & source,
object_id const & native_id,
367 std::optional<blob_identity>
const & exact_target) {
369 words(source.interleave().classes);
370 words(source.interleave().checkpoints);
371 sections_.push_back(source.false_borrow_bits());
372 words(source.cut_lcps());
387 auto magic =
index ?
"IX02" :
"KV02";
388 for (
unsigned i = 0; i != 4; ++i)
directory_[i] = std::byte(magic[i]);
392 for (std::size_t i = 0; i !=
sections_.size(); ++i) {
393 if (end > std::numeric_limits<std::uint64_t>::max() - 7)
394 throw std::overflow_error(
"Everett section alignment overflows");
414 object_id const & native_id, std::optional<blob_identity> exact_target = std::nullopt) {
415 if ((!exact_target && (pair.target() || pair.borrowed().size())) ||
416 (pair.target() && pair.borrowed().size() != pair.target()->group_count()))
417 throw std::invalid_argument(
"Everett index encoding needs its exact bound target");
419 result.
index(pair, native_id, exact_target);
423 std::optional<blob_identity> = std::nullopt) =
delete;
429 object_id const & native_id, std::optional<blob_identity> exact_target = std::nullopt) {
431 throw std::invalid_argument(
"Everett index encoding needs its exact bound target");
433 result.
index(index, native_id, exact_target);
437 std::optional<blob_identity> = std::nullopt) =
delete;
445 auto header = source.
header();
447 if (header.kind != kind)
throw std::invalid_argument(
"Everett mapped profile kind mismatch");
448 auto body = source.
body();
450 auto view = section_detail::profile<P, Role>(header, body.bytes(),
layout);
451 return {std::move(source), std::move(body), std::move(
layout), std::move(
view)};
463 std::span<std::
byte const>
section(std::
size_t slot) const & {
466 std::span<std::byte const>
section(std::size_t)
const && =
delete;
475 if (!
active())
throw std::logic_error(
"Everett mapped profile has no mapping");
491 auto const &
layout = profile.layout();
496 if (profile.
size() > std::numeric_limits<std::uint64_t>::max() - 7 ||
498 ((profile.
size() + 7) >> 3))
499 throw std::invalid_argument(
"Everett index navigation shape mismatch");
500 return {std::move(profile), std::move(ranks), cuts};
519 std::optional<blob_identity>
const &
target_id() const && = delete;
524 std::span<std::byte const>
section(std::size_t)
const && =
delete;
527 std::vector<std::uint64_t> classes;
529 if (groups > classes.max_size())
throw std::length_error(
"Everett rank scan size");
530 classes.reserve(
static_cast<std::size_t
>(groups));
531 for (std::uint64_t group = 0; group != groups; ++group) classes.push_back(
ranks_.
class_at(group));
533 if (expected.view().count() !=
borrowed().size())
throw std::invalid_argument(
"Everett rank total mismatch");
537 if (
auto tail = (
borrowed().size() & 7))
538 if ((std::to_integer<unsigned>(flags.back()) >> tail) != 0)
539 throw std::invalid_argument(
"nonzero Everett false-borrow padding");
543 if (!
profile_.
active())
throw std::logic_error(
"Everett mapped index has no mapping");
void put(std::span< std::byte > bytes, std::size_t at, unsigned width, std::uint64_t value) noexcept
Definition file.h:70
void validate_metadata(file_header< P > const &header)
Definition file.h:93
std::uint64_t get(std::span< std::byte const > bytes, std::size_t at, unsigned width) noexcept
Definition file.h:65
std::uint64_t add(std::uint64_t a, std::uint64_t b)
Definition profile.h:39
std::uint64_t multiply(std::uint64_t a, std::uint64_t b)
Definition profile.h:44
void resize(bit_string &value, std::uint64_t bits)
Definition profile.h:465
std::uint64_t load_bits(bit_view data, std::uint64_t first, unsigned width) noexcept
Definition profile.h:93
void append(bit_string &target, bit_view source)
Definition profile.h:480
object_id get_id(std::span< std::byte const > bytes, std::size_t at)
Definition sections.h:83
std::uint64_t align(std::uint64_t value) noexcept
Definition sections.h:68
constexpr std::size_t native_directory_bytes
Definition sections.h:42
constexpr std::size_t low
Definition sections.h:47
constexpr std::size_t native_descriptor_offset
Definition sections.h:44
void scan_profile(profile_view< P, Role > const &view)
Definition sections.h:179
void validate_gaps(std::span< std::byte const > body, directory const &layout)
Definition sections.h:147
constexpr std::size_t checkpoints
Definition sections.h:48
constexpr std::size_t index_descriptor_offset
Definition sections.h:45
constexpr std::size_t descriptor_bytes
Definition sections.h:46
void put_id(std::span< std::byte > bytes, std::size_t at, object_id const &id)
Definition sections.h:75
constexpr std::size_t samples
Definition sections.h:47
constexpr std::size_t index_directory_bytes
Definition sections.h:43
constexpr std::size_t sparse
Definition sections.h:47
constexpr std::size_t high
Definition sections.h:47
constexpr std::size_t fc
Definition sections.h:47
void equal_words(word_view actual, std::span< std::uint64_t const > expected, char const *message)
Definition sections.h:174
constexpr std::uint16_t version
Definition sections.h:41
constexpr std::size_t classes
Definition sections.h:48
directory parse(file_header< P > const &header, std::span< std::byte const > body)
Definition sections.h:102
constexpr std::size_t cut_lcps
Definition sections.h:48
constexpr std::size_t false_borrows
Definition sections.h:48
void zero(std::span< std::byte const > bytes, char const *message)
Definition sections.h:71
std::span< std::byte const > section(std::span< std::byte const > body, directory const &layout, std::size_t slot)
Definition sections.h:93
profile_view< P, Role > profile(file_header< P > const &header, std::span< std::byte const > body, directory const &layout)
Definition sections.h:155
unsigned hex_value(char c) noexcept
Definition sections.h:74
Definition active_engine.h:18
encoded_sections< P > encode_index_sections(profile_blob< P > const &pair, object_id const &native_id, std::optional< blob_identity > exact_target=std::nullopt)
Definition sections.h:413
file_open_mode
Definition file.h:32
std::vector< std::byte > encode_file(file_header< P > const &header, std::span< std::byte const > body)
Definition file.h:221
encoded_sections< P > encode_native_sections(profile_array< P, stream_role::native > const &native)
Definition sections.h:405
file_kind
Definition object_path.h:25
Streams and seals immutable object files without catalog publication.
Declares Everett's profile blob support.
bit_view view() const &
Definition profile.h:178
std::uint64_t size() const noexcept
Definition profile.h:64
bit_view subview(std::uint64_t first, std::uint64_t count) const
Definition profile.h:73
bool operator==(blob_identity const &) const =default
object_id index
Definition sections.h:36
object_id native
Definition sections.h:35
Definition elias_fano.h:195
Definition elias_fano.h:212
Definition sections.h:264
encoded_sections & operator=(encoded_sections const &)=delete
encoded_sections(encoded_sections const &)=delete
std::vector< std::byte > materialize() const
Definition sections.h:299
std::vector< std::span< std::byte const > > sections_
Definition sections.h:328
void samples(std::span< elias_fano_sample const > values)
Definition sections.h:339
P policy_type
Definition sections.h:265
void require_active() const
Definition sections.h:321
friend encoded_sections< Q > encode_native_sections(profile_array< Q, stream_role::native > const &)
file_header< P > const & header() const &&=delete
encoded_sections(encoded_sections &&other) noexcept
Definition sections.h:268
void finish(file_kind kind)
Definition sections.h:382
encoded_sections()=default
friend encoded_sections< Q > encode_index_sections(profile_index< Q > const &, object_id const &, std::optional< blob_identity >)
void profile(profile_array< P, Role > const &array)
Definition sections.h:352
file_header< P > header_
Definition sections.h:324
std::vector< std::vector< std::byte > > converted_
Definition sections.h:329
object_seal_receipt seal(std::filesystem::path const &root, object_id const &id, object_attempt_id const &attempt) const
Definition sections.h:308
friend encoded_sections< Q > encode_index_sections(profile_blob< Q > const &, object_id const &, std::optional< blob_identity >)
std::array< std::byte, section_detail::index_directory_bytes > directory_
Definition sections.h:325
std::size_t directory_size_
Definition sections.h:327
std::vector< std::span< std::byte const > > chunks() const &&=delete
file_header< P > const & header() const &
Definition sections.h:280
std::vector< std::span< std::byte const > > chunks() const &
Definition sections.h:284
void words(std::span< std::uint64_t const > values)
Definition sections.h:331
void index(Index const &source, object_id const &native_id, std::optional< blob_identity > const &exact_target)
Definition sections.h:366
encoded_sections & operator=(encoded_sections &&other) noexcept
Definition sections.h:272
std::array< std::byte, 8 > zero_
Definition sections.h:326
file_header< P > header() const
Definition file.h:268
mapped_slice body() const
Definition file.h:269
Definition sections.h:486
static mapped_index open(std::filesystem::path const &path)
Definition sections.h:502
word_view cut_lcps() const &
Definition sections.h:514
rank_groups_view< P::group_size > ranks_
Definition sections.h:548
object_id const & native_id() const &
Definition sections.h:516
mapped_index(mapped_profile< P, stream_role::borrowed > profile, rank_groups_view< P::group_size > ranks, word_view cuts)
Definition sections.h:545
std::span< std::byte const > section(std::size_t slot) const &
Definition sections.h:523
rank_groups_view< P::group_size > interleave() const &
Definition sections.h:508
word_view cut_lcps() const &&=delete
rank_groups_view< P::group_size > interleave() const &&=delete
std::optional< blob_identity > const & target_id() const &&=delete
std::span< std::byte const > false_borrow_bits() const &&=delete
void scan() const
Definition sections.h:525
std::span< std::byte const > false_borrow_bits() const &
Definition sections.h:512
static mapped_index open(file< P > source)
Definition sections.h:488
static mapped_index from_slice(mapped_slice source, file_open_mode mode=file_open_mode::checked)
Definition sections.h:503
object_id const & native_id() const &&=delete
std::optional< blob_identity > const & target_id() const &
Definition sections.h:518
word_view cuts_
Definition sections.h:549
section_detail::directory const & layout() const &&=delete
profile_view< P, stream_role::borrowed > borrowed() const &
Definition sections.h:506
std::uint64_t virtual_size() const
Definition sections.h:520
P policy_type
Definition sections.h:487
profile_view< P, stream_role::borrowed > borrowed() const &&=delete
void require_active() const
Definition sections.h:542
mapped_profile< P, stream_role::borrowed > profile_
Definition sections.h:547
std::span< std::byte const > section(std::size_t) const &&=delete
section_detail::directory const & layout() const &
Definition sections.h:521
Definition sections.h:442
void scan() const
Definition sections.h:467
mapped_slice body_
Definition sections.h:480
section_detail::directory const & layout() const &
Definition sections.h:461
static mapped_profile from_slice(mapped_slice source, file_open_mode mode=file_open_mode::checked)
Definition sections.h:454
std::uint64_t size() const
Definition sections.h:460
profile_view< P, Role > view_
Definition sections.h:482
section_detail::directory layout_
Definition sections.h:481
profile_view< P, Role > view() const &&=delete
bool active() const noexcept
Definition sections.h:457
void require_active() const
Definition sections.h:474
section_detail::directory const & layout() const &&=delete
std::span< std::byte const > section(std::size_t) const &&=delete
static mapped_profile open(std::filesystem::path const &path)
Definition sections.h:453
mapped_profile(file< P > source, mapped_slice body, section_detail::directory layout, profile_view< P, Role > view)
Definition sections.h:477
P policy_type
Definition sections.h:443
std::span< std::byte const > section(std::size_t slot) const &
Definition sections.h:463
file< P > source_
Definition sections.h:479
static mapped_profile open(file< P > source)
Definition sections.h:444
profile_view< P, Role > view() const &
Definition sections.h:458
Definition mapped_file.h:81
std::span< std::byte const > bytes() const &noexcept
Definition mapped_file.h:99
bool empty() const noexcept
Definition mapped_file.h:97
Definition object_writer.h:39
Definition object_path.h:38
Definition object_writer.h:88
static object_seal_receipt seal(std::filesystem::path const &root, object_id const &id, object_attempt_id const &attempt, file_header< P > const &header, std::span< std::span< std::byte const > const > chunks, Ops &ops)
Definition object_writer.h:164
Definition profile.h:1168
elias_fano const & group_offsets() const noexcept
Definition profile.h:1243
std::uint64_t size() const noexcept
Definition profile.h:1240
profile_metadata const & metadata() const noexcept
Definition profile.h:1242
std::span< std::byte const > bytes() const noexcept
Definition profile.h:1241
Definition profile_blob.h:187
Definition profile_index.h:39
borrowed_array const & borrowed() const &noexcept
Definition profile_index.h:55
std::span< std::byte const > bytes() const noexcept
Definition profile.h:749
elias_fano_view group_offsets() const noexcept
Definition profile.h:751
void validate_contents() const
Definition profile.h:716
std::uint64_t block_count() const noexcept
Definition profile.h:734
static profile_view from_sections(std::span< std::byte const > bytes, elias_fano_view offsets, profile_metadata metadata)
Definition profile.h:708
std::uint64_t size() const noexcept
Definition profile.h:748
profile_metadata const & metadata() const noexcept
Definition profile.h:750
Definition rank_groups.h:127
word_view checkpoint_words() const noexcept
Definition rank_groups.h:166
std::uint64_t group_count() const noexcept
Definition rank_groups.h:162
std::uint64_t class_at(std::uint64_t group) const
Definition rank_groups.h:167
word_view class_words() const noexcept
Definition rank_groups.h:165
static rank_groups build(std::span< std::uint64_t const > source, std::uint64_t count)
Definition rank_groups.h:247
static sample_view little_endian(std::span< std::byte const > bytes)
Definition word_view.h:92
bool operator==(descriptor const &) const =default
std::uint64_t offset
Definition sections.h:51
std::uint64_t length
Definition sections.h:52
std::optional< object_id > native_id
Definition sections.h:64
std::optional< blob_identity > target_id
Definition sections.h:65
std::size_t count
Definition sections.h:57
std::uint64_t extent
Definition sections.h:59
std::uint64_t virtual_count
Definition sections.h:63
std::uint64_t terminal_key_units
Definition sections.h:60
unsigned low_width
Definition sections.h:62
std::size_t bytes
Definition sections.h:58
std::uint64_t universe
Definition sections.h:61
std::array< descriptor, 9 > sections
Definition sections.h:56
Definition word_view.h:31
static word_view little_endian(std::span< std::byte const > bytes)
Definition word_view.h:36
std::size_t size() const noexcept
Definition word_view.h:41
Borrows native or little-endian directory words and select samples.