Expand description
Per-account write metering: one token bucket on write operations and one on request bytes, both keyed by the authenticated account.
Every account shares one write-ahead log, and [capacity] log_budget_bytes bounds it for all of them together. The server trims the
log at [capacity] checkpoint_log_bytes, so what the budget has to hold is
what all the accounts write between two checkpoints. The meter bounds how
fast one account can grow it, so an account in a loop is one share of that
rather than all of it. It bounds a rate, not a total: every account has its
own buckets.
§What is charged
createRecord, putRecord and deleteRecord cost one operation;
applyWrites costs one per write in its batch. Each also costs its
request body’s length in bytes. uploadBlob costs one operation and no
bytes, because [blobs] account_quota_bytes already bounds what an
account’s blobs hold. A request is charged once write policy has allowed
it, just before it commits, so neither a token that may not write nor a
client that policy refuses can spend the account’s share. A write the
store refuses after that, such as a failed swap, has still spent its
tokens. A write refused by the byte bucket has already spent its
operations.
The buckets are in memory and start full when the server starts.
§The defaults, worked through
A write’s cost to the log does not depend on the record’s size: the body
goes to the record heap, and the log gets the record’s slot and the
commit naming it. Measured, that is about 1 KiB for a single
createRecord, putRecord or deleteRecord, and about 240 bytes per
write inside a 200-write applyWrites. So the operation bucket is what
bounds the log:
- At most
DEFAULT_OPS_BURST+DEFAULT_OPS_PER_HOUR= 4,600 operations in any hour. - 4,600 × 1 KiB ≈ 4.5 MiB of log an hour, about 0.2% of the 2 GiB budget a default 20 GiB volume gets.
- One account writing flat out reaches the default 1 GiB watermark, where the server checkpoints and trims, in about 227 hours. A repository deep enough to double the cost of a write halves that.
The byte bucket bounds the record heap, which shares the volume:
- At most
DEFAULT_BYTES_BURST+DEFAULT_BYTES_PER_HOUR= 72 MiB of request bodies in any hour, about 0.35% of a 20 GiB volume. - A loop of full 2 MiB requests gets four back to back, then one every 112 seconds.
An agent writing a 1 KiB record every five seconds spends 720 operations and under 1 MiB an hour: 20% of the operation rate and about 1% of the byte rate.
Structs§
- Refusal
- A write the meter refused.
- Write
Limit Error - A
[writes]key written outside the range it is documented with. - Write
Limits - How fast one account may write, and how much it may write at once.
- Write
Meter - The two buckets for every account that has written lately. A bucket that has refilled is dropped, since a missing one starts full anyway.
Enums§
- Bucket
- Which bucket refused a write.
Constants§
- DEFAULT_
BYTES_ BURST WriteLimits::bytes_burst’s default: 8 MiB, four full request bodies.- DEFAULT_
BYTES_ PER_ HOUR WriteLimits::bytes_per_hour’s default: 64 MiB.- DEFAULT_
OPS_ BURST WriteLimits::ops_burst’s default.- DEFAULT_
OPS_ PER_ HOUR WriteLimits::ops_per_hour’s default: one operation a second.- SWEEP_
EVERY 🔒 - How often
WriteMeter::chargedrops buckets that have refilled.
Functions§
- quota 🔒
Type Aliases§
- Keyed 🔒