When it does not fit

A span the queries do not see

A rule for dividing a levelled store's range-filter memory by its levels' sizes, with a floor of half a bit a key, came within five points of the division fitted to the store's own queries at every budget from one bit up — but at half a bit the shuffled and the clustered store wanted opposite divisions of identically sized levels. A level's fences, its first and last keys, say how much of the key space it spans, and a clustered level spans little. Scaling each level's bits by that span was predicted to close the half-bit gap and change nothing above. It changes nothing at half a bit — where the floor is the whole budget, so there is nothing left to scale — and from one bit up it puts the clustered store 30 points behind the fitted division, where the floored rule was within one. A level holding one cluster spans 0.4% of the key space and meets 4.4% of the queries, because half of them start at a stored key: the fences measure the key space, and the queries are aimed at the keys.

A levelled store keeps its keys in sorted levels, each about four times the size of the one above it, and a range query reads every level that might hold a key in its range. The filter each run carries put a range filter in front of each level, so a query can skip a level the filter rules out, and the question since has been how to divide a fixed memory among the filters. A division chosen before the queries arrive found a rule that reads only the levels’ sizes: give a level more bits a key the smaller it is relative to the deepest, δ\delta more for every factor of four. On the full store it matched the division fitted to the store’s own queries.

The sizes a store passes through ran the rule through the fill and found it rounded the deepest level to no filter at all whenever that level was not quite most of the store, and a floor under every level repaired that with a floor of half a bit a key: from one bit a key up the floored rule came within five points of the fitted division at every checkpoint on both arrival orders, the shuffled store and the clustered one, where keys arrive a cluster at a time. At half a bit a key it did not. There the shuffled store lost 35 points of a perfect filter’s saving to the fitted division under the floor and the clustered store lost 26 without it, and at half a bit the two stores wanted opposite divisions of levels whose sizes were identical. No rule that reads sizes alone could be right on both.

That essay’s closing section named what the sizes leave out. A level filled a cluster at a time spans a few clusters of the key space, and its fences — its first and last keys, which a store knows for nothing when it writes the level — rule it out of every query that falls outside them; a shuffled level spans everything and is ruled out by nothing. It proposed scaling each level’s bits by the share of the key space its fences span, before the snap to the grid of bit sizes and before the floor, so that a level most queries skip gets fewer bits and one every query reaches gets more. The prediction was that at half a bit a key this rule would match the fitted division within five points at every checkpoint on both orders, and that at a bit and above it would change nothing, since every shuffled level spans the whole key space and the floor already decides the clustered one. The risk named was the clustered store’s deepest level, which spans every cluster once the fill is complete.

A span, scaled in

The store, the queries and the charges are the earlier essays’. Sixteen clusters of keys in a 32-bit key space, inserted in a shuffled order or one cluster at a time, measured at six points of the fill; range queries of four lengths, half starting at a uniformly random point and half at a stored key; a level read for a query costs one transfer plus one for every block of keys the range covers in it, and a filter that rules the level out saves the read. A division is scored by the share of a perfect filter’s saving it captures, measured on queries other than those the fitted division was chosen on.

The span rule takes the floored size rule’s target for each level — a base plus δ=4\delta = 4 bits for every factor of four a level is smaller than the deepest — multiplies it by the level’s span, the distance between its fences over the whole key space, then snaps it down to the grid of sizes the filters come in and raises it to the floor of half a bit. The base is searched, as before, for the largest that fits the budget.

Nothing at half a bit, and harm above it

