Status: a proposal, not adopted.
It would replace how both variants of Cleaning by ripeness estimate a page’s drain and decide on it: the single-rate draft on branch ripeness, and the draft with a static share on branch ripeness2.
It assumes both drafts, and uses their notation: fills relative to , for a page’s fill, and for its draining and static shares, , , , , , and .
Executive summary
Keep a posterior over each page’s drain rather than a point estimate, and decide from it: with a static share, that is what makes the static share pay. A page’s estimate rests on little: a data page in kladde-bench’s files holds 10 to 30 chunks, and the fall that would show a static share comes to a few of them (Ripeness with a static share). The drafts cope with that by devices of their own, a forgetting rate, a weight for the starting estimate, a test, and a floor; here each becomes a parameter of one prior.
- Evidence is counted in bytes, and weighed in loss events.
A page loses the bytes that writes supersede, on a data page often part of a
Ref’s payload at a time; divided by the dispersion of the events’ sizes, , bytes lost and bytes exposed count as the independent observations they are. - With one rate per page, the posterior is a Gamma distribution, exact even for a rate that drifts, and its mean is exactly the single-rate draft’s estimate. What it adds is how certain the estimate is, and a start learned from the file.
- With a static share, the posterior is a mixture over how many of the page’s untouched chunks drain. A chunk that has lost bytes is known to drain, and a prior on the draining fraction takes the place of the static-share draft’s test.
- A page’s start is learned from the file, not tuned. Fresh content starts from the file’s empirical prior, the mean and spread of the rates at which fresh pages have drained, which comes out weak and beats every fixed start in simulation. Starting moved content from its sources’ posteriors, matched in their moments, does not pay until they are corrected for moved content being colder than its source, so moved content starts from the empirical prior too.
- How the decision reads the posterior matters little. Deciding by the expected gain (a) or by the probability of a gain (b) differs from the posterior mean by about a point in simulation, except that (b) costs a few points more on pages of a few large chunks. Rule (c), which guards against every loss a page could still suffer, is too cautious; (c′), which weighs each by its predictive probability, is the posterior mean in effect, since the predictive trusts the very posterior whose dips make cleaning early.
- In simulation, the cure model’s posterior, started from the empirical prior and decided by (a), costs 10.9 % more than cleaning at the true index where the static-share draft’s fit costs 24.3 %, with chunks losing their bytes in parts; with chunks dying whole, 37.9 % against 45.0 %. It sees a static share almost exactly once chunks lose their bytes in parts, since a chunk’s first loss shows that it drains. The single-rate posterior costs a point or three less than its draft.
These are simulations, costed by the drafts’ own model; nothing has run on kladde-bench.
The decision under a posterior
The gain of cleaning now
Cleaning a page now rather than one epoch later gains per epoch, where solves for . Waiting one more epoch costs , the room the page’s survivors would not fill, and saves what the bytes that die meanwhile would have cost: of them, each of which would have been copied now and cost afterwards. At its own threshold , content of rate balances the two, so , and since , is . is measured in pages: the room a cleaning frees, less the draining share weighted by what waiting would still save on it. The page is ripe once , which is the drafts’ rule: exactly when , and with one rate per page, and .
rises from 0, like for small and like for large , and it is concave.
| 0.0001 | 0.01 | 1 | 10 | 100 | |
|---|---|---|---|---|---|
| 0.014 | 0.15 | 2.1 | 12.6 | 104.7 |
Three ways to decide
With a posterior over the page’s parameters , which are with one rate per page and with a static share, becomes a random variable, and there are three ways to turn it into a decision.
- (a) The expected gain: clean once . This is what a decision-maker who is neutral to risk does; over a mixture posterior, it is the weighted sum of the components’ expected gains.
- (b) The probability of a gain: clean once , that is, once cleaning now is more likely than not to be right. The step function in counts how often cleaning is right, not by how much.
- (c) Ripe whatever it loses next: clean once the page would be ripe by the posterior mean, or by (a), even after any number of further losses. Waiting teaches derives it: the other two clean at the first epoch the posterior calls a page ripe, which is early, because a page’s next loss can make it unripe again. In simulation, it is too cautious to pay. Its refinement (c′) weighs each further loss by its predictive probability, and cleans once cleaning now gains at least what the option to wait is worth.
All of them keep the drafts’ ranking by an index, since each is monotone in . For every , rises with , since rises with ; so and rise with too, and each criterion holds for every above one price . A page’s index is , the at which it becomes ripe, as in the drafts, so the budget loop, the controller, and the floor stay as they are: a page is ripe once , and the loop takes the highest index first.
Between losses, the ranking ages each posterior’s scale, as the drafts age a rate. A posterior changes every epoch, losses or not, but the ranking can only afford a change when a page changes. So each page’s index is computed exactly at each of its losses, and between them its rate is taken to fall by per epoch in distribution: the posterior’s scale shrinks and its shape stays. Every criterion below then grows the index by the same factor per epoch, on every page alike, which is what the drafts’ ordered sets need. Where that differs from the exact update, it takes the posterior for more certain than it is between losses, which the section on learning shows to be the safe side.
One rate per page
Losses counted in bytes, weighed in loss events
The observations are the bytes a page loses, weighed by how many independent events they came in: a write supersedes a range, and the bytes of one range are one observation, not many.
The model is the single-rate draft’s: a page’s live bytes die at a rate , a fraction of them per epoch, whatever their age.
But they do not die one at a time: a write supersedes a range, which on a data page is often part of a Ref’s payload, the rest of which lives on, and on a leaf is a whole statement.
So a page’s losses are a compound Poisson process: events arriving at a rate proportional to and to the live bytes, each removing some bytes.
Over an exposure , the live bytes times the epochs they were watched, the bytes lost have mean and a variance larger than that by the factor , the dispersion of the events’ sizes.
Divided by , and behave as a Poisson count and its exposure, and the likelihood of is
exact where the events are of one size, and counts them, and a match of the first two moments otherwise. Over an epoch in which a page starts with live and loses , its exposure is , counting what died as live for half the epoch; , , and may be in pages or bytes, as long as all three are in the same unit.
- Counting every byte as an observation would make the posterior times too sure: 250 times, for statements of 250 bytes that die whole.
- Counting statements would miss that a data page’s statements lose their payloads in parts and live on, and would count a statement’s many partial losses as none.
The fold knows each event’s size, since it supersedes one range at a time, so it can keep and as running averages over the file, one pair for data pages and one for leaves. On a leaf, whose statements die whole, an event is a statement’s death, and is the mean size of the statements that die, weighted by their size. The dispersion sets only how sure the posterior is: the posterior mean below is a ratio of bytes lost to bytes exposed, the same in any unit.
The exact posterior is a Gamma distribution
A Gamma prior on the rate gives a Gamma posterior, whose two parameters count the page’s loss events and its exposure, in events. With a prior , of density proportional to , the posterior after losing over an exposure is
with mean and a relative spread of , where and are the posterior’s two parameters. is the number of loss events the estimate rests on, the prior’s included: the prior acts as events over an exposure of , so a starting estimate worth epochs of the page’s would be and , though below the weight is learned rather than set.
A rate that drifts keeps the posterior exact
A prior under which the rate drifts by random factors, of mean one, turns the update into a discounted one, and keeps it exact: and each epoch, with . The drafts forget old losses because a page’s rate changes as its content does. The Bayesian way to say so is a prior over the rate’s path, and one prior makes the forgetting exact: between epochs, , with drawn from a distribution independent of , where is the posterior’s shape before the step: the gamma–beta model of Smith and Miller, A non-Gaussian state space model and application to prediction of records (J. R. Stat. Soc. B, 1986), known in forecasting as the Poisson–gamma steady model with a discount factor. A variable times an independent one is , so the rate’s prior for the next epoch is : the same mean, and a variance larger by . The epoch’s losses then update it as above. The drafts’ forgetting rate becomes the prior’s drift, its third parameter beside and .
The single-rate draft is this posterior’s mean
Once a page’s exposure has settled, the posterior mean follows exactly the single-rate draft’s update.
With live, settles at , and then , which is the draft’s lose.
The posterior adds two things.
- Its mean is right while the exposure is still growing. Until then, the mean is the ratio of the discounted losses to the discounted exposure, as Adam’s bias correction would make it, but with the prior’s weight, events, learned from evidence; the draft’s start weighs about epochs, fixed.
- Its shape counts the loss events the estimate rests on. At the settled exposure, . A page at fill 0.5 draining at 0.01 per epoch, with , rests on 3.2 events if it loses 64 bytes at a time, and its rate is uncertain by 56 %; if it loses whole statements of 250 bytes, it rests on 0.8 of one.
What a page keeps
A page keeps , , and the epoch it last lost bytes, all updated in closed form: one number more than the single-rate draft. Over epochs without a loss, with live, and .
/// Per page, beside kind, epoch and coverage: 12 bytes.
struct Drain {
a: f32, // the posterior's shape: loss events, discounted, with the prior's
b: f32, // its rate: exposure in events, discounted, with the prior's
at: u32, // the epoch of the page's last natural loss, from the session's base
}
impl Drain {
/// A flush's fold superseded `lost` of the page's `live` bytes; `sigma` is
/// the dispersion of loss events on pages of its kind.
fn lose(&mut self, lost: u32, live: u32, sigma: f32, now: u32) {
let (lost, live) = (lost as f32 / sigma, live as f32 / sigma);
// The epochs since the last loss, without one:
let (delta, d) = ((-BETA).exp(), (now - self.at - 1) as f32);
let decay = delta.powf(d);
self.a *= decay;
self.b = self.b * decay + live * (1.0 - decay) / (1.0 - delta);
// This epoch:
self.a = delta * self.a + lost;
self.b = delta * self.b + live - 0.5 * lost;
self.at = now;
}
}The dispersion drifts as the application’s writes change, and a page’s sums mix the values it had when they were added, which matters little since it moves slowly.
Where a page’s prior comes from
A page’s prior is learned rather than tuned: fresh content starts from the file’s empirical prior, and moved content could start from its sources’ posteriors, matched in their first two moments, though in simulation the empirical prior serves it better. The drafts start a page at a rate with a fixed weight; here the weight, too, comes from evidence: how alike the file’s fresh pages have turned out, and how much its sources knew. Either way, the prior is a Gamma distribution, which is fixed by its mean and variance : and .
Fresh content starts from the file’s empirical prior: the mean and the spread of the rates at which fresh pages have drained in their first epochs. The drafts start fresh content at “a running estimate of what pages lose in the epoch after they are written”; this estimates the spread as well. Over the pages the file has written, let page lose events over an exposure of in its first epochs, with the posterior’s memory, . Were all of them to drain at one rate, would scatter about as Poisson counts do; the scatter beyond that is the spread of their rates, and the method of moments for a Gamma mixture of Poisson rates gives
over the last such pages, floored at a small fraction of . The prior’s weight, events, is then how alike the file’s fresh pages are: a file whose fresh pages all drain alike starts each one sure of its rate, and one whose fresh pages differ starts each one unsure, so that its own losses soon decide. The fold keeps the five sums , , , , and over the file, discounted like the rest, and adds a page to them once it is epochs old.
Moved content starts from its sources’ posteriors: the Gamma distribution with the mean and variance of the mixture they make. A page whose content comes from sources with byte shares and posteriors of mean and variance starts with
the moments of the rate of a byte drawn from the mix, and fresh content in the mix counts as one more source, with the empirical prior. The variance includes the spread between the sources as well as each one’s own: a page mixed from sources that drain alike starts as sure as they were, and one mixed from sources that drain differently starts unsure, as it should, since the single rate it will be estimated to drain at is not yet known. With a static share, the rate’s prior comes from the draining content of the sources alone, and the draining fraction’s prior from their draining shares, as before.
But a source sure of the wrong rate hands its certainty on, and moved content’s source usually is: the survivors of a cleaned page drain slower than the page did. In simulation, matching the sources’ posteriors costs more than starting from the empirical prior, which gains even on pages whose start is right; so until the sources’ rates are corrected for what their content’s survival says about it, moved content, too, starts from the empirical prior.
A page the consolidator state cannot vouch for starts from the seed, as a past it was watched through. The seed at open has the drafts’ rate, and weighs what the page’s past would have, had the page been watched through it losing bytes at that rate: is the discounted exposure of the bytes it would have held, over , and .
The floor
The floor becomes a rate that no content falls below. Adding times each epoch’s exposure to its loss events asserts a background rate for all content, and keeps the posterior mean at or above it; it changes every draining page’s rate by , which is negligible, and it caps a frozen page’s index as the drafts’ floor does.
Deciding on one rate
With and , every criterion reduces to the drafts’ index with an effective rate that depends on the posterior’s shape .
- The posterior mean, for comparison: .
- (a) , with . The page is ripe once , so with . has no closed form, but it is a smooth function of two variables, so a table of over and , computed once, gives the index in two lookups.
- (b) , the regularized incomplete gamma function , which is where is the median of . So : the drafts’ index at the posterior’s median rate, with for .
Both make an uncertain page riper than its posterior mean does, and the less the page has lost, the riper. is concave, so and ; and the median of a Gamma distribution lies below its mean, so . The factor , for a page at fill 0.5:
| , the loss events the posterior rests on | 0.5 | 1 | 2 | 5 | 20 |
|---|---|---|---|---|---|
| (a), expected gain | 1.29 | 1.15 | 1.08 | 1.03 | 1.01 |
| (b), probability of a gain | 2.20 | 1.44 | 1.19 | 1.07 | 1.02 |
For (a), the factor is larger at higher fills, 1.23 at and fill 0.8, and smaller at lower ones; for (b), it does not depend on the fill.
Waiting teaches, and the drafts’ rule does not see it
The drafts clean a page at the first epoch at which one more epoch of waiting does not pay; that is optimal only if a ripe page stays ripe, and under an estimated rate it does not: the page’s next loss can make it unripe again. The static-share draft says so: “once ripe, a page stays ripe, since and only fall as it drains; for a stopping problem of that kind, stopping at the first epoch at which one more epoch of waiting does not pay is optimal.” With the rate known, that holds. With the rate estimated, a loss does two things: it lowers the fill, which ripens the page, and it raises the estimated rate, which unripens it.
At the drafts’ constants, the second wins at every fill above 1/11. Take the posterior mean at a settled exposure, , and a loss event of . It raises by one, and so the estimated rate by about ; and it lowers the fill by , which raises by , since . A page that has just become ripe, , is still ripe after the loss only if , that is, if , whatever the size of the event. At and , that asks for , a fill of at most 1/11; at the price of 0.025 that the single-rate branch’s controller settled on under skewed overwrites, a fill of at most 0.2. Above those fills, a page that has just become ripe is unripe again after its next loss, until the estimate has fallen again.
So every rule that cleans at the first ripe epoch cleans early, and the more so the fewer losses its estimate rests on. It cleans a page at the first dip of its estimate, not at the epoch at which the page’s content has drained enough. That holds for the drafts’ point estimates as much as for (a) and (b), which only add to it by making uncertain pages riper still, and it is part of what the static-share draft’s simulation saw on pages that drain slowly.
(c) Clean a page only once no loss it could still suffer would make it unripe again. The index for (c) is the least of the indexes the page would have after further loss events, for every :
with any of the indexes above. Losses at once are the case to guard against: losses spread over time are no worse, since the estimate falls between them, and epochs without a loss only ripen a page further. So once a page’s (c) index has reached , no observation it could still make would reverse the decision, which restores the drafts’ argument, at the price of cleaning later than the best rule would when the losses that would unripen the page are unlikely. The minimum lies a few losses out: for a page at fill 0.5 that loses a thirtieth of a page at a time, with a posterior resting on , it lies at , 24 % below the page’s present index by the posterior mean. Rule (c) needs no parameter of its own, and costs a handful of evaluations of the underlying index per loss. But it guards against losses that a page is unlikely to suffer as firmly as against likely ones, and in simulation that makes it wait too long on every page but those that drain slowly as one share.
(c′) Clean a page once cleaning now gains at least what the option to wait is worth. This weighs each further loss by its probability, which (c) did not. Over the posterior’s memory, epochs, a page’s loss events have a negative-binomial predictive distribution, the Poisson count averaged over the Gamma posterior:
with for one rate per page. After events, the posterior is discounted by , with the events and the epochs’ exposure added, and the page has lost . If that leaves it unripe, cleaning now forgoes the gain per epoch that waiting would have kept, so the option to wait is worth per epoch, and (c′) cleans once
both at the posterior mean. Both sides are monotone in , so the index is again the at which they are equal, found by bisection over a sum of some tens of terms. This is the knowledge gradient, the one-step look-ahead of Bayesian optimal learning, with a step as long as the posterior’s memory.
(c′) is the posterior mean in all but name: the option to wait is worth anything only where the posterior rests on less than one loss event. At fills of 0.3 to 0.8, with loss events of 180 bytes, its index equals the posterior mean’s for a posterior resting on 2 events or more, with a horizon of 1, 3, or epochs alike, and falls 4 to 10 % below it for one resting on half an event. The predictive comes from the same posterior whose dip makes the drafts’ rule clean early, so it expects no more losses than that posterior does, and over any horizon, the losses it does expect ripen the page further, by draining it, while the estimate relaxes. What (c) guarded against, the dip itself, is not in the predictive at all: it shows that the drift the prior assumes is faster than a page’s rate really changes, and the remedy for that lies in the prior’s drift, not in the decision rule.
A draining share over a static one
The cure model, per chunk
Each chunk a page is written with drains with some probability and is static otherwise; a draining chunk loses its bytes at the rate , in loss events, and a static one never loses any.
A chunk is what the page holds of one statement: on a data page, a Ref’s payload, and on a leaf, the statement itself.
The class is the chunk’s rather than each byte’s because temperature belongs to allocations, so a chunk’s bytes share one fate.
In survival analysis, this is a mixture cure model: a population of which a fraction never experiences the event.
A chunk that has lost bytes is known to drain, and on a data page it usually lives on.
A write that supersedes part of a Ref’s payload shows that the chunk drains, and leaves the rest of it live; on a leaf, a statement’s first loss is its death.
So the draining share has a known part and an unknown one: the live bytes of the touched chunks, , drain for certain, and of the untouched chunks, some number drain, so that , with the untouched chunks’ mean size.
The exact posterior is a mixture over the untouched chunks that drain
With a Gamma prior on and a Beta prior on , the posterior is a mixture of Gamma–Beta products, one for each number of untouched chunks that drain. Take a page written epochs ago with chunks, of which have been touched, and not. The touched chunks drain, and their losses, in all over an exposure of their bytes since the page’s write, bear on the rate as in the single-rate posterior. Each untouched chunk either drains and has lost nothing in epochs of it, which for bytes has probability , or is static:
taking the untouched chunks at their mean size , which the binomial expansion needs; exactly, the sum runs over the subsets of untouched chunks that drain, each with its own size. Its term is the case that exactly of the untouched chunks drain, and each term is a Gamma density in times a Beta density in , so with the priors and , the posterior is the mixture
with , , and the Beta function. The weight is the posterior probability that exactly of the untouched chunks drain, and given , the rate has the single-rate posterior of a page whose draining untouched chunks have added their exposure to that of the touched ones.
- The Beta factor prefers splits like the page’s past: draining chunks out of , against the prior’s and .
- The Gamma factor charges each draining untouched chunk for having lost nothing: the more of them drain, the lower the rate must be to explain their survival, and the less the losses that did happen fit.
- is the single-rate posterior: every chunk drains, and is the page’s whole exposure.
The prior replaces the test
The static-share draft makes a static share earn statements’ worth of log-likelihood; here the prior on does that, with a weight of its own. A page starts from the draining fraction of what it holds, 1 for fresh content, which the draft starts with no static share; the prior is , worth chunks, with half a chunk of each kind so that neither is ruled out. For fresh content, the weights of splits with static chunks start small, and grow only as the untouched chunks outlive what draining content would. Unlike the test, the prior does not decide between one share and two: the posterior keeps both, weighted, and the decision sees the mixture.
A drifting rate
Discounting all of the evidence, the class count with the rest, keeps the mixture’s form; it is an approximation, since the drift has no exact update here. The single-rate posterior’s discounting carries over to everything that bears on the rate: , the touched chunks’ exposure , and , which becomes the discounted age , the exposure of a byte live throughout; the prior’s and are discounted with them. With , the discounted is again the single-rate draft’s settled exposure, so the two models agree where every chunk drains. A touched chunk’s live bytes stay in the draining share for good, and the rate says how fast they drain now: if the chunk has since gone cold, the rate falls.
The count of touched chunks is discounted too, although a chunk’s class does not drift, so that it weighs against as much of the untouched chunks’ survival as the posterior remembers. The untouched chunks’ exposure is discounted, so a chunk that has outlived its page’s draining content by many epochs counts for only the last or so of them. Kept whole, the count of touched chunks would go on weighing, undiminished, against that shortened survival: a page whose draining chunks were touched long ago would go on counting them as evidence that its untouched chunks drain too, when their long survival says they do not. And “draining” lumps together content that drains at different rates: on the page of the static-share draft’s example, the fast share’s early losses would count, for good, as evidence that the untouched chunks drain, although they drain at a twenty-fifth of that rate if at all. Discounted, the class evidence fades with the rate evidence it belongs to, which in simulation costs less.
What a page keeps, and what a loss costs
A page keeps its discounted loss events, the touched chunks’ discounted exposure, the discounted count of touched chunks, the epoch of its last loss, the count and bytes of its untouched chunks, and the prior’s two class counts: 22 bytes; and each statement needs one bit, set at its first loss. The prior on the rate enters the discounted sums as pseudo-observations, as in the single-rate posterior; the prior on is the two class counts, and , a byte each in halves of a chunk, which a page keeps from its write. follows from the page’s epoch.
The fold learns a chunk’s first loss from a bit in its statement’s record.
The statement slab’s record counts a statement’s pins in 32 bits, which leaves room for one more.
When the fold supersedes part of a Ref’s payload whose bit is clear, it sets the bit, moves the chunk’s bytes, the extent of its fragment before the split, from the page’s untouched counts to its touched ones, and adds their exposure since the page’s write, , to the touched exposure.
At open, a Ref whose live fragments no longer cover its whole payload is touched; on a leaf, a statement’s first loss is its death, and no bit is needed.
Each loss recomputes the weights, work in the untouched chunks, some 30 terms on a data page at most and some 300 on a leaf; the heaviest few carry almost all the weight, and the rest can be dropped.
Deciding on a mixture
Every criterion is a sum over the mixture, with one Gamma posterior per split. With and :
- (a) . All components share the shape , so one table of serves every .
- (b) , where a term with nothing draining, , counts as ripe at any price.
- (c′) as with one rate, at the posterior means of the draining share and its rate, with the predictive of the losses that will suffer.
The index is the at which the criterion holds with equality, found by bisection, each step . Aging the rate’s scale between losses multiplies every by the same factor, which leaves the weights as they are and scales the index, so the ranking ages uniformly here too.
How it relates to the draft’s fit
The draft’s fit reads the page’s losses alone; the cure model also reads which chunks they came from, and which they did not. The fit asks how fast a page’s losses fall, and infers the draining share from the losses’ current rate; the untouched content enters only as a cap on it. The cure model knows the touched chunks drain without waiting for them to die, and asks, of every untouched chunk, how likely it is to drain, given that it has lost nothing in the epochs the posterior remembers, and given how the page’s other chunks behaved. So a page whose losses keep coming from a few chunks has evidence of a static share in all of its other chunks, even when its losses are few, which is the case the evaluation found the fit unable to see.
Checking in simulation
In simulation, the cure model’s posterior costs half of what the static-share draft’s fit does where chunks lose their bytes in parts, as a data page’s Refs do, and 3 to 30 % less where they die whole; the single-rate posterior costs a little less than its draft; the file’s empirical prior beats every fixed start; and how (a), (b), and (c′) read a posterior matters less than the posterior itself.
tools/simulate-ripeness.py compare --set bayes runs the eight scenarios of the static-share draft’s simulation, with its measure: the excess cost of cleaning each page by an estimate, over cleaning it once its true index reaches .
Its pages hold chunks, which either die whole, as statements on a leaf do, or lose their bytes in pieces, each piece dying at its chunk’s rate, as a Ref’s payload loses the parts that writes supersede; the dispersion is that of the pieces, as the fold would measure it, and the tested fit counts its test in loss events too.
It runs 400 pages a scenario rather than 800, since the mixture is slower, with , chunks on the draining fraction, (c) for one rate per page only, over the posterior mean, and the drafts’ floor as a cap on the index rather than as a background rate.
The first two tables start each page as the drafts do, from its scenario’s rate, at a weight of epochs; the third compares that with the learned priors.
The summed excess cost of the eight scenarios:
| chunks of | losses | the single-rate draft | posterior mean | (a) | (b) | (c) | (c′) |
|---|---|---|---|---|---|---|---|
| 16 to 64 bytes | whole | 27.4 % | 27.0 % | 26.3 % | 26.0 % | 46.8 % | 27.5 % |
| 32 to 256 bytes | whole | 46.3 % | 44.3 % | 44.1 % | 44.8 % | 44.6 % | 44.3 % |
| 32 to 256 bytes | pieces of 32 bytes | 27.2 % | 26.7 % | 26.0 % | 25.3 % | 58.1 % | 27.3 % |
| 256 to 1024 bytes | whole | 112.8 % | 111.8 % | 113.7 % | 117.3 % | 111.6 % | not run |
| 256 to 1024 bytes | pieces of 64 bytes | 30.6 % | 29.8 % | 29.3 % | 29.2 % | 40.4 % | 29.9 % |
| chunks of | losses | the static-share draft’s tested fit | cure model, posterior means | (a) | (b) | (c′) |
|---|---|---|---|---|---|---|
| 16 to 64 bytes | whole | 27.4 % | 21.5 % | 19.6 % | 19.3 % | 21.6 % |
| 32 to 256 bytes | whole | 45.0 % | 40.4 % | 40.1 % | 40.0 % | 40.3 % |
| 32 to 256 bytes | pieces of 32 bytes | 24.3 % | 12.7 % | 11.8 % | 11.5 % | 12.8 % |
| 256 to 1024 bytes | whole | 109.3 % | 106.0 % | 106.2 % | 109.6 % | not run |
| 256 to 1024 bytes | pieces of 64 bytes | 30.3 % | 15.7 % | 14.5 % | 15.1 % | 15.6 % |
The pages are the same for every estimator, but a difference of a point or so in a sum is within what a different draw of pages moves.
- Where chunks lose their bytes in parts, the cure model sees a static share almost exactly. With chunks of 32 to 256 bytes losing 32 at a time, it costs 0.1 % on the page with a static share, against the tested fit’s 6.4 % and the single-rate draft’s 9.4 %, and 1.3 to 2.1 % on the page of the draft’s example, against 7.1 %. A chunk’s first loss shows that it drains, long before it dies, so the chunks that never lose anything stand out as static within a few epochs.
- Where chunks die whole, the cure model still gains, 40 % against the tested fit’s 45 %: some 12 points on the pages with a static share, from the untouched chunks that outlive the draining content, less some 5 on the pages that drain as one share, where the fit’s test keeps out static shares that are not there.
- With one rate per page, the posterior costs about what the draft does, a point or two less, since its mean is the draft’s estimate; what it adds, the certainty, changes little in the decisions.
- Partial losses make every estimate better, since they are more events: the single-rate draft’s excess cost falls from 46 % to 27 %, and the cure model’s from 40 % to 12 %.
- (a) and (b) differ little from the posterior mean, and from each other, except on pages of a few large chunks that die whole, where (b) costs 3 to 4 points more than (a). They make uncertain pages riper, as derived above, which gains a little on pages with a static share and loses a little on pages that drain slowly as one share.
- (c) is too cautious wherever losses come in many small events: with chunks losing 32 bytes at a time, it costs 58 % against the posterior mean’s 27 %, since it guards against as many further losses as the page has pieces. It gains only on pages that drain slowly as one share, 0.7 % against 1.1 % on the page draining at 0.01.
- (c′) costs what the posterior mean does, up to half a point more, as derived above: the predictive it weighs further losses by comes from the posterior it would have to distrust.
- A lighter prior pays: with , as heavy as the single-rate draft’s start, the single-rate posterior costs 30.5 % against 26.7 % with chunks losing 32 bytes at a time, most of it on the page whose start is wrong, where a heavy prior holds on to the wrong rate while the page shrinks; the cure model costs 14.3 to 15.4 % against 11.5 to 12.7 %.
- Discounting the class count pays: kept whole, it costs the cure model 14.1 to 17.3 % against 11.5 to 12.7 %, with chunks losing 32 bytes at a time.
Where a page’s prior comes from, in simulation
The file’s empirical prior beats every fixed start, and matching the sources’ posteriors does not, since a source that is sure of the wrong rate hands its certainty on. The empirical prior is learned, as derived above, from 400 fresh pages of each scenario but the seeded one, drawn apart from the pages it then starts, over their first 10 epochs; every page but the seeded ones starts from it, whatever its scenario’s rate. The moment-matched prior takes each scenario’s rates as its sources’, each source a page at fill 0.5 whose posterior has settled, and so rests on as many events as such a page would have. With chunks of 32 to 256 bytes:
| the rate’s prior | losses | posterior mean | (a) | (c′) | cure model, posterior means | (a) | (c′) |
|---|---|---|---|---|---|---|---|
| the scenario’s rate, | whole | 44.3 % | 44.1 % | 44.3 % | 40.4 % | 40.1 % | 40.3 % |
| moment-matched to the sources | whole | 46.4 % | 46.3 % | 46.4 % | 42.2 % | 41.6 % | 42.1 % |
| the file’s empirical prior | whole | 43.3 % | 43.1 % | 43.3 % | 39.1 % | 37.9 % | 39.0 % |
| the scenario’s rate, | pieces of 32 bytes | 26.7 % | 26.0 % | 27.3 % | 12.7 % | 11.8 % | 12.8 % |
| moment-matched to the sources | pieces of 32 bytes | 26.4 % | 25.6 % | 27.0 % | 12.8 % | 12.0 % | 12.9 % |
| the file’s empirical prior | pieces of 32 bytes | 25.2 % | 24.5 % | 25.8 % | 11.6 % | 10.9 % | 11.8 % |
- The empirical prior is weak, and that is why it wins. It comes out at a mean rate of 0.045 per epoch, resting on 0.8 of an event, since the scenarios’ fresh pages drain at rates from 0.002 to 0.5: each page’s own losses soon decide. It gains most on the page whose start is wrong, 0.5 % against 1.2 % with whole chunks, and costs nothing on the pages whose start is right, although it ignores that start.
- The moment-matched prior gains a little on pages mixed from sources that drain differently, a few tenths of a point on the two mixed pages, since it starts them unsure, but loses on the page whose source is sure of the wrong rate, 3.8 % against 1.2 % with whole chunks. Moved content, being colder than its source, is that case more often than not, as the open questions note, so this draft starts moved content from the empirical prior too, until the sources’ rates are corrected for what their content’s survival says.
What would change
In either draft, the estimate becomes a posterior, the index is computed from it by (a), and every constant the estimate had becomes a parameter of the prior.
- “Estimating how fast a page still drains” would keep a posterior: with one rate per page, the Gamma posterior’s two parameters in place of
rho; with a static share, the discounted loss events and exposure, the touched and untouched chunks’ counts, and the class counts in place of the fit’s sums, and the mixture in place of the fit and its test. - The page table would keep a
Drainof 12 bytes with one rate per page, against the single-rate draft’s 8, or 22 with a static share, against the static-share draft’s 18; with a static share, each statement’s record would also give a bit to mark its first loss. - The fold would keep two running averages per page kind, of the sizes of the ranges it supersedes and of their squares, for the dispersion , and five running sums over the pages it has watched through their first epochs, for the empirical prior.
- A new page would start from the file’s empirical prior, where the drafts start it from a byte-weighted mean rate with a fixed weight; its moved content would start from its sources’ posteriors, moment-matched, only once those are corrected for moved content being colder than its source.
- Ranking would compute a page’s index by (a) at each of its losses, from a table of computed once, and age it between losses as the drafts do; (b) needs no table, and cost a few points more in simulation only on pages of a few large chunks that die whole.
- Bytes that consolidation moves out of a page would lower its live bytes without counting as losses; the posterior’s evidence on the rate stays, and with a static share, a chunk moved out leaves the page’s touched or untouched counts, whichever held it.
- The constants would all become the prior’s:
| the drafts’ constant | becomes |
|---|---|
| the forgetting rate | the drift of the prior over the rate’s path, |
| the starting estimate, and its weight of epochs or | learned: for fresh content, the file’s empirical prior; for moved content, its sources’ posteriors |
| the static-share test’s | the weight of the prior on the draining fraction, in chunks |
| the floor | a background rate that the model asserts for all content |
Open questions
- Moved content is colder than its source. The survivors of a cleaned page outlived what died around them, so they drain slower than the page they came from, whose posterior they bring; the moment-matched prior overstates their rate, if by less as the source’s own evidence is weaker. Discounting a source’s rate by what its survival says about it would correct that.
- A starting prior’s weight is exposure, fixed in byte-epochs. On a page that drains fast, and shrinks, a strong start outweighs the page’s own losses for longer than the drafts’ averages of fractions let it; a learned prior is strong only where the file’s pages, or a page’s sources, agree.
- Chunks of unequal size. The mixture takes the untouched chunks at their mean size; the exact posterior weighs each subset of them by its own sizes, which a page of a few large chunks and many small ones would notice.
- What a loss event is. The dispersion treats every superseded range as one event, but one write that supersedes ranges on several pages, or several ranges of one page, is arguably one event; which grouping calibrates the posterior best is a question for measurement.
- Pooling evidence across pages, beyond the start. The empirical prior pools the file’s pages once, at a page’s start; the pages one flush wrote hold content the application wrote together, and a hierarchical prior, with the rates of one flush’s pages drawn around a rate shared by them, would go on lending each page the others’ losses.
- A drift that fits the file. A page’s next loss can make a ripe page unripe, so cleaning at the first ripe epoch cleans early; (c), which guards against every loss the page could still suffer, waits too long, and (c′), which weighs each by its predictive probability, does nothing, since the predictive trusts the posterior’s dip. The dip comes from the prior’s drift, which forgets a page’s losses at whether its rate changes or not. The drift could be learned from the file as the prior’s other parameters are, for instance by how well each page’s posterior predicts its next losses, and a slower drift for pages whose losses stay steady would dip less.
- Moved content’s classes. Chunks moved from a source where they had been touched could arrive known to drain, and the draining fraction’s prior could come from the sources’ mixtures as the rate’s does, rather than from their shares with a fixed weight.
- Epochs, not time. The model counts rates per epoch, as the drafts do, and so shares their open question about the clock.