When it does not fit

A reach that follows the stream

A full B+-tree leaf that passes keys along its siblings wants a short reach on random insertion and the whole parent on a nearly ordered stream, and a tree is never told which it is receiving. Let the reach double after every 64 overflows whose walks averaged two siblings or less and halve otherwise, and it finds the whole parent on every ordered stream. On random keys it lands on the fixed reaches' own frontier. On a stream that turns from random to ordered halfway it beats every fixed reach, by 57 leaves at the same writes. It notices a turn to random in 62 insertions and a turn to order in 779. Below a target of 1.75 siblings it thrashes on ordered keys.

A key passed along the row gave a full B±tree leaf one parameter: how many siblings away, in either direction, it may look for room before it splits. The two kinds of stream it measured asked for opposite settings. On random insertion the reach is expensive, and more so the further it goes: a reach of four writes 3.01 pages a key for leaves 92.6% full, and the whole parent writes 17.07 for 98.9%. On a nearly ascending stream it is almost free: the whole parent in reach writes 2.36 pages a key against the adjacent rule’s 2.25, for 14% fewer leaves. The fixed reach that suits one stream is wrong for the other by a wide margin.

A tree is not told which stream it is receiving, and a run is a property of the input is the page on why “nearly sorted” is a measurement rather than a label a caller can supply. That essay’s closing section pointed out that the tree can nonetheless read it off its own behaviour. Every redistribution is a walk of some number of siblings, and the walks already made say whether room has been near or far. A run of short walks means the neighbourhood has space; a run of long ones means it is full. It proposed a reach that follows those walks, predicted that it would track the better fixed reach on each pure stream within a few per cent and beat both fixed reaches on a stream that changes, and named the number to watch: how many insertions it takes to notice the change.

A reach with one rule

The rule is as small as it can be. The tree counts overflows — insertions that find their leaf already full. Every 64 overflows it looks at the redistributions among them and takes the mean distance their keys were passed. If that mean is at or below a target, the reach doubles, up to the whole parent of 64. If it is above, the reach halves, down to one. An overflow that ends in a split has no walk and does not enter the mean, though it counts towards the 64. The reach starts at one.

That is the whole of it: one number, the target, and a window of 64. Everything else — the trees of 131,072 keys, leaves of 64 keys and a fan-out of 64, the pages counted as every leaf and parent an insertion writes — is exactly the arrangement of the earlier essay, so every fixed-reach point below is one of its points and can be read against its plates. Every tree is checked for key order and for separators that name the first key of the subtree after them.

The target has a natural reading in the currency the earlier page used. A redistribution that walks dd siblings writes dd leaves and one parent, and a split writes two or three pages. A walk of two costs about what a split does. So a target of two says: keep widening while the tree’s typical redistribution costs no more than the split it replaces, and back off when looking further has begun to cost more than giving up would.

On the frontier, wherever the target puts it

On random insertion there is no single best reach. There is a frontier: fewer leaves for more pages written, and a reader’s ratio of scans to insertions picks the point. So the first test is not whether the adaptive rule hits some particular reach, but whether it lands on that frontier at all or somewhere inside it.

On random insertion a reach that follows its walks lands on the fixed reaches' frontier wherever its target puts it — target 2 gives 2,220 leaves at 3.06 pages a key, beside reach 4's 2,211 at 3.01Leaves in the finished tree against pages written per key, for 131,072 keys inserted in random order. Fixed reaches: 1, 2,429 leaves at 1.59; 2, 2,313 leaves at 2.15; 4, 2,211 leaves at 3.01; 8, 2,148 leaves at 4.43; 16, 2,107 leaves at 6.98; 32, 2,077 leaves at 11.30; 64, 2,071 leaves at 17.07. The reach that doubles after 64 overflows whose walks averaged at most the target and halves otherwise: target 1, 2,386 leaves at 1.69, -0.9% from the fixed frontier at that cost; target 1.5, 2,294 leaves at 2.47, 0.8% from the fixed frontier at that cost; target 2, 2,220 leaves at 3.06, 0.5% from the fixed frontier at that cost; target 3, 2,165 leaves at 4.12, 0.2% from the fixed frontier at that cost; target 4, 2,122 leaves at 5.22, -0.6% from the fixed frontier at that cost; target 8, 2,085 leaves at 8.92, -0.4% from the fixed frontier at that cost.2122232451015pages written per key insertedleaves in the finished tree, in hundreds1241664target 1target 2target 8fixed reach (digits:siblings)reach following the walks131,072 keys, leaves of 64, fan-out 64window of 64 overflows
Fig. 1 Leaves in the finished tree against pages written per key, for 131,072 keys in random order. Fixed reaches, from 1 to 64 siblings: 2,429 leaves at 1.59 pages a key through 2,211 at 3.01 (reach 4) to 2,071 at 17.07. The reach following its walks at targets 1, 1.5, 2, 3, 4 and 8: 2,386 at 1.69, 2,294 at 2.47, 2,220 at 3.06, 2,165 at 4.12, 2,122 at 5.22 and 2,085 at 8.92 — each within 0.9% of the fixed frontier’s leaves at the same cost.

