1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
//! Shared accounting adapter, not a store/view admission or allocator owner.
use crate::lifecycle::stats::{AccountedCounter, Accounting, AllocationComponent};
use crate::lifecycle::{Store, StoreError};
use std::sync::Arc;
pub use crate::lifecycle::stats::{
AllocationInterval, AllocationIntervalError, AllocationIntervalSnapshot,
};
/// Hard aggregate graph ceiling; all participants share the store's allowance.
pub const MAX_GRAPH_RESIDENT_BYTES: u64 = 256 * 1024 * 1024;
/// A non-allocating clone of the existing store's shared accounting authority.
/// Construction does not admit a view or permit work after store close.
#[derive(Clone)]
pub struct GraphResources {
accounting: Arc<Accounting>,
}
impl GraphResources {
/// Reuses a store configured with an aggregate limit at most 256 MiB.
/// No second budget or independent accounting instance is created. The
/// retained-view owner separately enforces admission and close cancellation.
pub fn from_store(store: &Store) -> Result<Self, StoreError> {
Self::from_accounting(&store.accounting)
}
pub(crate) fn from_accounting(accounting: &Arc<Accounting>) -> Result<Self, StoreError> {
let limit = accounting.resident_limit();
if limit > MAX_GRAPH_RESIDENT_BYTES {
return Err(StoreError::BudgetExceeded {
needed: limit,
budget: MAX_GRAPH_RESIDENT_BYTES,
component: "graph aggregate configuration",
});
}
Ok(Self {
accounting: Arc::clone(accounting),
})
}
/// Current engine capacities; application-retention reporting is reserved for ZE-310.
pub fn snapshot(&self) -> Result<GraphResourceSnapshot, StoreError> {
let (engine_bytes, engine_peak_bytes) = self.accounting.graph_resource_bytes()?;
Ok(GraphResourceSnapshot {
engine_bytes,
engine_peak_bytes,
application_bytes: 0,
application_peak_bytes: 0,
})
}
/// Nonshipping snapshot of internal store-cumulative work for exact tests.
#[cfg(any(test, feature = "test-seams"))]
pub fn work_ledger(&self) -> Result<crate::lifecycle::stats::GraphWorkLedger, StoreError> {
Ok(self.accounting.graph_work())
}
pub(crate) fn record_work(&self, kind: crate::lifecycle::stats::GraphWorkKind, units: u64) {
work_batch::record(&self.accounting, kind, units);
}
pub(crate) fn record_work_delta(&self, delta: crate::lifecycle::stats::GraphWorkLedger) {
work_batch::record_delta(&self.accounting, delta);
}
pub(crate) fn begin_work(&self) -> work_batch::WorkBatch {
work_batch::WorkBatch::new(&self.accounting)
}
/// Current exact shared reservations, including all other store participants.
pub fn reserved_bytes(&self) -> Result<u64, StoreError> {
Ok(self.accounting.audit()?.resident_owned_bytes)
}
/// Monotone resident reservation peak since this store Accounting was created.
/// This includes short-lived overlap and is not periodic process-RSS sampling.
pub fn peak_reserved_bytes(&self) -> Result<u64, StoreError> {
self.accounting.resident_peak_bytes()
}
/// Begins one exact shared-reservation observation on this store owner.
/// Existing live reservations are included. The guard owns no Store or
/// graph admission and a second observation returns a typed busy error.
pub fn begin_allocation_interval(&self) -> Result<AllocationInterval, AllocationIntervalError> {
self.accounting.begin_allocation_interval()
}
/// Reserves anonymous participant capacity before allocating or adopting it.
/// The participant owns the backing and must reconcile actual capacity;
/// reservation success alone proves no allocation or view ownership.
pub fn reserve(&self, bytes: usize) -> Result<GraphReservation, StoreError> {
let mut charge = AccountedCounter::new(&self.accounting, AllocationComponent::Temporary)?;
charge.set(bytes)?;
Ok(GraphReservation { charge })
}
}
/// Owned shared capacity reservation. Drop releases precisely the current charge.
pub struct GraphReservation {
charge: AccountedCounter,
}
impl GraphReservation {
pub(crate) fn belongs_to(&self, resources: &GraphResources) -> bool {
self.charge.belongs_to(&resources.accounting)
}
/// Changes the charge atomically against the shared budgets; failed growth
/// preserves its prior value. Backing must be freed before shrinking.
pub fn resize(&mut self, bytes: usize) -> Result<(), StoreError> {
self.charge.set(bytes)
}
/// Exact currently reserved capacity, not a count of initialized elements.
pub const fn bytes(&self) -> u64 {
self.charge.bytes()
}
}
/// Allocation observations exclude mappings, process footprint and caller/model buffers.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct GraphResourceSnapshot {
/// Current engine-owned working capacities and controls.
pub engine_bytes: u64,
/// Lifetime engine capacity high-water, including replacement overlap.
pub engine_peak_bytes: u64,
/// Reserved for ZE-310; currently zero.
pub application_bytes: u64,
/// Reserved for ZE-310; currently zero.
pub application_peak_bytes: u64,
}
pub(crate) mod work_batch;