Scaling each level's bits by the span of its fences changes nothing at half a bit a key — 34.8 points behind on the shuffled store, as the floored rule, 9.1 points behind on the clustered store, as the floored rule — and from one bit up it puts the clustered store 29.6 points behind the fitted division where the floored rule was 0.9The worst gap, in points of the perfect filter's saving, between the fitted division of a levelled store's range-filter memory and two rules, over six checkpoints of the fill: the size rule with a floor of half a bit a key, and the same with each level's bits scaled by the share of the key space its fences span. shuffled, 0.5 bits a key: span 34.8 at ¾ of the fill, floored 34.8 at ¾; shuffled, 1 bits a key: span 2.3 at full of the fill, floored 4.1 at ½; shuffled, 2 bits a key: span 4.1 at ¼ of the fill, floored 4.2 at ½; shuffled, 4 bits a key: span 4.1 at ¼ of the fill, floored 4.1 at ¼; clustered, 0.5 bits a key: span 9.1 at full of the fill, floored 9.1 at full; clustered, 1 bits a key: span 29.6 at full of the fill, floored 0.9 at ⅜; clustered, 2 bits a key: span 30.7 at ⅛ of the fill, floored 0.7 at ⅛; clustered, 4 bits a key: span 30.4 at ⅛ of the fill, floored 0.6 at ⅛.shuffled, 0.5 bits a key34.8 span34.8 flooredshuffled, 1 bits a key2.3 span4.1 flooredshuffled, 2 bits a key4.1 span4.2 flooredshuffled, 4 bits a key4.1 span4.1 flooredclustered, 0.5 bits a key9.1 span9.1 flooredclustered, 1 bits a key29.6 span0.9 flooredclustered, 2 bits a key30.7 span0.7 flooredclustered, 4 bits a key30.4 span0.6 flooredworst points behind the fitted division over the filltwo orders, four budgetssix checkpoints
Fig. 1 The worst gap, in points of a perfect filter’s saving, between the fitted division and each rule over six checkpoints of the fill, at budgets of half a bit to four bits a key, on the shuffled and the clustered store. Span-scaled rule, shuffled: 34.8, 2.3, 4.1, 4.1. Floored rule, shuffled: 34.8, 4.1, 4.2, 4.1. Span-scaled, clustered: 9.1, 29.6, 30.7, 30.4. Floored, clustered: 9.1, 0.9, 0.7, 0.6.

Scaling each level’s bits by the span of its fences changes nothing at half a bit a key — 34.8 points behind the fitted division on the shuffled store and 9.1 on the clustered one, as the floored rule — and from one bit up it puts the clustered store about 30 points behind, where the floored rule was within one. On the shuffled store it does no harm and a little good at one bit, 2.3 points behind rather than 4.1, because the shuffled levels’ spans are all alike and scaling them all by the same share changes only the base the budget search finds. On the clustered store it is the worst rule any of these essays has measured from one bit up.

The prediction was wrong on both halves, and the first half for a reason that needs no measurement at all.

The floor is the budget

At half a bit a key the floor is the budget: every level gets half a bit under both rules at every point of the fill, so a scale on the span has nothing to move; the fitted division on the shuffled store gives the deepest level nothing and the shallow levels several bits — 3/1/0, 8/0, 16/2/0, 8/4/0.5/0, 8/4/2/0, 16/6/0 — which no floor can reachThe shuffled store at half a bit a key: the bits a key each level is given, shallowest first, at six points of the fill, by the floored size rule (the same as the span rule at every point) and the fitted division, with the share of a perfect filter's saving each captures: ⅛: rules 0.5/0.5/0.5 (21.7), fitted 3/1/0 (40.5); ¼: rules 0.5/0.5 (38.4), fitted 8/0 (54.7); ⅜: rules 0.5/0.5/0.5 (33.0), fitted 16/2/0 (65.2); ½: rules 0.5/0.5/0.5/0.5 (34.7), fitted 8/4/0.5/0 (61.1); ¾: rules 0.5/0.5/0.5/0.5 (33.2), fitted 8/4/2/0 (68.0); full: rules 0.5/0.5/0.5 (37.6), fitted 16/6/0 (71.5).rules: bits a key per level · fitted division⅛ of the fill0.50.50.5310¼ of the fill0.50.580⅜ of the fill0.50.50.51620½ of the fill0.50.50.50.5840.50¾ of the fill0.50.50.50.58420full of the fill0.50.50.51660shuffled store, ½ bit a keylevels shallowest first
Fig. 2 The shuffled store at half a bit a key, six checkpoints of the fill: bits a key given to each level, shallowest first, by the floored size rule — which the span rule matches exactly at every point — and by the fitted division. The rules give every level half a bit. The fitted division: 3/1/0 at an eighth of the fill, 8/0 at a quarter, 16/2/0, 8/4/0.5/0, 8/4/2/0, and 16/6/0 on the full store.

