Everett
Loading...
Searching...
No Matches
mapped_blob.h
Go to the documentation of this file.
1
13#pragma once
14
15#include <everett/query.h>
16#include <everett/sections.h>
17
18#include <memory>
19#include <optional>
20#include <stdexcept>
21#include <string>
22#include <unordered_map>
23#include <unordered_set>
24#include <utility>
25#include <vector>
26
27namespace everett {
28 // Pins two physical files and their exact downstream pair. Bind checks
29 // identity declarations and shapes; scan checks contents and sampled keys.
30 // The caller/catalog vouches for each owner's opaque physical identity.
31 template <class P> struct mapped_blob {
32 using policy_type = P;
33 using pair_type = std::shared_ptr<mapped_blob const>;
36 mapped_blob(mapped_blob const &) = delete;
37 mapped_blob & operator=(mapped_blob const &) = delete;
40
41 static pair_type bind(blob_identity identity, std::shared_ptr<native_type const> native,
42 std::shared_ptr<index_type const> index, pair_type target = {}) {
43 if (!native || !index) throw std::invalid_argument("null Everett mapped pair component");
44 if (identity.native != index->native_id()) throw std::invalid_argument("Everett index names another native object");
45 auto const & expected = index->target_id();
46 if (bool(expected) != bool(target) || (expected && *expected != target->identity()))
47 throw std::invalid_argument("Everett mapped pair target identity mismatch");
48 if (index->borrowed().size() != (target ? target->group_count() : 0))
49 throw std::invalid_argument("Everett mapped pair sample count mismatch");
50 profile_blob_view<P> view(native->view(), index->borrowed(), index->interleave(),
51 index->false_borrow_bits(), index->cut_lcps(), index->virtual_size());
52 return pair_type(new mapped_blob(std::move(identity), std::move(native), std::move(index),
53 std::move(target), std::move(view)));
54 }
55
56 blob_identity const & identity() const & noexcept { return identity_; }
57 blob_identity const & identity() const && = delete;
58 std::shared_ptr<native_type const> native_object() const noexcept { return native_; }
59 std::shared_ptr<index_type const> index_object() const noexcept { return index_; }
60 pair_type target() const noexcept { return target_; }
61 profile_view<P, stream_role::native> native() const & { return view_.native(); }
63 profile_view<P, stream_role::borrowed> borrowed() const & { return view_.borrowed(); }
65 profile_blob_view<P> view() const & { return view_; }
66 profile_blob_view<P> view() const && = delete;
67 rank_groups_view<P::group_size> interleave() const & noexcept { return view_.interleave(); }
69 word_view cut_lcps() const & noexcept { return view_.cut_lcps(); }
70 word_view cut_lcps() const && = delete;
71 std::uint64_t virtual_size() const noexcept { return view_.virtual_size(); }
72 std::uint64_t group_count() const noexcept { return view_.group_count(); }
73 bool false_borrow(std::uint64_t ordinal) const { return view_.false_borrow(ordinal); }
74 profile_blob_window project(std::uint64_t group) const { return view_.project(group); }
76 profile_query_context<P> const & lower, profile_comparison_work * native_work = nullptr,
77 profile_comparison_work * borrowed_work = nullptr) const {
78 return view_.search_window(group, lower, native_work, borrowed_work);
79 }
80
81 // Explicit complete-chain scan. Reconstructs sequential keys and rebuilds
82 // compact directories as scratch; it does not materialize all full keys.
83 // Success attests current readable bytes, not recovery from a failed fsync.
84 void scan() const {
85 std::unordered_set<mapped_blob const *> seen;
86 std::unordered_set<native_type const *> native_seen;
87 for (auto current = this; current; current = current->target_.get()) {
88 if (!seen.insert(current).second) throw std::invalid_argument("cyclic Everett mapped chain");
89 if (native_seen.insert(current->native_.get()).second) current->native_->scan();
90 current->index_->scan();
91 current->scan_pair();
92 current->scan_samples();
93 }
94 }
95
96 private:
98 std::shared_ptr<native_type const> native_;
99 std::shared_ptr<index_type const> index_;
102
103 mapped_blob(blob_identity identity, std::shared_ptr<native_type const> native,
104 std::shared_ptr<index_type const> index, pair_type target, profile_blob_view<P> view)
105 : identity_(std::move(identity)), native_(std::move(native)), index_(std::move(index)),
106 target_(std::move(target)), view_(std::move(view)) {}
107
111 explicit merged_cursor(mapped_blob const & source) : native(source.native()), borrowed(source.borrowed()) {}
112 bool done() const noexcept { return native.done() && borrowed.done(); }
113 bool is_borrowed() const {
114 if (done()) throw std::out_of_range("Everett merged cursor at end");
115 return !borrowed.done() && (native.done() ||
116 compare_bits<typename P::architecture>(borrowed.peek().key.prefix, native.peek().key.prefix) < 0);
117 }
118 bit_view key() const { return is_borrowed() ? borrowed.peek().key.prefix : native.peek().key.prefix; }
119 void advance() { if (is_borrowed()) borrowed.advance(); else native.advance(); }
120 };
121
122 void scan_pair() const {
123 merged_cursor cursor(*this);
124 bit_string previous_native, previous_borrowed;
125 bool had_native = false;
126 std::uint64_t ordinal = 0, borrowed_count = 0, population = 0;
127 auto ranks = interleave();
128 auto cuts = cut_lcps();
129 while (!cursor.done()) {
130 auto key = cursor.key();
131 auto group = ordinal / P::group_size;
132 if (ordinal % P::group_size == 0) {
133 auto lcp = borrowed_count ? compare_common_bits<typename P::architecture>(previous_borrowed.view(), key).common_bits : 0;
134 if (cuts[group] != lcp) throw std::invalid_argument("Everett cut LCP disagrees with keys");
135 if (ranks.template rank<typename P::architecture>(group) != borrowed_count) throw std::invalid_argument("Everett rank disagrees with interleaving");
136 population = 0;
137 }
138 if (cursor.is_borrowed()) {
139 bool expected = had_native && compare_bits<typename P::architecture>(previous_native.view(), key) == 0;
140 if (false_borrow(borrowed_count) != expected)
141 throw std::invalid_argument("Everett false-borrow flag disagrees with keys");
142 previous_borrowed = bit_string::copy(key);
143 ++borrowed_count;
144 ++population;
145 } else {
146 previous_native = bit_string::copy(key);
147 had_native = true;
148 }
149 cursor.advance();
150 ++ordinal;
151 if (ordinal % P::group_size == 0 || cursor.done())
152 if (ranks.class_at(group) != population)
153 throw std::invalid_argument("Everett rank population disagrees with keys");
154 }
155 if (ordinal != virtual_size() || borrowed_count != borrowed().size())
156 throw std::invalid_argument("Everett merged stream count mismatch");
157 }
158 void scan_samples() const {
159 auto samples = borrowed().cursor();
160 if (!target_) {
161 if (!samples.done()) throw std::invalid_argument("Everett borrowed stream has no target");
162 return;
163 }
165 std::uint64_t ordinal = 0;
166 while (!target.done()) {
167 if (ordinal % P::group_size == 0) {
168 if (samples.done() || compare_bits<typename P::architecture>(samples.peek().key.prefix, target.key()) != 0)
169 throw std::invalid_argument("Everett borrowed key is not the exact target sample");
170 samples.advance();
171 }
172 target.advance();
173 ++ordinal;
174 }
175 if (!samples.done()) throw std::invalid_argument("Everett trailing borrowed target samples");
176 }
177 };
178
180
181 // Resolve the exact on-disk links using only fixed metadata, cache shared
182 // native mappings within this chain, and adopt its already-prepared head.
183 // This reads no FC payload or rank/EF words and never rebuilds an index.
184 template <class P> mapped_query_root<P> open_mapped_query(std::filesystem::path const & root,
185 blob_identity const & head) {
186 using native_pointer = std::shared_ptr<mapped_native<P> const>;
187 using index_pointer = std::shared_ptr<mapped_index<P> const>;
188 struct pending_pair { blob_identity identity; native_pointer native; index_pointer index; };
189 std::vector<pending_pair> pending;
190 std::unordered_set<std::string> seen;
191 std::unordered_map<std::string, native_pointer> natives;
192 std::optional<blob_identity> current = head;
193 while (current) {
194 if (!seen.insert(current->index.hex()).second) throw std::invalid_argument("cyclic Everett object identities");
195 auto index = std::make_shared<mapped_index<P> const>(
197 if (index->native_id() != current->native) throw std::invalid_argument("Everett chain native identity mismatch");
198 auto found = natives.find(current->native.hex());
199 if (found == natives.end()) {
200 auto native = std::make_shared<mapped_native<P> const>(
202 found = natives.emplace(current->native.hex(), std::move(native)).first;
203 }
204 pending.push_back({*current, found->second, index});
205 current = index->target_id();
206 }
207 typename mapped_blob<P>::pair_type pair;
208 for (auto i = pending.size(); i-- > 0;)
209 pair = mapped_blob<P>::bind(std::move(pending[i].identity), std::move(pending[i].native),
210 std::move(pending[i].index), std::move(pair));
211 return mapped_query_root<P>::adopt_prepared(std::move(pair));
212 }
213}
Definition active_engine.h:18
stream_role
Definition policy.h:25
mapped_query_root< P > open_mapped_query(std::filesystem::path const &root, blob_identity const &head)
Definition mapped_blob.h:184
std::filesystem::path object_path(object_id const &id, file_kind kind)
Definition object_path.h:52
Prepares immutable catalog chains and enumerates every matching native segment.
Encodes portable blob sections and retains mmap-backed profile directories.
Definition profile.h:166
bit_view view() const &
Definition profile.h:178
static bit_string copy(bit_view source)
Definition profile.h:181
Definition profile.h:56
Definition sections.h:34
object_id native
Definition sections.h:35
Definition mapped_blob.h:108
bool is_borrowed() const
Definition mapped_blob.h:113
merged_cursor(mapped_blob const &source)
Definition mapped_blob.h:111
bool done() const noexcept
Definition mapped_blob.h:112
profile_cursor< P, stream_role::borrowed > borrowed
Definition mapped_blob.h:110
void advance()
Definition mapped_blob.h:119
profile_cursor< P, stream_role::native > native
Definition mapped_blob.h:109
bit_view key() const
Definition mapped_blob.h:118
Definition mapped_blob.h:31
profile_blob_window project(std::uint64_t group) const
Definition mapped_blob.h:74
static pair_type bind(blob_identity identity, std::shared_ptr< native_type const > native, std::shared_ptr< index_type const > index, pair_type target={})
Definition mapped_blob.h:41
word_view cut_lcps() const &&=delete
mapped_blob(mapped_blob const &)=delete
rank_groups_view< P::group_size > interleave() const &&=delete
mapped_blob & operator=(mapped_blob const &)=delete
std::uint64_t group_count() const noexcept
Definition mapped_blob.h:72
profile_view< P, stream_role::native > native() const &&=delete
profile_blob_view< P > view() const &&=delete
pair_type target() const noexcept
Definition mapped_blob.h:60
std::shared_ptr< native_type const > native_
Definition mapped_blob.h:98
P policy_type
Definition mapped_blob.h:32
std::shared_ptr< index_type const > index_object() const noexcept
Definition mapped_blob.h:59
mapped_blob(blob_identity identity, std::shared_ptr< native_type const > native, std::shared_ptr< index_type const > index, pair_type target, profile_blob_view< P > view)
Definition mapped_blob.h:103
profile_blob_window_result< P > search_window(std::uint64_t group, profile_query_context< P > const &lower, profile_comparison_work *native_work=nullptr, profile_comparison_work *borrowed_work=nullptr) const
Definition mapped_blob.h:75
bool false_borrow(std::uint64_t ordinal) const
Definition mapped_blob.h:73
void scan_samples() const
Definition mapped_blob.h:158
pair_type target_
Definition mapped_blob.h:100
profile_view< P, stream_role::native > native() const &
Definition mapped_blob.h:61
blob_identity const & identity() const &&=delete
rank_groups_view< P::group_size > interleave() const &noexcept
Definition mapped_blob.h:67
std::shared_ptr< index_type const > index_
Definition mapped_blob.h:99
std::uint64_t virtual_size() const noexcept
Definition mapped_blob.h:71
void scan() const
Definition mapped_blob.h:84
blob_identity identity_
Definition mapped_blob.h:97
mapped_blob(mapped_blob &&)=delete
mapped_blob & operator=(mapped_blob &&)=delete
profile_view< P, stream_role::borrowed > borrowed() const &&=delete
profile_blob_view< P > view_
Definition mapped_blob.h:101
profile_blob_view< P > view() const &
Definition mapped_blob.h:65
void scan_pair() const
Definition mapped_blob.h:122
blob_identity const & identity() const &noexcept
Definition mapped_blob.h:56
word_view cut_lcps() const &noexcept
Definition mapped_blob.h:69
std::shared_ptr< native_type const > native_object() const noexcept
Definition mapped_blob.h:58
std::shared_ptr< mapped_blob const > pair_type
Definition mapped_blob.h:33
Definition sections.h:486
static mapped_index open(file< P > source)
Definition sections.h:488
Definition sections.h:442
static mapped_profile open(file< P > source)
Definition sections.h:444
Definition profile_blob.h:73
Definition profile_blob.h:61
Definition profile_blob.h:37
Definition profile.h:452
Definition profile.h:1066
bool done() const noexcept
Definition profile.h:1091
profile_item< P > peek() const &
Definition profile.h:1093
void advance()
Definition profile.h:1103
Definition profile.h:328
Definition profile.h:695
Definition query.h:51
static query_root adopt_prepared(pair_type source)
Definition query.h:60
Definition rank_groups.h:127
Definition word_view.h:31