16#include <unordered_map>
17#include <unordered_set>
33template<
class Diagnostics = PositionTailNoDiagnostics>
38 if constexpr (Diagnostics::enabled)
55 static constexpr std::uint64_t
maximum = (UINT64_C(1) << 53) - 1;
61 template<
class Diagnostics = PositionTailNoDiagnostics>
64 if (!std::isfinite(value) || std::signbit(value)) {
65 rejection.reject(PositionTailGuard::InvalidQuantity);
69 if (value == 0.0)
return;
71 const double fraction = std::frexp(value, &exponent);
72 auto integer =
static_cast<std::uint64_t
>(std::ldexp(fraction, 53));
80 term.
quantum =
static_cast<std::int16_t
>(exponent);
81 merge(term, rejection);
84 void add(
double value)
noexcept {
86 add(value, rejection);
89 template<
class Diagnostics>
92 if (!
valid || !other.valid) {
93 rejection.reject(PositionTailGuard::InvalidCertificate);
97 if (other.magnitude == 0)
return;
102 const int common = std::min(
quantum, other.quantum);
103 std::uint64_t left =
magnitude, right = other.magnitude;
104 const auto shift = [&](std::uint64_t& value,
int bits) {
105 if (bits >= 53 || value > (
maximum >> bits)) {
106 if constexpr (Diagnostics::enabled)
107 rejection.reject(bits >= 53 ? PositionTailGuard::QuantumShift
108 : PositionTailGuard::MagnitudeShift);
114 if (!shift(left,
quantum - common) || !shift(right, other.quantum - common)
116 rejection.reject(PositionTailGuard::MagnitudeOverflow);
121 quantum =
static_cast<std::int16_t
>(common);
124 template<
class Diagnostics>
127 rejection.reject(PositionTailGuard::InvalidCertificate);
131 if (!std::isfinite(value)) {
132 rejection.reject(PositionTailGuard::NonfiniteResult);
139 bool read(
double& result)
const noexcept {
141 return read(result, rejection);
144static_assert(
sizeof(PositionTailExact) == 16,
"compact dyadic certificate");
145static_assert(std::numeric_limits<double>::is_iec559
146 && std::numeric_limits<double>::digits == 53,
"binary64 proof");
151 std::uint32_t visited = 0;
152 bool is_long =
false;
154 using Origins = std::unordered_map<std::uint64_t, Origin>;
155 static_assert(
sizeof(Origins::value_type) == 32,
"32 bytes per origin, excluding map overhead");
159 static_assert(
sizeof(Margins) == 32,
"unchanged disk summary width");
164 void set_directory(
const std::string& directory) { margins_.set_directory(directory); }
170 template<
class Read,
class Diagnostics = PositionTailNoDiagnostics>
171 void begin_position(std::int64_t barrier, std::size_t base, std::size_t end, Read&& read,
172 Diagnostics diagnostics = {}) {
173 if constexpr (Diagnostics::enabled) {
175 unsafe_reason_ = PositionTailGuard::None;
180 high_closed_origin_ = 0;
186 std::int64_t newer_time = 0;
187 for (std::size_t index = end; index > base;) {
188 const Trade& row = read(--index);
190 if constexpr (Diagnostics::enabled) {
195 if (have_time_ && row.
exit_time > newer_time) {
196 invalidate(PositionTailGuard::NonmonotoneTime, diagnostics);
199 if (!have_time_) last_time_ = row.
exit_time;
202 accumulate(row, diagnostics);
206 template<
class Read,
class Diagnostics = PositionTailNoDiagnostics>
207 void observe(std::size_t base, std::size_t end, Read&& read, Diagnostics diagnostics = {}) {
209 if (!active_ || !safe_)
return;
210 if (end < observed_end_ || observed_end_ < base) {
211 if constexpr (Diagnostics::enabled)
212 unsafe_reason_ = end < observed_end_ ? PositionTailGuard::PublicationRewind
214 invalidate(PositionTailGuard::Invalidated, diagnostics);
217 while (observed_end_ < end) {
218 const Trade& row = read(observed_end_++);
220 if constexpr (Diagnostics::enabled) {
225 if constexpr (Diagnostics::enabled)
226 unsafe_reason_ = row.
exit_time < barrier_ ? PositionTailGuard::BeforeBarrier
228 invalidate(PositionTailGuard::Invalidated, diagnostics);
233 accumulate(row, diagnostics);
237 template<
class Diagnostics = PositionTailNoDiagnostics>
238 void open_origin(std::uint64_t incarnation,
bool is_long, Diagnostics = {}) {
240 if (!safe_ || !active_)
return;
241 auto found = origins_.find(incarnation);
242 if (found == origins_.end()) {
248 row.completed.valid = incarnation > high_closed_origin_;
249 if constexpr (Diagnostics::enabled)
250 if (!row.completed.valid)
251 row.completed.reason = PositionTailGuard::ReactivatedOrigin;
252 origins_.emplace(incarnation, row);
253 }
else if (found->second.is_long != is_long) {
254 if constexpr (Diagnostics::enabled)
255 if (found->second.completed.reason == PositionTailGuard::None)
256 found->second.completed.reason = PositionTailGuard::SideMismatch;
257 found->second.completed.valid =
false;
262 origins_.erase(incarnation);
263 if (origins_.empty()) {
265 }
else if (origins_.bucket_count() / 4 > origins_.size()) {
266 origins_.rehash(origins_.size());
282 if (active_ && safe_) live_cohorts_.insert(row);
284 live_cohorts_.erase(row);
285 if (live_cohorts_.empty())
287 else if (live_cohorts_.bucket_count() / 4 > live_cohorts_.size())
288 live_cohorts_.rehash(live_cohorts_.size());
291 template<
class Visit>
293 for (
const auto* row : live_cohorts_) visit(row);
296 template<
class Diagnostics = PositionTailNoDiagnostics>
298 if constexpr (Diagnostics::enabled) {
300 if (unsafe_reason_ == PositionTailGuard::None
301 || unsafe_reason_ == PositionTailGuard::Inactive)
302 unsafe_reason_ = reason;
310 template<
class Select,
class Diagnostics = PositionTailNoDiagnostics>
311 bool ancestry(
bool is_long, Select&& select,
double& result, Diagnostics diagnostics = {}) {
313 if (!safe_ || !active_)
return finish(
false, unsafe_reason_, diagnostics);
314 if (++query_generation_ == 0) {
315 for (
auto& row : origins_) row.second.visited = 0;
318 PositionTailExact total;
319 PositionTailRejection<Diagnostics> rejection;
320 select([&](std::uint64_t incarnation) {
322 const auto found = origins_.find(incarnation);
323 if (found == origins_.end()) {
326 if (incarnation <= high_closed_origin_) {
327 rejection.reject(PositionTailGuard::MissingOrigin);
332 auto& row = found->second;
333 if (row.visited == query_generation_)
return;
334 row.visited = query_generation_;
335 if (!row.completed.valid) {
336 if constexpr (Diagnostics::enabled)
337 rejection.reject(row.completed.reason == PositionTailGuard::None
338 ? PositionTailGuard::InvalidCertificate : row.completed.reason);
340 }
else if (row.is_long == is_long) total.merge(row.completed, rejection);
342 const bool certified = total.read(result, rejection);
343 return finish(certified, rejection.value(), diagnostics);
346 template<
class Diagnostics = PositionTailNoDiagnostics>
347 bool margin(
bool is_long,
const std::string* named_entry,
double& result,
348 Diagnostics diagnostics = {}) {
350 if (!safe_ || !active_)
return finish(
false, unsafe_reason_, diagnostics);
351 const auto side = is_long ? 1 : 0;
354 if constexpr (Diagnostics::enabled)
356 const bool certified = all_margins_.side[side].
read(result, rejection);
357 return finish(certified, rejection.
value(), diagnostics);
359 const auto offset = margins_.
find(*named_entry);
362 return finish(
true, PositionTailGuard::None, diagnostics);
364 const auto value = margins_.
get(*offset);
365 if constexpr (Diagnostics::enabled) rejection.
reject(value.side[side].reason);
366 const bool certified = value.side[side].read(result, rejection);
367 return finish(certified, rejection.
value(), diagnostics);
371 template<
class Diagnostics>
375 if constexpr (Diagnostics::enabled) {
382 template<
class Diagnostics>
383 void accumulate(
const Trade& trade, Diagnostics) {
384 high_closed_origin_ = std::max(high_closed_origin_, trade.entry_incarnation);
385 const auto origin = origins_.find(trade.entry_incarnation);
386 if (origin != origins_.end()) {
387 PositionTailRejection<Diagnostics> rejection;
388 if constexpr (Diagnostics::enabled) rejection.
reason = origin->second.completed.reason;
389 if (origin->second.is_long != trade.is_long) {
390 rejection.
reject(PositionTailGuard::SideMismatch);
391 origin->second.completed.valid =
false;
393 origin->second.completed.add(trade.qty, rejection);
394 if constexpr (Diagnostics::enabled)
395 origin->second.completed.reason = rejection.
reason;
398 const auto side = trade.is_long ? 1 : 0;
399 PositionTailRejection<Diagnostics> all_rejection, named_rejection;
400 if constexpr (Diagnostics::enabled)
401 all_rejection.reason = all_margins_.side[side].reason;
402 all_margins_.side[side].add(trade.qty, all_rejection);
403 if constexpr (Diagnostics::enabled)
404 all_margins_.side[side].reason = all_rejection.reason;
405 const auto inserted = margins_.insert(trade.entry_id, Margins{});
406 auto value = margins_.get(inserted.first);
407 if constexpr (Diagnostics::enabled) named_rejection.reason =
value.side[side].reason;
408 value.side[side].add(trade.qty, named_rejection);
409 if constexpr (Diagnostics::enabled)
value.side[side].reason = named_rejection.reason;
410 margins_.set(inserted.first, value);
414 std::unordered_set<const void*> live_cohorts_;
418 ::pineforge::detail::DiskIdTable<Margins> margins_;
419 Margins all_margins_{};
420 std::uint64_t high_closed_origin_ = 0;
421 std::size_t observed_end_ = 0;
422 std::int64_t barrier_ = 0, last_time_ = 0;
423 std::uint32_t query_generation_ = 0;
424 bool active_ =
false, safe_ =
false, have_time_ =
false;
432template<
class Read,
class Include,
class Diagnostics = PositionTailNoDiagnostics>
435 Include&& include,
const std::string& from_entry,
438 for (std::size_t index = end; index > base;) {
439 const Trade& trade = read(--index);
441 if constexpr (Diagnostics::enabled) {
445 if (trade.
exit_time < barrier)
return result;
447 [&] { return trade.entry_id == from_entry; })) result += trade.
qty;
451 PositionTailSpill::Row trade;
452 while (spill->
previous(cursor, trade)) {
454 if constexpr (Diagnostics::enabled) ++work.
spill_rows;
455 if (trade.exit_time < barrier)
break;
456 if (include(trade.is_long, trade.entry_incarnation, trade.margin_call,
457 [&] { 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
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