At half a bit a key the floor is the budget: every level gets half a bit under both rules at every point of the fill, so a scale on the span has nothing to move; the fitted division on the shuffled store gives the deepest level nothing and the shallow levels several bits — 8/4/2/0 at three quarters of the fill, 16/6/0 on the full store — which no floor can reach. A floor of half a bit a key on every level spends half a bit a key on the whole store, which is the whole of a budget of half a bit. Whatever the rule does before the floor, the floor then raises every level to half a bit, and the result is the even split. The span rule’s scaling happens before the floor, as proposed, and is erased by it.

The fitted division at that budget does the opposite of a floor. It takes the deepest level’s share, most of the store’s keys, gives it no filter at all, and spends those bits on the small levels, eight or sixteen bits a key on a level of a few thousand keys. On the shuffled store that is worth 35 points: a range query reaches every level, the deepest level must be read anyway by most queries, and a filter on it at half a bit a key rules out almost nothing, while a filter of eight bits a key on a small level rules it out nearly every time. The floor was introduced to stop the size rule giving the deepest level nothing at larger budgets, where that was a mistake; at half a bit giving the deepest level nothing is the right answer, and the floor forbids it.

So the half-bit gap was never the span’s to close. It is a conflict between the floor and the budget, and a rule that kept the floor could not close it however it read the levels.

What a level’s fences span

Every shuffled level's fences span 0.82 of the key space at every point of the fill — all the clusters, from the first to the last — while the clustered store's levels span 0.004 to 0.82 when it is full: its small levels hold a cluster each, and its deepest spans all of themThe share of the 32-bit key space between each level's first and last key, at six points of the fill, for the shuffled and the clustered store: shuffled: ⅛ 0.815/0.816/0.816, ¼ 0.815/0.816, ⅜ 0.815/0.816/0.816, ½ 0.815/0.815/0.816/0.816, ¾ 0.815/0.815/0.816/0.816, full 0.815/0.815/0.816; clustered: ⅛ 0.006/0.006/0.256, ¼ 0.004/0.537, ⅜ 0.350/0.391/0.537, ½ 0.004/0.004/0.628/0.537, ¾ 0.004/0.004/0.161/0.782, full 0.004/0.498/0.816.00.2500.5000.7501point of the fillshare of the key space its fences span⅛¼⅜½¾fullshuffledclusteredone dot a levelsixteen clusters
Fig. 3 The share of the key space between each level’s first and last key, at six points of the fill, for the shuffled store and the clustered store, one dot a level. Every shuffled level spans 0.815 or 0.816 at every point. The clustered store’s levels range from 0.004 to 0.82; on the full store 0.004, 0.498 and 0.816.

Every shuffled level’s fences span 0.82 of the key space at every point of the fill — all the clusters, from the first to the last — while the clustered store’s levels span 0.004 to 0.82 when it is full: its small levels hold a cluster each, and its deepest spans all of them. The sixteen clusters lie across about four fifths of the 32-bit space, so 0.82 is the most any level can span, and every shuffled level, however small, holds keys from the first cluster and the last. In the clustered store a level written from the buffer while one cluster was arriving holds that cluster alone and spans four thousandths of the key space; a merge of several levels spans several clusters and whatever lies between them.

The risk the proposal named is on this plate: the clustered store’s deepest level spans 0.816 on the full store, as much as a shuffled level. But the rule’s damage at one bit is not on the deepest level. It is on the smallest.

The queries are aimed at the keys