Every target lands on the frontier. Target two ends with 2,220 leaves at 3.06 pages a key, beside a fixed reach of four at 2,211 and 3.01. Target three sits between reaches four and eight, target eight between sixteen and thirty-two. The largest departure from the frontier at the same cost is 0.9%, and three of the six are on the favourable side of it. The adaptive rule is not choosing a reach at random and averaging badly. It is moving along the same curve the fixed reaches trace, to a point its target sets.

That is a stronger result than it first looks. Across a random stream the reach does not settle. With target two it changes 1,336 times over 131,072 insertions and spends 74% of them at a reach of four, eight or sixteen, 9% at the whole parent and the rest below four. A rule that oscillated between a cheap reach and an expensive one could easily have ended with the costs of the expensive one and the leaves of the cheap one. It does not, because the walks it measures are the cost it pays. When long walks make a window expensive, the next window is narrower.

The target is therefore the ratio the earlier page declined to set — the same kind of ratio one dial between two structures found choosing between a B-tree and a log-structured store — written as a quantity the tree can measure: how far it is willing to pass a key, on average, to avoid a split. The sibling a full leaf asks first found that the rule databases use is one fixed setting of this trade that suits one stream. Here the trade has a knob, and the knob’s position is a walk length rather than a reach.

Every ordered stream finds the whole parent

At a target of two siblings the adaptive reach ends every ordered stream with the fewest leaves any reach gives — 2,096 on the nearly ascending one — and random insertion 2,220 at 3.06 pages a keyLeaves in the finished tree and pages written per key, for the adjacent-sibling rule (reach 1), for the fixed reach with the fewest leaves, and for the reach that follows its walks at a target of two. Random: reach 1 2,429 at 1.59; reach 64 2,071 at 17.07; adaptive 2,220 at 3.06, ending at a reach of 8. Ascending: reach 1 3,048 at 2.05; reach 2 2,048 at 2.69; adaptive 2,048 at 2.69, ending at a reach of 64. Descending: reach 1 3,048 at 2.05; reach 2 2,048 at 2.69; adaptive 2,048 at 2.69, ending at a reach of 64. Ascending, 1% late: reach 1 2,433 at 2.25; reach 32 2,095 at 2.37; adaptive 2,096 at 2.36, ending at a reach of 64.random2,429 · 1.592,071 · 17.07 · reach 642,220 · 3.06ascending3,048 · 2.052,048 · 2.69 · reach 22,048 · 2.69descending3,048 · 2.052,048 · 2.69 · reach 22,048 · 2.69ascending, 1% late2,433 · 2.252,095 · 2.37 · reach 322,096 · 2.36reach 1fewest leaves of any fixed reachfollowing the walksleaves · pages a keytarget 2, window 64
Fig. 2 For each pure stream, leaves and pages per key under three rules: reach 1, the fixed reach with the fewest leaves, and the reach following its walks at a target of two. Random: 2,429 at 1.59, reach 64’s 2,071 at 17.07, adaptive 2,220 at 3.06. Ascending and descending: 3,048 at 2.05, reach 2’s 2,048 at 2.69, adaptive 2,048 at 2.69. Ascending with 1% late: 2,433 at 2.25, reach 32’s 2,095 at 2.37, adaptive 2,096 at 2.36.

On the three ordered streams the prediction holds exactly. Ascending and descending insertion end with 2,048 leaves, every leaf full, at 2.69 pages a key — the same tree a fixed reach of two builds. On the nearly ascending stream with one key in a hundred late, the adaptive tree ends with 2,096 leaves at 2.36 pages a key. A fixed reach of 32 gives 2,095 at 2.37 and the whole parent 2,096 at 2.36. In both cases the adaptive rule reaches the whole parent 861 insertions from the start and stays there, changing its reach 9 times on ascending keys and 49 on the late stream.

