PineForge v1.9.0
Deterministic PineScript v6 backtest runtime — C ABI reference
Loading...
Searching...
No Matches
run_quota.hpp
Go to the documentation of this file.
1#pragma once
2
4
5#include <array>
6#include <cstddef>
7#include <cstdint>
8#include <memory>
9
10namespace pineforge::detail {
11
12inline constexpr std::uint64_t kRunQuotaMax = (std::uint64_t{1} << 53) - 1;
13inline constexpr std::size_t kRunQuotaWireSize = 256;
14inline constexpr std::uint16_t kRunQuotaVersion = 1;
15inline constexpr std::uint16_t kRunQuotaReply = 0x8000;
16
17inline constexpr char kRunQuotaModeEnv[] = "PF_RUN_QUOTA_MODE";
18inline constexpr char kRunQuotaNativeFdEnv[] = "PF_RUN_QUOTA_NATIVE_FD";
19inline constexpr char kRunQuotaPythonFdEnv[] = "PF_RUN_QUOTA_PYTHON_FD";
20inline constexpr char kRunQuotaEnforcement[] = "cooperative";
21inline constexpr char kRunQuotaManagedLine[] = "quota=managed enforcement=cooperative";
22inline constexpr char kRunQuotaUnmanagedLine[] = "quota=unmanaged";
23
24enum class QuotaMode { unmanaged, managed };
25// Captured once at the first mode/attachment call, before any strategy code.
26// The host must call during trusted startup. Any marker component means
27// managed; invalid/partial markers refuse on attach.
28// No request, strategy setting or later environment edit changes this mode.
29QuotaMode mode() noexcept;
30// No newline, allocation or output. The wrapper owns stderr/receipt emission.
31const char* quota_line() noexcept;
32// Test support only: the last predicate plus its environment/capture snapshot.
33// No output; never part of typed failure args, receipts, wire or product text.
34// The returned pointer lasts until the next call on this thread.
35const char* last_admission_diagnostic() noexcept;
36
37enum class QuotaOpcode : std::uint16_t {
39};
47enum class QuotaRole : std::uint64_t { host = 1, compiler, worker, finalizer, converter, reaper };
49// Configuration replies use the resource slot for a QuotaSetting.
65
66// Encoding is explicitly little endian; this type is never sent as a struct.
67// decode accepts requests and replies, validates framing and the three zero
68// slots, and leaves opcode-specific field validation to the endpoint.
70 std::uint16_t opcode = static_cast<std::uint16_t>(QuotaOpcode::hello);
71 std::uint64_t sequence = 0;
72 std::array<std::uint64_t, 30> slots{};
73
74 std::uint64_t& operator[](QuotaSlot slot) noexcept {
75 return slots[static_cast<std::size_t>(slot)];
76 }
77 std::uint64_t operator[](QuotaSlot slot) const noexcept {
78 return slots[static_cast<std::size_t>(slot)];
79 }
80};
81using QuotaWire = std::array<unsigned char, kRunQuotaWireSize>;
83QuotaMessage decode_quota_message(const unsigned char*, std::size_t);
84
86 std::uint64_t scratch_bytes = 0;
87 std::uint64_t scratch_files = 0;
88 std::uint64_t output_bytes = 0;
89 std::uint64_t descriptors = 0;
90};
92 // Opaque identities are full u64s, never JSON numbers. generation belongs
93 // to the object, not its fd number. A new backing must use a new identity.
94 std::uint64_t id = 0;
95 std::uint64_t generation = 0;
96 std::uint64_t device = 0;
97 std::uint64_t inode = 0;
98};
103struct RunQuotaEndpoint;
104
105// A ticket keeps its endpoint alive through moves, old readers and later
106// attempts. Destruction deliberately leaves unreported growth charged:
107// destruction cannot prove that a failed syscall realized zero bytes.
109public:
110 QuotaTicket() = default;
111 QuotaTicket(const QuotaTicket&) = delete;
113 QuotaTicket(QuotaTicket&&) noexcept = default;
114 QuotaTicket& operator=(QuotaTicket&&) noexcept = default;
115
116 std::uint64_t id() const noexcept { return ticket_; }
117 // Cumulative realization of this reservation, not another delta. Report
118 // the host-policy-rounded real storage extent after partial write/error.
119 // The host must confirm a new inode before accepting its file COMMIT.
120 // Call cancel afterwards to retire even a fully realized ticket.
121 void commit(QuotaAmounts realized, std::uint64_t actual_extent,
122 std::uint64_t device = 0, std::uint64_t inode = 0);
123 void cancel(); // Retires the ticket; returns only its unrealized portion.
124
125private:
126 friend class RunQuota;
127 std::shared_ptr<RunQuotaEndpoint> endpoint_;
128 QuotaMessage reservation_;
129 std::uint64_t ticket_ = 0;
130};
131
132class RunQuota {
133public:
134 // Duplicates a pre-opened, connected AF_UNIX SOCK_SEQPACKET endpoint.
135 // Repeated attachment to the same socket shares its mutex and sequence.
136 static RunQuota from_fd(int fd, QuotaRole role = QuotaRole::worker);
137 // With no host marker, returns a no-op client (including absurd sizes).
138 // Partial/invalid markers refuse. The host alone parses limits; HELLO
139 // authenticates the attempt. Call before loading any strategy code.
140 static RunQuota from_environment();
141
143 std::uint64_t new_extent, QuotaStage, QuotaArtifact);
144 // Call only AFTER successful shrink/last-close. Output is never refunded.
146 std::uint64_t new_extent, QuotaStage, QuotaArtifact);
149 std::shared_ptr<const QuotaSnapshot> refusal() const;
150 void check() const;
151
152private:
153 explicit RunQuota(std::shared_ptr<RunQuotaEndpoint> endpoint)
154 : endpoint_(std::move(endpoint)) {}
155 std::shared_ptr<RunQuotaEndpoint> endpoint_;
156};
157
158// The most recently attached environment endpoint is the active attempt for
159// failure rendering. Explicit from_fd clients do not change that binding.
160// The latch survives clear_run_failure and status-only exception translation.
162
163// Managed callers only: checked before rounding or constructing a request.
164// Unmanaged callers retain their existing sizing path.
165std::uint64_t quota_rounded_extent(std::uint64_t extent, std::uint64_t block_size);
166
167} // namespace pineforge::detail
QuotaTicket(QuotaTicket &&) noexcept=default
QuotaTicket & operator=(const QuotaTicket &)=delete
void commit(QuotaAmounts realized, std::uint64_t actual_extent, std::uint64_t device=0, std::uint64_t inode=0)
QuotaTicket(const QuotaTicket &)=delete
static RunQuota from_fd(int fd, QuotaRole role=QuotaRole::worker)
void release(QuotaObject, QuotaAmounts, std::uint64_t old_extent, std::uint64_t new_extent, QuotaStage, QuotaArtifact)
QuotaTicket reserve(QuotaObject, QuotaAmounts, std::uint64_t old_extent, std::uint64_t new_extent, QuotaStage, QuotaArtifact)
QuotaSnapshot snapshot(QuotaResource=QuotaResource::scratch_bytes)
QuotaSnapshot finish(QuotaResource=QuotaResource::scratch_bytes)
static RunQuota from_environment()
std::shared_ptr< const QuotaSnapshot > refusal() const
RunFailureValue run_quota_failure() noexcept
constexpr char kRunQuotaModeEnv[]
Definition run_quota.hpp:17
constexpr char kRunQuotaPythonFdEnv[]
Definition run_quota.hpp:19
std::uint64_t quota_rounded_extent(std::uint64_t extent, std::uint64_t block_size)
constexpr std::uint16_t kRunQuotaVersion
Definition run_quota.hpp:14
constexpr char kRunQuotaUnmanagedLine[]
Definition run_quota.hpp:22
constexpr char kRunQuotaNativeFdEnv[]
Definition run_quota.hpp:18
const char * last_admission_diagnostic() noexcept
constexpr std::uint64_t kRunQuotaMax
Definition run_quota.hpp:12
constexpr std::size_t kRunQuotaWireSize
Definition run_quota.hpp:13
const char * quota_line() noexcept
constexpr char kRunQuotaManagedLine[]
Definition run_quota.hpp:21
constexpr std::uint16_t kRunQuotaReply
Definition run_quota.hpp:15
QuotaMessage decode_quota_message(const unsigned char *, std::size_t)
constexpr char kRunQuotaEnforcement[]
Definition run_quota.hpp:20
QuotaWire encode_quota_message(const QuotaMessage &)
QuotaMode mode() noexcept
std::array< unsigned char, kRunQuotaWireSize > QuotaWire
Definition run_quota.hpp:81
A validated code and its canonical arguments: the JSON object with its keys sorted and no whitespace,...
std::uint64_t operator[](QuotaSlot slot) const noexcept
Definition run_quota.hpp:77
std::array< std::uint64_t, 30 > slots
Definition run_quota.hpp:72
std::uint64_t & operator[](QuotaSlot slot) noexcept
Definition run_quota.hpp:74