pub struct MemoryStore {
pub min_part: u64,
pub max_parts: usize,
/* private fields */
}Fields§
§min_part: u64§max_parts: usizeImplementations§
Source§impl MemoryStore
impl MemoryStore
Sourcepub fn backdate_epoch(&self, key: &str, secs: u64)
pub fn backdate_epoch(&self, key: &str, secs: u64)
Age an object’s last-modified stamp. Liveness here is judged against the STORE’s clock (A8), so a test about a dead holder has to be able to move that clock rather than sleep.
Sourcepub fn plant_lifecycle_rule(&self, rule: LifecycleView)
pub fn plant_lifecycle_rule(&self, rule: LifecycleView)
Plant a lifecycle rule the way a customer’s own fleet policy would. D8’s destroyer is a rule flint never wrote.
pub fn new() -> Self
Sourcepub fn with_if_match_missing_as_412(self) -> Self
pub fn with_if_match_missing_as_412(self) -> Self
Answer If-Match on a missing key with 412, as Ozone’s S3 gateway
does, instead of S3’s 404 NoSuchKey. See if_match_missing_412.
Sourcepub fn with_part_parallelism(self, n: usize) -> Self
pub fn with_part_parallelism(self, n: usize) -> Self
Stage this many parts of one compose concurrently (the S3
backend’s with_part_parallelism). Clamped to at least 1.
Sourcepub fn with_upload_inflight_max_bytes(self, n: u64) -> Self
pub fn with_upload_inflight_max_bytes(self, n: u64) -> Self
Bound the bytes the upload path holds at once (the S3 backend’s
with_upload_inflight_max_bytes; see gate.rs). 0 = no gate.
Sourcepub fn inject_put_whole_delay_ms(&self, ms: u64)
pub fn inject_put_whole_delay_ms(&self, ms: u64)
Every whole PUT from now on sleeps ms first — the write side’s
inject_get_range_delay_ms: whole bodies that overlap are in
flight together for the whole delay, so the upload byte gate’s
high-water mark reads the caller’s bound rather than the
scheduler’s luck.
Sourcepub fn strip_version_ids(&self, on: bool)
pub fn strip_version_ids(&self, on: bool)
Every write from here on reports no version id — a proxy that strips the header (D8’s refusal arm).
Sourcepub fn fail_lifecycle_writes(&self, on: bool)
pub fn fail_lifecycle_writes(&self, on: bool)
Lifecycle writes fail from here on; reads keep working.
Sourcepub fn inject_torn_complete(&self)
pub fn inject_torn_complete(&self)
Next compose: Complete LANDS but the response is lost.
Sourcepub fn inject_crash_before_complete(&self)
pub fn inject_crash_before_complete(&self)
Next compose: dies before Complete — MPU left pending.
Sourcepub fn inject_compose_swept(&self)
pub fn inject_compose_swept(&self)
Next compose: the operator’s abort sweep takes the assembly
before Complete — NoSuchUpload, S3’s answer, and nothing lands.
Sourcepub fn inject_get_range_failure(&self)
pub fn inject_get_range_failure(&self)
Step-11 drills: the NEXT get_range fails with a transport error — a single failure is absorbed by the chunk-retry loop.
Sourcepub fn inject_get_range_failures(&self, n: u64)
pub fn inject_get_range_failures(&self, n: u64)
The next n get_range calls fail with a transport error —
exceed the chunk-retry budget to force the truncate-back path.
Sourcepub fn inject_get_range_delay_ms(&self, ms: u64)
pub fn inject_get_range_delay_ms(&self, ms: u64)
Every get_range from now on sleeps ms first. Unlike the
one-shot stall this is persistent, and it is what makes a
fan-out OBSERVABLE: calls that overlap are in flight together
for the whole delay, so peak_get_range_in_flight reads the
caller’s bound rather than the scheduler’s luck.
Sourcepub fn inject_put_hold(&self, on: bool)
pub fn inject_put_hold(&self, on: bool)
Every whole PUT from now on parks until release_held_puts
(false lets new PUTs through again; a PUT already parked stays
parked). Checked at the start of each PUT, so a test can stall
one task’s upload, let the next caller’s through at once, and
release the stalled one when it chooses.
Sourcepub fn inject_put_hold_matching(&self, key_contains: &str)
pub fn inject_put_hold_matching(&self, key_contains: &str)
Like inject_put_hold, but only for keys containing
key_contains. inject_put_hold(false) ends it.
Sourcepub fn release_held_puts(&self)
pub fn release_held_puts(&self)
Let every parked PUT land.
Sourcepub fn peak_get_range_in_flight(&self) -> u64
pub fn peak_get_range_in_flight(&self) -> u64
The most get_range calls ever in flight at once since the last reset. A fan-out bounded at N reads exactly N here when there is work for N — and exactly 1 when it is not a fan-out at all.
pub fn reset_peak_get_range_in_flight(&self)
Sourcepub fn inject_head_failures(&self, n: u64)
pub fn inject_head_failures(&self, n: u64)
The next n HEAD calls fail with a transport error.
The condition this models is not exotic: the foreign-key sweep issues one HEAD per unknown object, which on a large bucket is exactly the shape that earns a 503 SlowDown. The SDK’s default retry absorbs a blip; a sustained throttle outlives it.
Sourcepub fn inject_epoch_renew_failures(&self, n: u64)
pub fn inject_epoch_renew_failures(&self, n: u64)
The next n renewals fail as a transport error — not a 412, so
the holder cannot tell “deposed” from “cut off”. Zero clears it.
Sourcepub fn inject_put_lands_then_fails(&self, key_contains: &str, n: u64)
pub fn inject_put_lands_then_fails(&self, key_contains: &str, n: u64)
The next n whole PUTs STORE THE OBJECT and then report 409.
This is the one failure a conditional writer cannot interpret.
S3 answers a contended conditional write with 409
ConditionalRequestConflict, and a lost response to a PUT that
landed looks the same from the client: the write is durable and
the caller was told it failed. Every other injector here models
a failure that did NOT happen server-side; this one models the
failure that DID.
key_contains narrows it to one object — a batch uploads its
packs BEFORE the snapshot CAS, so an untargeted injection would
break a pack upload and never reach the write under test.
Sourcepub fn inject_get_range_stall(&self, ms: u64)
pub fn inject_get_range_stall(&self, ms: u64)
Step-11 drills: the NEXT get_range stalls ms before serving —
a slow hydration to race concurrent I/O and priority against.
Sourcepub fn inject_corrupt_body(&self, key: &str, mutate: impl FnOnce(&mut Vec<u8>))
pub fn inject_corrupt_body(&self, key: &str, mutate: impl FnOnce(&mut Vec<u8>))
Test surface: the bytes under a key change while its etag and its stored checksum claim do NOT — bit-rot, a broken gateway, a cache serving the wrong body. Nothing on the wire says so: If-Match still matches, and a store that never carried a checksum header validates nothing. Only a reader that checks the body against what the MANIFEST cites can see it.
Sourcepub fn raw_put(
&self,
key: &str,
bytes: Bytes,
meta: Vec<(String, String)>,
) -> ObjectMeta
pub fn raw_put( &self, key: &str, bytes: Bytes, meta: Vec<(String, String)>, ) -> ObjectMeta
Test surface: plant an object directly (foreign writers, torn own states, import fixtures). Stamps go in as given.
Sourcepub fn redeem_presigned_put(
&self,
url: &str,
headers: &BTreeMap<String, String>,
body: Bytes,
) -> StoreResult<ObjectMeta>
pub fn redeem_presigned_put( &self, url: &str, headers: &BTreeMap<String, String>, body: Bytes, ) -> StoreResult<ObjectMeta>
Test surface: REDEEM a URL from ObjectStore::presign_put the
way S3 does, so a test can play the client — or the attacker —
who holds it.
Without this the double’s presigned URL was a string nothing ever used, and “the URL grants only the bytes it was issued for” could not be asked of it at all. What S3 enforces, and so what this enforces (and nothing more):
- every header the URL SIGNED must be presented, with the signed value, or the signature does not match (403). An unsigned header binds nothing: the holder simply leaves it out.
- a presented
x-amz-checksum-sha256must be the base64 SHA-256 of the body (400 BadDigest). - a presented
If-None-Match: *refuses a key that exists (412).
Header names are compared case-insensitively, as HTTP does.
Sourcepub fn expire_noncurrent(&self, older_than_secs: u64) -> Vec<(String, String)>
pub fn expire_noncurrent(&self, older_than_secs: u64) -> Vec<(String, String)>
Test surface: the NONCURRENT-VERSION LIFECYCLE BACKSTOP (D8), modelled as an explicit method because it is a timer in reality and an untestable one if left implicit.
The hazard it exists to demonstrate is INVERTED from the
eager-prefix design’s: gated staging makes the cited version
noncurrent the moment a newer generation is staged, so a
NoncurrentVersionExpiration rule on files/ runs a clock
against live cited data — and never against the newest uncited
bytes, which are current and which no lifecycle rule can reach.
Reaping a cited noncurrent version dangles the manifest; that is
Inv_CitedVersionLives’s required-firing mutation and leg B23’s
abandoned-mid-stage endgame.
Returns the (key, version_id) pairs reaped.
Sourcepub fn version_count(&self, key: &str) -> usize
pub fn version_count(&self, key: &str) -> usize
Test surface: how many versions a key currently holds (leg B21’s oracle — steady state must return to ONE live version per key, reclaimed by flint’s exact per-citation GC, NOT by waiting for the backstop).
Sourcepub fn raw_complete_upload(&self, upload_id: &str) -> StoreResult<ObjectMeta>
pub fn raw_complete_upload(&self, upload_id: &str) -> StoreResult<ObjectMeta>
Test surface: a DEPOSED writer’s late CompleteMultipartUpload.
Assembles whatever parts exist (unconditionally — the deposed
straggler of the A8 drill carries no working guard); answers
NoSuchUpload if the assembly was fenced away, exactly S3’s
answer after the takeover abort-sweep.
Sourcepub fn raw_begin_upload(&self, key: &str) -> String
pub fn raw_begin_upload(&self, key: &str) -> String
Test surface: an orphan MPU (for the A9 sweep tests).
Trait Implementations§
Source§impl Default for MemoryStore
impl Default for MemoryStore
Source§impl ObjectStore for MemoryStore
impl ObjectStore for MemoryStore
Source§fn presign_get<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
ttl_secs: u64,
) -> Pin<Box<dyn Future<Output = StoreResult<String>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn presign_get<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
ttl_secs: u64,
) -> Pin<Box<dyn Future<Output = StoreResult<String>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
A stand-in URL: deterministic, unmistakably not real, and refused for a key that does not exist. A test can assert that the right key was signed and that a missing object is not advertised; whether a git client can actually fetch it is a question only a real store answers, and forge’s storm leg is where that is asked.
Source§fn presign_put<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
key: &'life1 str,
ttl_secs: u64,
sha256: &'life2 [u8; 32],
) -> Pin<Box<dyn Future<Output = StoreResult<PresignedPut>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn presign_put<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
key: &'life1 str,
ttl_secs: u64,
sha256: &'life2 [u8; 32],
) -> Pin<Box<dyn Future<Output = StoreResult<PresignedPut>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
A stand-in URL for a write. Unlike the read side it does NOT
require the object to exist — that is the whole point of an
upload. The headers it binds are written INTO the URL as h.
parameters, which is how redeem_presigned_put plays S3’s
signature: a signed header must be presented as signed.
Source§fn get_range_segments<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
key: &'life1 str,
offset: u64,
len: u64,
if_match: &'life2 str,
) -> Pin<Box<dyn Future<Output = StoreResult<Vec<Bytes>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn get_range_segments<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
key: &'life1 str,
offset: u64,
len: u64,
if_match: &'life2 str,
) -> Pin<Box<dyn Future<Output = StoreResult<Vec<Bytes>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Real S3 always delivers a ranged body as MANY frames. This
double handed back exactly one, so a caller that walks segments
and advances a running offset was never actually exercised
against it — a double missing a property its subject always has,
which passes for the wrong reason. Built on get_range so every
injected failure, stall and in-flight count still applies.
Source§fn delete_many<'life0, 'life1, 'async_trait>(
&'life0 self,
keys: &'life1 [String],
) -> Pin<Box<dyn Future<Output = StoreResult<DeleteManyReport>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn delete_many<'life0, 'life1, 'async_trait>(
&'life0 self,
keys: &'life1 [String],
) -> Pin<Box<dyn Future<Output = StoreResult<DeleteManyReport>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
One request per thousand keys, as S3’s DeleteObjects costs — so
a request census over the double reads what the wire would.
Source§fn request_counts(&self) -> Option<RequestCounts>
fn request_counts(&self) -> Option<RequestCounts>
counters.rs). None = a store that does not count.Source§fn put_whole<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
key: &'life1 str,
body: Bytes,
condition: &'life2 PutCondition,
stamps: &'life3 GenerationStamps,
crc64: u64,
) -> Pin<Box<dyn Future<Output = StoreResult<ObjectMeta>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
fn put_whole<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
key: &'life1 str,
body: Bytes,
condition: &'life2 PutCondition,
stamps: &'life3 GenerationStamps,
crc64: u64,
) -> Pin<Box<dyn Future<Output = StoreResult<ObjectMeta>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
crc64 is validated server-side; stamps ride as metadata.Source§fn copy_object<'life0, 'life1, 'life2, 'life3, 'life4, 'life5, 'async_trait>(
&'life0 self,
src_key: &'life1 str,
src_if_match: Option<&'life2 str>,
dst_key: &'life3 str,
condition: &'life4 PutCondition,
stamps: &'life5 GenerationStamps,
) -> Pin<Box<dyn Future<Output = StoreResult<ObjectMeta>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
'life5: 'async_trait,
fn copy_object<'life0, 'life1, 'life2, 'life3, 'life4, 'life5, 'async_trait>(
&'life0 self,
src_key: &'life1 str,
src_if_match: Option<&'life2 str>,
dst_key: &'life3 str,
condition: &'life4 PutCondition,
stamps: &'life5 GenerationStamps,
) -> Pin<Box<dyn Future<Output = StoreResult<ObjectMeta>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
'life5: 'async_trait,
fn compose_generation<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
spec: &'life1 ComposeSpec<'life2>,
) -> Pin<Box<dyn Future<Output = StoreResult<ObjectMeta>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn head<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
) -> Pin<Box<dyn Future<Output = StoreResult<ObjectMeta>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Source§fn get_whole<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
key: &'life1 str,
if_match: Option<&'life2 str>,
) -> Pin<Box<dyn Future<Output = StoreResult<(ObjectMeta, Bytes)>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn get_whole<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
key: &'life1 str,
if_match: Option<&'life2 str>,
) -> Pin<Box<dyn Future<Output = StoreResult<(ObjectMeta, Bytes)>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Source§fn get_range<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
key: &'life1 str,
offset: u64,
len: u64,
if_match: &'life2 str,
) -> Pin<Box<dyn Future<Output = StoreResult<Bytes>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn get_range<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
key: &'life1 str,
offset: u64,
len: u64,
if_match: &'life2 str,
) -> Pin<Box<dyn Future<Output = StoreResult<Bytes>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn list<'life0, 'life1, 'async_trait>(
&'life0 self,
prefix: &'life1 str,
) -> Pin<Box<dyn Future<Output = StoreResult<Vec<ListedObject>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn delete<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
) -> Pin<Box<dyn Future<Output = StoreResult<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Source§fn delete_if_match<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
key: &'life1 str,
etag: &'life2 str,
) -> Pin<Box<dyn Future<Output = StoreResult<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn delete_if_match<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
key: &'life1 str,
etag: &'life2 str,
) -> Pin<Box<dyn Future<Output = StoreResult<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
key only while its current ETag is etag (If-Match):
PreconditionFailed once the object has moved on, NotFound
when there is nothing to delete. Read moreSource§fn head_version<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
key: &'life1 str,
version_id: &'life2 str,
) -> Pin<Box<dyn Future<Output = StoreResult<ObjectMeta>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn head_version<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
key: &'life1 str,
version_id: &'life2 str,
) -> Pin<Box<dyn Future<Output = StoreResult<ObjectMeta>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Source§fn get_version<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
key: &'life1 str,
version_id: &'life2 str,
) -> Pin<Box<dyn Future<Output = StoreResult<(ObjectMeta, Bytes)>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn get_version<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
key: &'life1 str,
version_id: &'life2 str,
) -> Pin<Box<dyn Future<Output = StoreResult<(ObjectMeta, Bytes)>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Source§fn delete_version<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
key: &'life1 str,
version_id: &'life2 str,
) -> Pin<Box<dyn Future<Output = StoreResult<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn delete_version<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
key: &'life1 str,
version_id: &'life2 str,
) -> Pin<Box<dyn Future<Output = StoreResult<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Source§fn list_versions<'life0, 'life1, 'async_trait>(
&'life0 self,
prefix: &'life1 str,
) -> Pin<Box<dyn Future<Output = StoreResult<Vec<ListedVersion>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn list_versions<'life0, 'life1, 'async_trait>(
&'life0 self,
prefix: &'life1 str,
) -> Pin<Box<dyn Future<Output = StoreResult<Vec<ListedVersion>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
orphans.json is
missing or stale — the expensive path, which is why the durable
summary is written eagerly.Source§fn list_uploads<'life0, 'life1, 'async_trait>(
&'life0 self,
prefix: &'life1 str,
) -> Pin<Box<dyn Future<Output = StoreResult<Vec<PendingUpload>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn list_uploads<'life0, 'life1, 'async_trait>(
&'life0 self,
prefix: &'life1 str,
) -> Pin<Box<dyn Future<Output = StoreResult<Vec<PendingUpload>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Source§fn abort_upload<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
_key: &'life1 str,
upload_id: &'life2 str,
) -> Pin<Box<dyn Future<Output = StoreResult<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn abort_upload<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
_key: &'life1 str,
upload_id: &'life2 str,
) -> Pin<Box<dyn Future<Output = StoreResult<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Source§fn bootstrap<'life0, 'life1, 'async_trait>(
&'life0 self,
_prefix: &'life1 str,
) -> Pin<Box<dyn Future<Output = StoreResult<BootstrapReport>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn bootstrap<'life0, 'life1, 'async_trait>(
&'life0 self,
_prefix: &'life1 str,
) -> Pin<Box<dyn Future<Output = StoreResult<BootstrapReport>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Source§fn lifecycle_rules<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = StoreResult<Vec<LifecycleView>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn lifecycle_rules<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = StoreResult<Vec<LifecycleView>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
LifecycleView. Read moreSource§fn ensure_noncurrent_retention<'life0, 'life1, 'async_trait>(
&'life0 self,
prefix: &'life1 str,
days: u64,
) -> Pin<Box<dyn Future<Output = StoreResult<RetentionOutcome>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn ensure_noncurrent_retention<'life0, 'life1, 'async_trait>(
&'life0 self,
prefix: &'life1 str,
days: u64,
) -> Pin<Box<dyn Future<Output = StoreResult<RetentionOutcome>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
prefix
with read-merge-append, and report what is installed. Read morefn epoch_read<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
) -> Pin<Box<dyn Future<Output = StoreResult<Option<EpochState>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Source§fn epoch_acquire<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
key: &'life1 str,
holder_id: &'life2 str,
supersede: Option<&'life3 EpochState>,
) -> Pin<Box<dyn Future<Output = StoreResult<EpochLease>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
fn epoch_acquire<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
key: &'life1 str,
holder_id: &'life2 str,
supersede: Option<&'life3 EpochState>,
) -> Pin<Box<dyn Future<Output = StoreResult<EpochLease>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
supersede: None creates (If-None-Match:*); Some
replaces the OBSERVED state via CAS on its token — the caller
(step 7) is responsible for having JUDGED that holder dead
against the store’s clock. The new epoch is observed+1.Source§fn epoch_renew<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
key: &'life1 str,
lease: &'life2 EpochLease,
echo: Option<&'life3 str>,
) -> Pin<Box<dyn Future<Output = StoreResult<EpochLease>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
fn epoch_renew<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
key: &'life1 str,
lease: &'life2 EpochLease,
echo: Option<&'life3 str>,
) -> Pin<Box<dyn Future<Output = StoreResult<EpochLease>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
PreconditionFailed means deposed: self-fence. Read moreSource§fn epoch_release<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
key: &'life1 str,
lease: &'life2 EpochLease,
) -> Pin<Box<dyn Future<Output = StoreResult<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn epoch_release<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
key: &'life1 str,
lease: &'life2 EpochLease,
) -> Pin<Box<dyn Future<Output = StoreResult<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
lease’s own token so a deposed
holder cannot mark a live successor’s cell.Source§fn epoch_handoff<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
key: &'life1 str,
lease: &'life2 EpochLease,
echo: Option<&'life3 str>,
) -> Pin<Box<dyn Future<Output = StoreResult<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
fn epoch_handoff<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
key: &'life1 str,
lease: &'life2 EpochLease,
echo: Option<&'life3 str>,
) -> Pin<Box<dyn Future<Output = StoreResult<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
ObjectStore::epoch_release, but hand it to
the queue head (handoff = waiters[0], the rest stay queued) and
KEEP echo — the cell is at rest between every barrier now, so
the last holder’s echo is the only thing that tells an operator
which binary ran the last boundary. Guarded on the lease token
like every other transition. Default: the plain release.Source§fn epoch_enqueue<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
key: &'life1 str,
observed: &'life2 EpochState,
holder_id: &'life3 str,
) -> Pin<Box<dyn Future<Output = StoreResult<EpochState>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
fn epoch_enqueue<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
key: &'life1 str,
observed: &'life2 EpochState,
holder_id: &'life3 str,
) -> Pin<Box<dyn Future<Output = StoreResult<EpochState>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
holder_id to the cell’s FIFO of waiters, by CAS on the
OBSERVED token, and return the cell as rewritten. A holder that
is already queued is not appended twice. The write moves the
token: a live holder’s next renew/handoff 412s, re-reads, and
adopts the new token with the longer queue (lean lease.rs).
Default: unsupported — a backend without a queue serialises
claimants by the quiet-poll rule alone.Source§fn min_part_size(&self) -> u64
fn min_part_size(&self) -> u64
fn max_parts(&self) -> usize
Source§fn upload_gate(&self) -> Option<Arc<ByteGate>>
fn upload_gate(&self) -> Option<Arc<ByteGate>>
gate::ByteGate),
when it was built with one. The store charges every local part
of a compose to it; a caller that reads whole bodies ITSELF
before put_whole (lean’s upload_one) takes this so those
bodies are charged to the SAME budget, and the bound is one
number rather than two that must be set together. None = the
upload path is bounded only by its counts.