That is what the walks say. On an ordered stream the nearest room is almost always one sibling away, so every window’s mean walk sits below two and the reach keeps doubling until it hits the parent’s width. It never needs the width. The earlier essay’s walk histogram had 88% of redistributions on the late stream stopping at the first sibling. But the reach is free to be wide because walks stay short whatever it is, and the rare late key that needs to travel far is allowed to.

A stream that changes halfway

The case the prediction said the adaptive rule should win is a stream whose order changes. Two are measured. In one, the first 65,536 keys arrive in random order and the next 65,536, all larger, arrive ascending with one in a hundred late. In the other, the first half arrives nearly ascending and the second half is random keys interleaved among the first half’s, so that the random keys land in the leaves the ordered half filled.

On a stream that turns from random to nearly ascending halfway, the adaptive reach ends with 2,162 leaves at 2.75 pages a key — 57 fewer than any fixed reach gives at that costLeaves against pages written per key for 131,072 keys arriving as random, then ascending with 1% late. Fixed reaches: 1, 2,465 at 1.90; 2, 2,308 at 2.26; 4, 2,224 at 2.69; 8, 2,175 at 3.40; 16, 2,120 at 4.72; 32, 2,084 at 6.78; 64, 2,086 at 9.63. The reach following its walks at a target of two: 2,162 leaves at 2.75 pages a key, against 2,219 on the fixed frontier at the same cost.212223242468pages written per key insertedleaves in the finished tree, in hundreds1241664target 2fixed reach (digits:siblings)reach following the walksrandom, then ascending with 1% latetarget 2, window 64
Fig. 3 Random, then nearly ascending: fixed reaches from 2,465 leaves at 1.90 pages a key (reach 1) through 2,224 at 2.69 (reach 4) and 2,175 at 3.40 (reach 8) to 2,086 at 9.63 (reach 64). The reach following its walks ends with 2,162 leaves at 2.75 pages a key, 57 fewer than the fixed frontier gives at that cost — fewer leaves than reach 8 at about the cost of reach 4.

On the stream that turns from random to ordered, the adaptive rule beats every fixed reach. It ends with 2,162 leaves at 2.75 pages a key. A fixed reach of four costs 2.69 pages and ends with 2,224 leaves; a fixed reach of eight gets 2,175 leaves for 3.40 pages. The adaptive tree has fewer leaves than reach eight at about the cost of reach four, 57 leaves under the frontier at its cost. No fixed setting does that, because no fixed setting is short on the random half and wide on the ordered half.

The other direction does not go the same way.

On a stream that turns from nearly ascending to random halfway, the adaptive reach ends with 2,223 leaves at 2.70 pages a key — 16 more than the fixed reaches give at that costLeaves against pages written per key for 131,072 keys arriving as ascending with 1% late, then random. Fixed reaches: 1, 2,419 at 1.88; 2, 2,292 at 2.22; 4, 2,211 at 2.65; 8, 2,148 at 3.39; 16, 2,102 at 4.64; 32, 2,083 at 6.87; 64, 2,091 at 9.81. The reach following its walks at a target of two: 2,223 leaves at 2.70 pages a key, against 2,207 on the fixed frontier at the same cost.212223242468pages written per key insertedleaves in the finished tree, in hundreds1241664target 2fixed reach (digits:siblings)reach following the walksascending with 1% late, then randomtarget 2, window 64
Fig. 4 Nearly ascending, then random keys among the first half’s: fixed reaches from 2,419 leaves at 1.88 pages a key through 2,211 at 2.65 (reach 4) to 2,091 at 9.81 (reach 64). The reach following its walks ends with 2,223 leaves at 2.70 pages a key, 16 more than the fixed frontier gives at that cost.

On the stream that turns from ordered to random, the adaptive tree ends 16 leaves inside the frontier — 0.7% more leaves than a fixed reach at the same cost. The first half costs it nothing: it runs at the whole parent and fills the leaves as the late stream always does. The second half is where the loss is. The random keys land in leaves the ordered half filled completely, so there is no room anywhere nearby, and the first window after the change finds long walks and halves. The reach has to come down from 64, and in the windows it takes to come down, every overflow walks far. The fixed reach of four never had that bill to pay.

So the prediction is half right. An adaptive reach beats both fixed ones when the change is towards order, because widening costs nothing on the side it widens into. When the change is away from order it pays a toll for having been wide, and a fixed small reach that was worse on the first half is marginally better overall. How large the toll is depends on how fast the reach comes down.

