16#include <unordered_map>
17#include <unordered_set>
34template<
class Diagnostics = PositionTailNoDiagnostics>
39 if constexpr (Diagnostics::enabled)
56 static constexpr std::uint64_t
maximum = (UINT64_C(1) << 53) - 1;
62 template<
class Diagnostics = PositionTailNoDiagnostics>
65 if (!std::isfinite(value) || std::signbit(value)) {
66 rejection.reject(PositionTailGuard::InvalidQuantity);
70 if (value == 0.0)
return;
72 const double fraction = std::frexp(value, &exponent);
73 auto integer =
static_cast<std::uint64_t
>(std::ldexp(fraction, 53));
81 term.
quantum =
static_cast<std::int16_t
>(exponent);
82 merge(term, rejection);
85 void add(
double value)
noexcept {
87 add(value, rejection);
90 template<
class Diagnostics>
93 if (!
valid || !other.valid) {
94 rejection.reject(PositionTailGuard::InvalidCertificate);
98 if (other.magnitude == 0)
return;
103 const int common = std::min(
quantum, other.quantum);
104 std::uint64_t left =
magnitude, right = other.magnitude;
105 const auto shift = [&](std::uint64_t& value,
int bits) {
106 if (bits >= 53 || value > (
maximum >> bits)) {
107 if constexpr (Diagnostics::enabled)
108 rejection.reject(bits >= 53 ? PositionTailGuard::QuantumShift
109 : PositionTailGuard::MagnitudeShift);
115 if (!shift(left,
quantum - common) || !shift(right, other.quantum - common)
117 rejection.reject(PositionTailGuard::MagnitudeOverflow);
122 quantum =
static_cast<std::int16_t
>(common);
125 template<
class Diagnostics>
128 rejection.reject(PositionTailGuard::InvalidCertificate);
132 if (!std::isfinite(value)) {
133 rejection.reject(PositionTailGuard::NonfiniteResult);
140 bool read(
double& result)
const noexcept {
142 return read(result, rejection);
145static_assert(
sizeof(PositionTailExact) == 16,
"compact dyadic certificate");
146static_assert(std::numeric_limits<double>::is_iec559
147 && std::numeric_limits<double>::digits == 53,
"binary64 proof");
152 std::uint32_t visited = 0;
153 bool is_long =
false;
155 using Origins = std::unordered_map<std::uint64_t, Origin>;
156 static_assert(
sizeof(Origins::value_type) == 32,
"32 bytes per origin, excluding map overhead");
160 static_assert(
sizeof(Margins) == 32,
"unchanged disk summary width");
165 void set_directory(
const std::string& directory) { margins_.set_directory(directory); }
171 template<
class Read,
class Diagnostics = PositionTailNoDiagnostics>
172 void begin_position(std::int64_t barrier, std::size_t base, std::size_t end, Read&& read,
173 Diagnostics diagnostics = {}) {
174 if constexpr (Diagnostics::enabled) {
176 unsafe_reason_ = PositionTailGuard::None;
181 high_closed_origin_ = 0;
187 std::int64_t newer_time = 0;
188 for (std::size_t index = end; index > base;) {
189 const Trade& row = read(--index);
191 if constexpr (Diagnostics::enabled) {
196 if (have_time_ && row.
exit_time > newer_time) {
197 invalidate(PositionTailGuard::NonmonotoneTime, diagnostics);
200 if (!have_time_) last_time_ = row.
exit_time;
203 accumulate(row, diagnostics);
207 template<
class Read,
class Diagnostics = PositionTailNoDiagnostics>
208 void observe(std::size_t base, std::size_t end, Read&& read, Diagnostics diagnostics = {}) {
210 if (!active_ || !safe_)
return;
211 if (end < observed_end_ || observed_end_ < base) {
212 if constexpr (Diagnostics::enabled)
213 unsafe_reason_ = end < observed_end_ ? PositionTailGuard::PublicationRewind
215 invalidate(PositionTailGuard::Invalidated, diagnostics);
218 while (observed_end_ < end) {
219 const Trade& row = read(observed_end_++);
221 if constexpr (Diagnostics::enabled) {
226 if constexpr (Diagnostics::enabled)
227 unsafe_reason_ = row.
exit_time < barrier_ ? PositionTailGuard::BeforeBarrier
229 invalidate(PositionTailGuard::Invalidated, diagnostics);
234 accumulate(row, diagnostics);
238 template<
class Diagnostics = PositionTailNoDiagnostics>
239 void open_origin(std::uint64_t incarnation,
bool is_long, Diagnostics = {}) {
241 if (!safe_ || !active_)
return;
242 auto found = origins_.find(incarnation);
243 if (found == origins_.end()) {
249 row.completed.valid = incarnation > high_closed_origin_;
250 if constexpr (Diagnostics::enabled)
251 if (!row.completed.valid)
252 row.completed.reason = PositionTailGuard::ReactivatedOrigin;
253 origins_.emplace(incarnation, row);
254 }
else if (found->second.is_long != is_long) {
255 if constexpr (Diagnostics::enabled)
256 if (found->second.completed.reason == PositionTailGuard::None)
257 found->second.completed.reason = PositionTailGuard::SideMismatch;
258 found->second.completed.valid =
false;
263 origins_.erase(incarnation);
264 if (origins_.empty()) {
266 }
else if (origins_.bucket_count() / 4 > origins_.size()) {
267 origins_.rehash(origins_.size());
283 if (active_ && safe_) live_cohorts_.insert(row);
285 live_cohorts_.erase(row);
286 if (live_cohorts_.empty())
288 else if (live_cohorts_.bucket_count() / 4 > live_cohorts_.size())
289 live_cohorts_.rehash(live_cohorts_.size());
292 template<
class Visit>
294 for (
const auto* row : live_cohorts_) visit(row);
297 template<
class Diagnostics = PositionTailNoDiagnostics>
299 if constexpr (Diagnostics::enabled) {
301 if (unsafe_reason_ == PositionTailGuard::None
302 || unsafe_reason_ == PositionTailGuard::Inactive)
303 unsafe_reason_ = reason;
311 template<
class Select,
class Diagnostics = PositionTailNoDiagnostics>
312 bool ancestry(
bool is_long, Select&& select,
double& result, Diagnostics diagnostics = {}) {
314 if (!safe_ || !active_)
return finish(
false, unsafe_reason_, diagnostics);
315 if (++query_generation_ == 0) {
316 for (
auto& row : origins_) row.second.visited = 0;
319 PositionTailExact total;
320 PositionTailRejection<Diagnostics> rejection;
321 select([&](std::uint64_t incarnation) {
323 const auto found = origins_.find(incarnation);
324 if (found == origins_.end()) {
327 if (incarnation <= high_closed_origin_) {
328 rejection.reject(PositionTailGuard::MissingOrigin);
333 auto& row = found->second;
334 if (row.visited == query_generation_)
return;
335 row.visited = query_generation_;
336 if (!row.completed.valid) {
337 if constexpr (Diagnostics::enabled)
338 rejection.reject(row.completed.reason == PositionTailGuard::None
339 ? PositionTailGuard::InvalidCertificate : row.completed.reason);
341 }
else if (row.is_long == is_long) total.merge(row.completed, rejection);
343 const bool certified = total.read(result, rejection);
344 return finish(certified, rejection.value(), diagnostics);
347 template<
class Diagnostics = PositionTailNoDiagnostics>
348 bool margin(
bool is_long,
const std::string* named_entry,
double& result,
349 Diagnostics diagnostics = {}) {
351 if (!safe_ || !active_)
return finish(
false, unsafe_reason_, diagnostics);
352 const auto side = is_long ? 1 : 0;
355 if constexpr (Diagnostics::enabled)
357 const bool certified = all_margins_.side[side].
read(result, rejection);
358 return finish(certified, rejection.
value(), diagnostics);
360 const auto offset = margins_.
find(*named_entry);
363 return finish(
true, PositionTailGuard::None, diagnostics);
365 const auto value = margins_.
get(*offset);
366 if constexpr (Diagnostics::enabled) rejection.
reject(value.side[side].reason);
367 const bool certified = value.side[side].read(result, rejection);
368 return finish(certified, rejection.
value(), diagnostics);
372 template<
class Diagnostics>
376 if constexpr (Diagnostics::enabled) {
383 template<
class Diagnostics>
384 void accumulate(
const Trade& trade, Diagnostics) {
385 high_closed_origin_ = std::max(high_closed_origin_, trade.entry_incarnation);
386 const auto origin = origins_.find(trade.entry_incarnation);
387 if (origin != origins_.end()) {
388 PositionTailRejection<Diagnostics> rejection;
389 if constexpr (Diagnostics::enabled) rejection.
reason = origin->second.completed.reason;
390 if (origin->second.is_long != trade.is_long) {
391 rejection.
reject(PositionTailGuard::SideMismatch);
392 origin->second.completed.valid =
false;
394 origin->second.completed.add(trade.qty, rejection);
395 if constexpr (Diagnostics::enabled)
396 origin->second.completed.reason = rejection.
reason;
399 const auto side = trade.is_long ? 1 : 0;
400 PositionTailRejection<Diagnostics> all_rejection, named_rejection;
401 if constexpr (Diagnostics::enabled)
402 all_rejection.reason = all_margins_.side[side].reason;
403 all_margins_.side[side].add(trade.qty, all_rejection);
404 if constexpr (Diagnostics::enabled)
405 all_margins_.side[side].reason = all_rejection.reason;
406 const auto inserted = margins_.insert(trade.entry_id, Margins{});
407 auto value = margins_.get(inserted.first);
408 if constexpr (Diagnostics::enabled) named_rejection.reason =
value.side[side].reason;
409 value.side[side].add(trade.qty, named_rejection);
410 if constexpr (Diagnostics::enabled)
value.side[side].reason = named_rejection.reason;
411 margins_.set(inserted.first, value);
415 std::unordered_set<const void*> live_cohorts_;
419 ::pineforge::detail::DiskIdTable<Margins> margins_;
420 Margins all_margins_{};
421 std::uint64_t high_closed_origin_ = 0;
422 std::size_t observed_end_ = 0;
423 std::int64_t barrier_ = 0, last_time_ = 0;
424 std::uint32_t query_generation_ = 0;
425 bool active_ =
false, safe_ =
false, have_time_ =
false;
433template<
class Read,
class Include,
class Diagnostics = PositionTailNoDiagnostics>
436 Include&& include,
const std::string& from_entry,
439 for (std::size_t index = end; index > base;) {
440 const Trade& trade = read(--index);
442 if constexpr (Diagnostics::enabled) {
446 if (trade.
exit_time < barrier)
return result;
448 [&] { return trade.entry_id == from_entry; })) result += trade.
qty;
452 PositionTailSpill::Row trade;
453 while (spill->
previous(cursor, trade)) {
455 if constexpr (Diagnostics::enabled) ++work.
spill_rows;
456 if (trade.exit_time < barrier)
break;
457 if (include(trade.is_long, trade.entry_incarnation, trade.margin_call,
458 [&] { return spill->entry_id_equals(trade, from_entry); })) result += trade.qty;
Value get(Offset at) const
std::optional< Offset > find(const std::string &key) const
bool previous(std::uint64_t &cursor, Row &row) const
std::uint64_t size_bytes() const noexcept
bool ancestry(bool is_long, Select &&select, double &result, Diagnostics diagnostics={})
std::size_t resident_origins() const noexcept
PineExecutionAdapter::PositionTailWork work
void begin_position(std::int64_t barrier, std::size_t base, std::size_t end, Read &&read, Diagnostics diagnostics={})
void invalidate(PositionTailGuard reason=PositionTailGuard::Invalidated, Diagnostics={})
void for_each_live_cohort(Visit &&visit) const
void observe(std::size_t base, std::size_t end, Read &&read, Diagnostics diagnostics={})
void open_origin(std::uint64_t incarnation, bool is_long, Diagnostics={})
void retire_origin(std::uint64_t incarnation)
void live_cohort(const void *row, bool nonempty)
void set_directory(const std::string &directory)
bool margin(bool is_long, const std::string *named_entry, double &result, Diagnostics diagnostics={})
void clear_exposure_storage(Container &container)
double replay_position_tail(std::size_t end, std::size_t base, Read &&read, const PositionTailSpill *spill, std::int64_t barrier, Include &&include, const std::string &from_entry, PineExecutionAdapter::PositionTailWork &work, Diagnostics={})
PineExecutionAdapter::PositionTailGuard PositionTailGuard
constexpr char kMarginCallLabel[]
uint64_t entry_incarnation
std::uint64_t begin_updates
std::uint64_t sync_updates
std::uint64_t origin_visits
std::uint64_t update_rows
std::uint64_t open_updates
std::uint64_t invalidations
std::uint64_t fallback_queries
std::uint64_t closed_updates
std::uint64_t replay_host_rows
PositionTailGuard guard_reason
std::uint64_t guard_reasons[static_cast< std::size_t >(PositionTailGuard::Count)]
std::uint64_t replay_rows
std::uint64_t certified_queries
std::vector< std::uint64_t > roster_roots
static constexpr bool enabled
bool read(double &result) const noexcept
void merge(const PositionTailExact &other, PositionTailRejection< Diagnostics > &rejection) noexcept
void add(double value) noexcept
void add(double value, PositionTailRejection< Diagnostics > &rejection) noexcept
bool read(double &result, PositionTailRejection< Diagnostics > &rejection) const noexcept
static constexpr std::uint64_t maximum
static constexpr bool enabled
void reject(PositionTailGuard) const noexcept
constexpr PositionTailGuard value() const noexcept
PositionTailGuard value() const noexcept
void reject(PositionTailGuard value) noexcept