What the fences measure is not what the queries meet: on the clustered store at ¾ of the fill, a level holding one cluster spans 0.004 of the key space but holds 8.3% of the stored keys, and half the queries start at a stored key, so about 4.4% of queries can land inside it — 11 times its spanThe clustered store at ¾ of the fill, per level from the shallowest: its fences' share of the key space, the share of the store's keys inside its fences, and the share of queries that can begin inside them, half the queries starting uniformly and half at a stored key. level 1 (8192 keys): span 0.004, keys 0.083, queries 0.044; level 2 (40960 keys): span 0.004, keys 0.083, queries 0.044; level 3 (81920 keys): span 0.161, keys 0.250, queries 0.206; level 4 (655360 keys): span 0.782, keys 1.000, queries 0.891.level 1, 8,192 keys0.004 span0.044 querieslevel 2, 40,960 keys0.004 span0.044 querieslevel 3, 81,920 keys0.161 span0.206 querieslevel 4, 655,360 keys0.782 span0.891 queriesupper bar: fences' span · lower: share of queries that can land insideclustered storeshares of the whole
Fig. 4 The clustered store at three quarters of the fill, per level from the shallowest: its fences’ share of the key space, and the share of queries that can begin inside them, with half the queries starting uniformly and half at a stored key. Two one-cluster levels: span 0.004, queries 0.044, holding 8.3% of the stored keys each. A level of three clusters: span 0.161, queries 0.206. The deepest: span 0.782, queries 0.891.

What the fences measure is not what the queries meet: on the clustered store at three quarters of the fill, a level holding one cluster spans 0.4% of the key space but holds 8.3% of the stored keys, and half the queries start at a stored key, so about 4.4% of queries can land inside it — eleven times its span. The workload these essays have used, like most real ones, is aimed at the data: half its range queries begin at a key the store holds. A level holding one cluster is therefore asked about in proportion to its share of the keys as much as to its share of the key space, and its share of the keys is twenty times its span. Every one of those queries lands in a dense cluster where the range almost always holds a key of that level — the reason its filter can only save by being precise.

The span rule reads the span alone, scales the one-cluster level’s target down to a two-hundred-and-fiftieth of what the size rule gave it, raises it to the floor, and spends the difference on the level that spans half the key space. The fitted division does the reverse. On the full clustered store at one bit a key it gives the shallowest level, one cluster, twelve bits a key, the next eight, and the deepest half a bit.

One bit a key, through the fill

On the clustered store at 1 bit a key the span rule captures 70.2% of a perfect filter's saving on the full store where the fitted division captures 99.8% and the floored size rule 99.8%: it starves the one-cluster levels the queries are aimed at and gives their bits to the deepestThe clustered store at 1 bits a key, six checkpoints of the fill: the share of a perfect filter's saving captured by the fitted division, the size rule with a floor of half a bit, and the span-scaled rule. ⅛: fitted 94.5 (6/1/0.5), floored 94.5 (6/1/0.5), span 66.2 (0.5/0.5/1); ¼: fitted 99.3 (8/0.5), floored 99.3 (8/0.5), span 79.8 (0.5/1); ⅜: fitted 99.9 (16/1/0.5), floored 99.0 (8/3/0.5), span 98.0 (4/2/0.5); ½: fitted 99.4 (12/2/1/0.5), floored 98.6 (8/6/0.5/0.5), span 82.8 (0.5/0.5/2/0.5); ¾: fitted 99.6 (12/1/2/0.5), floored 99.4 (8/4/2/0.5), span 84.4 (0.5/0.5/1/1); full: fitted 99.8 (12/8/0.5), floored 99.8 (16/8/0.5), span 70.2 (0.5/4/0.5). Bits a key per level, shallowest first.00.2500.5000.7501point of the fillshare of a perfect filter's saving⅛¼⅜½¾fullfloored size rulefitted divisionspan-scaled ruleclustered, 1 bit a keyhigher is better
Fig. 5 The clustered store at one bit a key, six checkpoints of the fill: the share of a perfect filter’s saving captured by the fitted division, the floored size rule and the span-scaled rule. Fitted: 94.5, 99.3, 99.9, 99.4, 99.6, 99.8. Floored: 94.5, 99.3, 99.0, 98.6, 99.4, 99.8. Span: 66.2, 79.8, 98.0, 82.8, 84.4, 70.2. On the full store the fitted division gives 12/8/0.5 bits a key, the span rule 0.5/4/0.5.

On the clustered store at one bit a key the span rule captures 70.2% of a perfect filter’s saving on the full store where the fitted division and the floored size rule both capture 99.8%: it starves the one-cluster levels the queries are aimed at and gives their bits to the deepest. At every checkpoint but one the floored size rule is within a point of the fitted division, and the span rule is fifteen to thirty points behind. The exception, three eighths of the way through the fill, is the one checkpoint where the clustered store’s shallowest level spans several clusters, 0.35 of the key space, and the span rule’s scale is mild enough to do little harm.