How long it takes to notice

Turned to random, the reach first halves 62 insertions after the change and is at four or less by 275; turned to order, it first reaches the whole parent after 779The adaptive reach, in siblings on a logarithmic scale, from 1,000 insertions before the change to 3,000 after, window of 64 overflows, target 2. Nearly ascending then random: its reach changes 672 times over the whole stream, first after the change at 62 insertions, down to four or less by 275. Random then nearly ascending: 681 changes over the stream, the reach first at 64 after 779 insertions. The dashed line is the change.141664ascending with 1% late, then random141664random, then ascending with 1% late-1,000the change+1,000+2,000+3,000insertions from the changereach, in siblingstarget 2, window 64dashed: the change
Fig. 5 The reach, in siblings, from 1,000 insertions before the change to 3,000 after, target two, window 64. Nearly ascending then random: the reach sits at 64, first halves 62 insertions after the change, and is at four or less by 275. Random then nearly ascending: the reach oscillates between two and thirty-two before the change and first reaches 64 after 779; it then stays at 64 for 98% of the second half.

The two directions are noticed at very different speeds, and the asymmetry has a plain cause. A turn to random is noticed in 62 insertions. The ordered half has filled its leaves, so the first random key to overflow walks a long way. Overflows come fast — every leaf is full — and one window of 64 overflows arrives within a few dozen insertions. Its mean walk is 12.9 siblings, and the reach halves. Three more windows bring it to four by 275 insertions after the change, and one more to two by 346.

A turn to order takes 779 insertions to reach the whole parent. The ordered keys go to new leaves at the right of the tree, where walks are short, and a window of 64 overflows passes in about ninety insertions, so four doublings from eight would take under four hundred. What slows it is the one key in a hundred that arrives late. A late key lands among leaves the ordered keys have already filled and walks a long way — one window after the change averages 6.4 siblings, a later one 14.4 — and each such window halves the reach. It takes three setbacks of that kind before a run of short-walk windows carries the reach to 64, at 779 insertions. From there it stays at the whole parent for 98% of the second half, dipping for a window whenever a late key walks far.

The asymmetry is the right way round for a rule of this kind. Being too wide on a random stream costs many pages per key; being too narrow on an ordered one costs a few leaves not yet filled, which later redistributions can still fill. A rule that backs off fast and widens slowly errs towards the cheaper mistake. Its window is still a real parameter. At a window of 16 overflows the turn to random is noticed in 22 insertions and the turn to order in 213, but the reach changes 2,700 times over the stream instead of 680. At 256 it takes 980 and 3,285 insertions, and the adaptive tree on the ordered-to-random stream ends 0.09 pages a key more expensive. Sixty-four was chosen before measuring and it is a reasonable middle, not a tuned one.

The floor under the target

The target is a walk length, and an ordered stream has a walk length of its own.

The target has a floor: below 1.75 siblings the ascending stream ends with 2,473 leaves and 1,236 changes of reach; from 1.75 up it ends with 2,048 and fewer than tenFor targets from 1 to 3 siblings, the ascending stream's leaves and number of reach changes, and the random stream's leaves and pages per key. Target 1: ascending 2,473 leaves, 1,236 changes; nearly ascending 2,282; random 2,386 at 1.69. Target 1.25: ascending 2,473 leaves, 1,236 changes; nearly ascending 2,192; random 2,339 at 2.04. Target 1.5: ascending 2,470 leaves, 1,237 changes; nearly ascending 2,116; random 2,294 at 2.47. Target 1.75: ascending 2,048 leaves, 9 changes; nearly ascending 2,096; random 2,230 at 2.74. Target 2: ascending 2,048 leaves, 9 changes; nearly ascending 2,096; random 2,220 at 3.06. Target 2.5: ascending 2,048 leaves, 7 changes; nearly ascending 2,096; random 2,179 at 3.66. Target 3: ascending 2,048 leaves, 7 changes; nearly ascending 2,096; random 2,165 at 4.12.target 12,473 · 1,236 changestarget 1.252,473 · 1,236 changestarget 1.52,470 · 1,237 changestarget 1.752,048 · 9 changestarget 22,048 · 9 changestarget 2.52,048 · 7 changestarget 32,048 · 7 changesleaves an ascending stream ends with, and how often the reach changedascending, 131,072 keyswindow 64
Fig. 6 Leaves an ascending stream ends with, and how many times the reach changed, at targets from 1 to 3 siblings, window 64. Targets 1, 1.25 and 1.5: 2,473, 2,473 and 2,470 leaves, about 1,237 changes each. Targets 1.75, 2, 2.5 and 3: 2,048 leaves, every leaf full, and 7 to 9 changes.

