Skip to main content

Module write_meter

Module write_meter 

Source
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.
WriteLimitError
A [writes] key written outside the range it is documented with.
WriteLimits
How fast one account may write, and how much it may write at once.
WriteMeter
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::charge drops buckets that have refilled.

Functions§

quota 🔒

Type Aliases§

Keyed 🔒