That is the measure of how well the size rule had already done. The earlier essays found the floored rule within five points everywhere from one bit up, and on the clustered store within one; whatever distinguishes the two stores at those budgets, the sizes had already captured it, because a level’s size and the queries aimed at it move together when queries are aimed at keys.

What separates the two stores

The closing question was whether what separates the two stores is something a level can measure about itself, or only something the queries reveal. The fences are something a level measures about itself, and they measure the wrong thing for this workload: how much of the key space a level covers, when the queries are distributed by keys, not by key space. A level’s share of the keys it holds, which is its size, was already the better measure, and the span adds an error to it.

The small levels’ share of a range filter and one bit a key, divided both found that the small levels deserve more bits a key than their size alone suggests, and the fitted divisions here say so again: twelve bits a key on a one-cluster level of eight thousand keys. A rule that read the queries’ landing points — how often each level’s filter was consulted, and how often it could have saved a read — would see what the span cannot. One length for the gaps and the clusters found the same limit for a filter’s own design: what it should be tuned to is where the queries fall, which only the queries say.

What a store could read instead

A store can know more about a level than its fences, and still for nothing. The filter rebuilt with every write builds each level’s filter when the level is written, and at that moment the store holds every key of the level in order: it can count, in passing, how many distinct clusters the level touches and how many keys sit in each, or keep a coarse histogram of its keys over the key space. Weighted by the store’s own key distribution, such a histogram would give a level’s share of the queries a key-aimed workload sends it — which, on this workload, is about half its span plus half its share of the store’s keys, the number the reach plate computed.

That number would have told the rule what the fitted division already knew: the one-cluster levels are asked about far more often than their span suggests, a twelfth of the keys meeting a twelfth of the queries aimed at keys. Whether a rule built on it would beat the floored size rule is another matter. On this store the size rule is within a point of the fitted division from one bit up on the clustered store, so there is almost nothing left to win there, and on the shuffled store every level’s share of the queries is the same. The place a better measure could help is half a bit a key, and there the floor, not the measure, is what stands in the way.

What the store does not show

One workload. Half the queries start at a stored key and half anywhere. A workload of uniform range queries over the key space would make the span the right measure, and on it the span rule might do what was proposed; that workload was not run, and it is the obvious control.

Sixteen clusters. The clustered store’s levels hold one, a few or all of sixteen clusters. Many more, smaller clusters would make the spans of small levels larger relative to their key shares, and the rule’s error smaller.

A floor kept. The span rule was run with the floor, as proposed. Without the floor at half a bit, the span would have something to move; but the floor’s removal is what the fitted division wants at that budget, and the span would not be what decided it.

Still open: a floor that steps aside at half a bit

The half-bit gap is a conflict between two rules that are each right somewhere. The floor is right from one bit up, where giving the deepest level nothing was the size rule’s mistake; at half a bit the fitted division gives the deepest level nothing on the shuffled store, and the floor forbids it. A rule could keep the floor only while the budget can pay for it and leave room above it: apply the floor of half a bit only when the budget is at least twice the floor, and otherwise let the size rule divide the budget freely, deepest level included.

The measurement that follows runs the size rule with that conditional floor at budgets of half a bit, three quarters and one, on both orders through the fill. The prediction is that at half a bit on the shuffled store the rule then gives the deepest level nothing and comes within ten points of the fitted division, while the clustered store, whose fitted division at half a bit is the even split at four of the six checkpoints, loses the 9 points it loses now to about 26, as the unfloored rule did — so that no single setting of the condition is right for both stores at that budget, and the gap at half a bit is a gap between workloads rather than between rules. It could fail if the unfloored division at half a bit on the shuffled store gives the bits to the wrong small level. The question is whether a budget of half a bit a key has a division that suits both stores at all, or whether below a bit a key a store must read its queries before it can choose.

Named alongside this one

Essays reaching for the same objects. Nobody chose these; they are what the concept index makes visible.

The objects this essay names

Each one links to every other essay that touches it.

Bloom filterDesign parameterLsm treePer levelPredictionSpace accounting