Below a target of 1.75 the ascending stream thrashes. It ends with 2,470 leaves where every other target gives 2,048, and its reach changes about 1,237 times. The mechanism is the ordered stream’s own geometry. Once the reach is two, a full leaf at the right end redistributes into the two-thirds-full leaf behind it, and on an ascending stream those walks alternate between one sibling and two: over the whole stream they average exactly 1.500. A window’s mean scatters around that value, 1.46 in one window and 1.55 in the next, so a target of 1.5 sees half its windows above it and halves the reach to one. At one the leaf’s neighbour is full, so it splits; a window of splits has no walks, its mean is zero, and the reach doubles again. The tree alternates between the rule that cannot fill ordered leaves and the one that can, and ends up about halfway between their fills.

So the target has a floor, and the floor is not arbitrary: it is the mean walk the ordered stream needs, 1.5, plus the scatter of a 64-overflow window around it. A target set below it is asking the tree to accept less than the minimum any redistribution on that stream costs. The keys that arrive late found the same kind of fragility in the rightmost-split rule, which is perfect on one stream and collapses on a small departure from it. The adaptive rule’s failure is at a stated number rather than at an input.

The late stream is milder. At targets of 1, 1.25 and 1.5 it ends with 2,282, 2,192 and 2,116 leaves against 2,096 from 1.75 up. Its walks are a mix of ordered short ones and the occasional long walk of a late key, so it sits partly above the floor. On random insertion the target is simply a price: target one gives 2,386 leaves at 1.69 pages, target three 2,165 at 4.12, and every target in between is a point on the same frontier.

What was measured and what was not

One size of tree and one seed per stream. 131,072 keys, leaves of 64, a fan-out of 64. The frontier positions on random insertion are within a per cent of each other, and a second seed would move the adaptive points by about as much. The claim that it lands on the frontier holds at that resolution. The claim that it beats the frontier on the random-to-ordered stream by 57 leaves is larger than that, and the claim that it loses by 16 on the other is of the same order as the noise.

Pages, not time. Pages written count every leaf and parent an insertion touches, as on the earlier page and as the writes nobody counted first counted them. A walk’s writes are to adjacent leaves, which on a real device are often adjacent blocks, and the block that is not a block lists why such writes are cheaper than a page count says. That favours the wide reaches, and so favours the adaptive rule on ordered streams.

No concurrency. A walk of dd siblings locks d+1d + 1 leaves and the parent. The adaptive rule’s reach is wide exactly on ordered streams, where walks are short, so its lock footprint is small where its reach is large. That is an argument, not a measurement.

The change is abrupt. Both changing streams switch order at one insertion. A stream whose order drifts slowly would be noticed as soon as its walks cross the target and not otherwise, and a drift that stays near the target would leave the reach oscillating. Neither was measured.

Internal levels keep even splits. As on the earlier page, only the leaves redistribute. One access, eight kilobytes is the reminder that the leaves are where the pages are, so that is where the rule was measured.

Still open: a reach per region of the tree

The adaptive rule has one reach for the whole tree. The stream that turned from random to ordered shows why that is coarse. After the change the ordered keys go to new leaves at the right edge, where walks are short and the whole parent is right, and the random half’s leaves are never touched again. On a stream that interleaves — a clock-ordered stream of new events alongside random updates to old ones — both kinds of insertion arrive at once, in different parts of the tree, and one reach has to serve both. The window’s mean walk is then a mixture, and the reach settles at a compromise that is wrong for both regions.

A parent node already knows which region it is: it is the node whose children the chain walks along. The measurement that follows gives every parent its own window and its own reach, costing a few bytes a parent. It runs the interleaved stream with ordered and random insertions mixed in shares from 10% to 90%, and compares the per-parent rule with the tree-wide one and with every fixed reach. The prediction is that the per-parent rule tracks each region’s own best reach, and so beats the tree-wide rule by more as the mixture approaches half and half. The risk is the window: a parent sees far fewer overflows than the whole tree does, so its window takes far longer to fill, and a per-parent rule might never have enough walks in hand to change its mind before the region’s order changes again.

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.

B-treeBlock transferDesign parameterHonest limitIndex maintenanceInsertion orderMeasured countNode fillPresortednessThresholdTrade offWrite amplification