<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/"><channel><title>Cache on Opensource internals</title><link>https://articles.9j.nz/tags/cache/</link><description>Posts filed under Cache on Opensource internals.</description><generator>Hugo</generator><language>en-US</language><managingEditor>Jay Hubbert</managingEditor><lastBuildDate>Sat, 24 Oct 2026 13:10:00 +0000</lastBuildDate><atom:link href="https://articles.9j.nz/tags/cache/index.xml" rel="self" type="application/rss+xml"/><item><title>The Lock-Free Eviction Queue: Weak Pointers and Sequence Numbers</title><link>https://articles.9j.nz/posts/how-duckdb-evicts-blocks-with-a-lock-free-weak-pointer-queue/</link><pubDate>Sat, 24 Oct 2026 13:10:00 +0000</pubDate><dc:creator>Jay Hubbert</dc:creator><guid isPermaLink="true">https://articles.9j.nz/posts/how-duckdb-evicts-blocks-with-a-lock-free-weak-pointer-queue/</guid><category>duckdb</category><category>buffer-manager</category><category>memory</category><category>cache</category><category>performance</category><description>DuckDB's eviction queue holds weak pointers to blocks plus a sequence number, so stale entries are detected without taking the block lock.</description><content:encoded>&lt;blockquote&gt;&#10;&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; The eviction queue is a &lt;code&gt;duckdb_moodycamel::ConcurrentQueue&lt;/code&gt; of&#10;&lt;code&gt;BufferEvictionNode{ weak_ptr&amp;lt;BlockMemory&amp;gt; memory_p; idx_t handle_sequence_number; }&lt;/code&gt;.&#10;Because the queue stores only a &lt;em&gt;weak&lt;/em&gt; pointer, enqueuing a block costs nothing and never&#10;keeps a dead block alive — the queue is allowed to accumulate garbage. An entry is stale&#10;if the weak pointer has expired (the block was destroyed) &lt;strong&gt;or&lt;/strong&gt; if its sequence number no&#10;longer matches the block&amp;rsquo;s current &lt;code&gt;eviction_seq_num&lt;/code&gt; (a newer entry superseded it).&#10;Staleness is therefore detectable &lt;em&gt;without&lt;/em&gt; taking the block lock. Garbage collection is&#10;amortised: a purge runs every 4096 insertions and uses &lt;code&gt;try_dequeue_bulk&lt;/code&gt; +&#10;&lt;code&gt;enqueue_bulk&lt;/code&gt; with a &lt;em&gt;separate producer token&lt;/em&gt;, so the survivors land in a sub-queue the&#10;consumer token has already walked past and FIFO order is preserved.&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;h2 id="the-scenario"&gt;The scenario&lt;/h2&gt;&#10;&lt;p&gt;Eight threads are scanning eight different tables. The memory limit is 4 GB. Every time a&#10;scan finishes a block it hands the block back to the pool; every time a scan wants a new&#10;block it takes one. Meanwhile, the pool is over its limit and needs to make room.&lt;/p&gt;&#10;&lt;p&gt;The pool&amp;rsquo;s job is to keep a list of blocks it &lt;em&gt;could&lt;/em&gt; throw away, in roughly the order it&#10;should throw them away. That list has to survive:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;concurrency&lt;/strong&gt; — many threads adding and removing entries at once;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;blocks that die&lt;/strong&gt; — a &lt;code&gt;BlockHandle&lt;/code&gt; can be destroyed while its entry is still in the&#10;queue, leaving a dangling reference;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;duplicate entries&lt;/strong&gt; — the same block can be enqueued, evicted-and-reloaded, and&#10;enqueued again, so the queue can hold several entries for the same block, only one of&#10;which is current.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;A naive &lt;code&gt;std::queue&amp;lt;shared_ptr&amp;lt;BlockHandle&amp;gt;&amp;gt;&lt;/code&gt; fails on all three counts: it needs a lock,&#10;and it cannot represent &amp;ldquo;the block this entry refers to is gone&amp;rdquo;.&lt;/p&gt;&#10;&lt;h2 id="the-node-a-weak-pointer-and-a-version-number"&gt;The node: a weak pointer and a version number&lt;/h2&gt;&#10;&lt;p&gt;Here is the whole type:&lt;/p&gt;&#10;&lt;div class="code-block"&gt;&#10; &lt;div class="code-block-head"&gt;&#10; &lt;span class="code-lang"&gt;cpp&lt;/span&gt;&#10; &lt;button class="code-copy" type="button" data-copy&gt;Copy&lt;/button&gt;&#10; &lt;/div&gt;&#10; &lt;div class="code-block-body"&gt;&#10; &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// src/include/duckdb/storage/buffer/buffer_pool.hpp:27&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;BufferEvictionNode&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;BufferEvictionNode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;BufferEvictionNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;weak_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;BlockMemory&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;block_memory_p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;idx_t&lt;/span&gt; &lt;span class="n"&gt;eviction_seq_num&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;weak_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;BlockMemory&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;memory_p&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;idx_t&lt;/span&gt; &lt;span class="n"&gt;handle_sequence_number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;IsDeadNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;optional_idx&lt;/span&gt; &lt;span class="n"&gt;debug_sleep_micros&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;optional_idx&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#10; &lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;p&gt;Two fields. &lt;code&gt;memory_p&lt;/code&gt; is a &lt;strong&gt;weak&lt;/strong&gt; pointer to the block&amp;rsquo;s &lt;code&gt;BlockMemory&lt;/code&gt;; &lt;code&gt;handle_sequence_number&lt;/code&gt;&#10;is a version number.&lt;/p&gt;&#10;&lt;p&gt;Why weak? Because the queue must not keep a block alive. If the queue held a &lt;code&gt;shared_ptr&lt;/code&gt;,&#10;then a block could never be freed while its entry sat in the queue, and the queue would&#10;grow without bound as blocks are loaded and unloaded. With a &lt;code&gt;weak_ptr&lt;/code&gt;, the entry is&#10;&lt;em&gt;allowed&lt;/em&gt; to dangle — the entry survives the block, and the purger notices.&lt;/p&gt;&#10;&lt;p&gt;Why a sequence number? Because a block can be enqueued more than once. Suppose a block&#10;is unpinned (enqueued, sequence 1), then pinned and unpinned again (enqueued, sequence 2).&#10;Now the queue holds two entries for the same block. Only the second is current. Without a&#10;version, the sweeper would happily unload the block twice, or unload it while somebody had&#10;re-pinned it.&lt;/p&gt;&#10;&lt;p&gt;The version lives on the block itself:&lt;/p&gt;&#10;&lt;div class="code-block"&gt;&#10; &lt;div class="code-block-head"&gt;&#10; &lt;span class="code-lang"&gt;cpp&lt;/span&gt;&#10; &lt;button class="code-copy" type="button" data-copy&gt;Copy&lt;/button&gt;&#10; &lt;/div&gt;&#10; &lt;div class="code-block-body"&gt;&#10; &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// src/include/duckdb/storage/buffer/block_handle.hpp:120&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;//! Returns the eviction sequence number.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;idx_t&lt;/span&gt; &lt;span class="nf"&gt;GetEvictionSequenceNumber&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;eviction_seq_num&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;memory_order_acquire&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;//! Increments the eviction sequence number prior to returning it.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;idx_t&lt;/span&gt; &lt;span class="nf"&gt;NextEvictionSequenceNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BlockLock&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="n"&gt;VerifyMutex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;new_sequence_number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;eviction_seq_num&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;memory_order_relaxed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="c1"&gt;// Publish preceding dead-node accounting to lock-free queue readers.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="n"&gt;eviction_seq_num&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_sequence_number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;memory_order_release&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;new_sequence_number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#10; &lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;p&gt;and the declaration carries the invariant in a comment:&lt;/p&gt;&#10;&lt;div class="code-block"&gt;&#10; &lt;div class="code-block-head"&gt;&#10; &lt;span class="code-lang"&gt;cpp&lt;/span&gt;&#10; &lt;button class="code-copy" type="button" data-copy&gt;Copy&lt;/button&gt;&#10; &lt;/div&gt;&#10; &lt;div class="code-block-body"&gt;&#10; &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// src/include/duckdb/storage/buffer/block_handle.hpp:242&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;//! The internal eviction sequence number. Monotonic: it is never reset, so an eviction queue&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;//! entry is stale if and only if its sequence number differs from this one. Writers hold the block lock.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;atomic&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;idx_t&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;eviction_seq_num&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#10; &lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;p&gt;&lt;strong&gt;Monotonic. Never reset.&lt;/strong&gt; That is the key property. Because the counter only ever goes&#10;up, &amp;ldquo;the entry&amp;rsquo;s number differs from the block&amp;rsquo;s current number&amp;rdquo; is an unambiguous test&#10;for &amp;ldquo;this entry is from an older generation&amp;rdquo;. No ABA problem, no epoch, no generation&#10;list.&lt;/p&gt;&#10;&lt;h2 id="two-ways-a-node-dies"&gt;Two ways a node dies&lt;/h2&gt;&#10;&lt;p&gt;The liveness test is short:&lt;/p&gt;&#10;&lt;div class="code-block"&gt;&#10; &lt;div class="code-block-head"&gt;&#10; &lt;span class="code-lang"&gt;cpp&lt;/span&gt;&#10; &lt;button class="code-copy" type="button" data-copy&gt;Copy&lt;/button&gt;&#10; &lt;/div&gt;&#10; &lt;div class="code-block-body"&gt;&#10; &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// src/storage/buffer/buffer_pool.cpp:42&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;BufferEvictionNode&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;BufferEvictionNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;weak_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;BlockMemory&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;block_memory_p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;idx_t&lt;/span&gt; &lt;span class="n"&gt;eviction_seq_num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;memory_p&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;block_memory_p&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="n"&gt;handle_sequence_number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eviction_seq_num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;D_ASSERT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;memory_p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expired&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;BufferEvictionNode&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;IsDeadNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;optional_idx&lt;/span&gt; &lt;span class="n"&gt;debug_sleep_micros&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;shared_memory_p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;memory_p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;debug_sleep_micros&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsValid&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="n"&gt;ThreadUtil&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;SleepMicroSeconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;debug_sleep_micros&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetIndex&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;shared_memory_p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handle_sequence_number&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;shared_memory_p&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;GetEvictionSequenceNumber&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#10; &lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;p&gt;Two death certificates:&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;&lt;strong&gt;&lt;code&gt;!shared_memory_p&lt;/code&gt;&lt;/strong&gt; — the weak pointer could not be upgraded. The &lt;code&gt;BlockMemory&lt;/code&gt; was&#10;destroyed, so the block is gone entirely. The entry is garbage.&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;&lt;strong&gt;&lt;code&gt;handle_sequence_number != shared_memory_p-&amp;gt;GetEvictionSequenceNumber()&lt;/code&gt;&lt;/strong&gt; — the&#10;block is alive, but this entry is from an older generation. A newer entry for the same&#10;block exists, and &lt;em&gt;that&lt;/em&gt; one is the live one.&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;Note that the second test reads &lt;code&gt;GetEvictionSequenceNumber()&lt;/code&gt; with &lt;code&gt;memory_order_acquire&lt;/code&gt;&#10;while the writer used &lt;code&gt;memory_order_release&lt;/code&gt;. That pairing is what makes the test&#10;well-defined: if the reader sees the new number, it also sees everything the writer did&#10;before storing it.&lt;/p&gt;&#10;&lt;p&gt;And note what is &lt;em&gt;not&lt;/em&gt; here: &lt;strong&gt;no lock&lt;/strong&gt;. &lt;code&gt;IsDeadNode&lt;/code&gt; touches only the weak pointer&amp;rsquo;s&#10;control block and one atomic load. It can be called on a queue full of blocks that other&#10;threads are concurrently locking, loading and unloading. The staleness test is entirely&#10;lock-free.&lt;/p&gt;&#10;&lt;p&gt;The &lt;code&gt;debug_sleep_micros&lt;/code&gt; parameter is a debug-only hook: it makes the thread sleep between&#10;upgrading the weak pointer and checking the sequence number, so that a race between a&#10;block&amp;rsquo;s destruction and the purger can be provoked on purpose. There is a whole DuckDB&#10;setting for it.&lt;/p&gt;&#10;&lt;h2 id="the-queue"&gt;The queue&lt;/h2&gt;&#10;&lt;p&gt;The container is a third-party lock-free MPMC queue:&lt;/p&gt;&#10;&lt;div class="code-block"&gt;&#10; &lt;div class="code-block-head"&gt;&#10; &lt;span class="code-lang"&gt;cpp&lt;/span&gt;&#10; &lt;button class="code-copy" type="button" data-copy&gt;Copy&lt;/button&gt;&#10; &lt;/div&gt;&#10; &lt;div class="code-block-body"&gt;&#10; &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// src/storage/buffer/buffer_pool.cpp:61&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="n"&gt;duckdb_moodycamel&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ConcurrentQueue&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;BufferEvictionNode&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;eviction_queue_t&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#10; &lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;p&gt;&lt;code&gt;duckdb_moodycamel::ConcurrentQueue&lt;/code&gt; is Cameron Desrochers&amp;rsquo; implementation, vendored in&#10;&lt;code&gt;third_party/concurrentqueue&lt;/code&gt;. Its own header describes it as &amp;ldquo;a C++11 implementation of a&#10;multi-producer, multi-consumer lock-free queue&amp;rdquo;, and points at a write-up of the design.&lt;/p&gt;&#10;&lt;p&gt;And DuckDB keeps a no-threads fallback so that single-threaded builds still compile:&lt;/p&gt;&#10;&lt;div class="code-block"&gt;&#10; &lt;div class="code-block-head"&gt;&#10; &lt;span class="code-lang"&gt;cpp&lt;/span&gt;&#10; &lt;button class="code-copy" type="button" data-copy&gt;Copy&lt;/button&gt;&#10; &lt;/div&gt;&#10; &lt;div class="code-block-body"&gt;&#10; &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// src/include/duckdb/parallel/concurrentqueue.hpp:58&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;template&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ConcurrentQueue&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;//! The standard library queue.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;deque&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;//! Default constructor.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;ConcurrentQueue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;//! Constructor reserving capacity.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;explicit&lt;/span&gt; &lt;span class="nf"&gt;ConcurrentQueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;capacity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reserve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;capacity&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#10; &lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;p&gt;The real queue is not a ring buffer. It is a &lt;strong&gt;linked list of per-producer sub-queues&lt;/strong&gt;,&#10;which is what makes the producer/consumer &lt;em&gt;token&lt;/em&gt; trick possible.&lt;/p&gt;&#10;&lt;h2 id="adding-to-the-queue"&gt;Adding to the queue&lt;/h2&gt;&#10;&lt;p&gt;Here is the enqueue path, from the &lt;code&gt;BufferPool&lt;/code&gt; down to the queue:&lt;/p&gt;&#10;&lt;div class="code-block"&gt;&#10; &lt;div class="code-block-head"&gt;&#10; &lt;span class="code-lang"&gt;cpp&lt;/span&gt;&#10; &lt;button class="code-copy" type="button" data-copy&gt;Copy&lt;/button&gt;&#10; &lt;/div&gt;&#10; &lt;div class="code-block-body"&gt;&#10; &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// src/storage/buffer/buffer_pool.cpp:274&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;BufferPool&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;AddToEvictionQueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BlockLock&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;shared_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;BlockHandle&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;memory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;GetMemory&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;// Verify the caller passed this block&amp;#39;s lock before we mutate any of its state.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;// The block lock is held throughout: Unpin holds it; ConvertToPersistent acquires the&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;// (uncontended) lock of the freshly created block before calling.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;VerifyMutex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GetEvictionQueueForBlockMemory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;D_ASSERT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetReaders&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HasLiveQueueEntry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="c1"&gt;// Count the previous live entry before bumping the sequence number. PurgeIteration&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="c1"&gt;// reads sequence numbers without the block lock; bumping first could let it see the&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="c1"&gt;// previous entry as stale and decrement dead_nodes before this matching increment.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IncrementDeadNodes&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;ts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NextEvictionSequenceNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#10; &lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;p&gt;Three things in this excerpt, and all three are about the race between the &lt;em&gt;lock-free&lt;/em&gt;&#10;purger and this &lt;em&gt;locked&lt;/em&gt; writer.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;&lt;code&gt;HasLiveQueueEntry&lt;/code&gt;&lt;/strong&gt; tracks whether the block already has an entry in the queue that has&#10;not been counted as dead. If it does, the &lt;em&gt;previous&lt;/em&gt; entry is about to become stale (we&#10;are about to bump the sequence number), so the dead-node counter is incremented now.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;The ordering comment is the interesting part:&lt;/strong&gt;&lt;/p&gt;&#10;&lt;blockquote&gt;&#10;&lt;p&gt;Count the previous live entry before bumping the sequence number. PurgeIteration reads&#10;sequence numbers without the block lock; bumping first could let it see the previous&#10;entry as stale and decrement dead_nodes before this matching increment.&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;p&gt;This is a genuine race, and the code closes it by ordering the two operations. If we&#10;bumped the sequence number first, a concurrent purger could observe the &lt;em&gt;old&lt;/em&gt; entry as&#10;stale, decide it is dead, and decrement &lt;code&gt;total_dead_nodes&lt;/code&gt; — and then our increment would&#10;arrive and push the counter &lt;em&gt;up&lt;/em&gt; by one, leaving the counter permanently one too high.&#10;By counting the dead node first, the counter is momentarily one too low rather than one&#10;too high, and the purger&amp;rsquo;s decrement corrects it.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;&lt;code&gt;NextEvictionSequenceNumber&lt;/code&gt;&lt;/strong&gt; is called last, and it bumps the counter that makes the&#10;previous entry stale. After this point, the new entry is the only live one.&lt;/p&gt;&#10;&lt;p&gt;Then the actual enqueue:&lt;/p&gt;&#10;&lt;div class="code-block"&gt;&#10; &lt;div class="code-block-head"&gt;&#10; &lt;span class="code-lang"&gt;cpp&lt;/span&gt;&#10; &lt;button class="code-copy" type="button" data-copy&gt;Copy&lt;/button&gt;&#10; &lt;/div&gt;&#10; &lt;div class="code-block-body"&gt;&#10; &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// src/storage/buffer/buffer_pool.cpp:144&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;EvictionQueue&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;AddToEvictionQueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BufferEvictionNode&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;enqueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;evict_queue_insertions&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;INSERT_INTERVAL&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#10; &lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;p&gt;One line of real work, and then the amortisation trigger: the queue counts its own&#10;insertions and reports &amp;ldquo;time to purge&amp;rdquo; every 4096 of them.&lt;/p&gt;&#10;&lt;h2 id="the-purge"&gt;The purge&lt;/h2&gt;&#10;&lt;div class="code-block"&gt;&#10; &lt;div class="code-block-head"&gt;&#10; &lt;span class="code-lang"&gt;cpp&lt;/span&gt;&#10; &lt;button class="code-copy" type="button" data-copy&gt;Copy&lt;/button&gt;&#10; &lt;/div&gt;&#10; &lt;div class="code-block-body"&gt;&#10; &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// src/storage/buffer/buffer_pool.cpp:154&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;EvictionQueue&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Purge&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;// only one thread purges the queue, all other threads early-out&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;unique_lock&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;guard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;purge_lock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;try_to_lock&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;guard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;owns_lock&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;// we purge INSERT_INTERVAL * PURGE_SIZE_MULTIPLIER nodes&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;idx_t&lt;/span&gt; &lt;span class="n"&gt;purge_size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;INSERT_INTERVAL&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;PURGE_SIZE_MULTIPLIER&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;// get an estimate of the queue size as-of now&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;idx_t&lt;/span&gt; &lt;span class="n"&gt;approx_q_size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size_approx&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;// early-out, if the queue is not big enough to justify purging&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;// - we want to keep the LRU characteristic alive&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;approx_q_size&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;purge_size&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;EARLY_OUT_MULTIPLIER&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#10; &lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;p&gt;The purge is &lt;em&gt;not&lt;/em&gt; a lock-free operation, and it does not need to be: it is a rare,&#10;batch-oriented garbage collection, and it is explicitly serialised. &lt;code&gt;std::try_to_lock&lt;/code&gt;&#10;means that if another thread is already purging, this thread just gives up — the purge&#10;will happen anyway.&lt;/p&gt;&#10;&lt;p&gt;The early-out is a heuristic with a stated motive: &amp;ldquo;we want to keep the LRU characteristic&#10;alive&amp;rdquo;. Purging a queue that is mostly alive means re-inserting most of its nodes, which&#10;costs time and disturbs the order. So the purge only runs when the queue is big.&lt;/p&gt;&#10;&lt;p&gt;The constants:&lt;/p&gt;&#10;&lt;div class="code-block"&gt;&#10; &lt;div class="code-block-head"&gt;&#10; &lt;span class="code-lang"&gt;cpp&lt;/span&gt;&#10; &lt;button class="code-copy" type="button" data-copy&gt;Copy&lt;/button&gt;&#10; &lt;/div&gt;&#10; &lt;div class="code-block-body"&gt;&#10; &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// src/storage/buffer/buffer_pool.cpp:114&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;//! We trigger a purge of the eviction queue every INSERT_INTERVAL insertions&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;constexpr&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;idx_t&lt;/span&gt; &lt;span class="n"&gt;INSERT_INTERVAL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4096&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;//! We multiply the base purge size by this value.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;constexpr&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;idx_t&lt;/span&gt; &lt;span class="n"&gt;PURGE_SIZE_MULTIPLIER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;//! We multiply the purge size by this value to determine early-outs. This is the minimum queue size.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;//! We never purge below this point.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;constexpr&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;idx_t&lt;/span&gt; &lt;span class="n"&gt;EARLY_OUT_MULTIPLIER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;//! We multiply the approximate alive nodes by this value to test whether our total dead nodes&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;//! exceed their allowed ratio. Must be greater than 1.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;constexpr&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;idx_t&lt;/span&gt; &lt;span class="n"&gt;ALIVE_NODE_MULTIPLIER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#10; &lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;p&gt;So: purge every 4096 insertions, purge 8192 nodes at a time, and only bother if the queue&#10;has at least 32768 nodes in it.&lt;/p&gt;&#10;&lt;h2 id="the-bulk-purge-and-the-fifo-trick"&gt;The bulk purge, and the FIFO trick&lt;/h2&gt;&#10;&lt;p&gt;Here is the actual garbage collection:&lt;/p&gt;&#10;&lt;div class="code-block"&gt;&#10; &lt;div class="code-block-head"&gt;&#10; &lt;span class="code-lang"&gt;cpp&lt;/span&gt;&#10; &lt;button class="code-copy" type="button" data-copy&gt;Copy&lt;/button&gt;&#10; &lt;/div&gt;&#10; &lt;div class="code-block-body"&gt;&#10; &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// src/storage/buffer/buffer_pool.cpp:215&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;EvictionQueue&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;PurgeIteration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;idx_t&lt;/span&gt; &lt;span class="n"&gt;purge_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;// if this purge is significantly smaller or bigger than the previous purge, then&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;// we need to resize the purge_nodes vector. Note that this barely happens, as we&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;// purge queue_insertions * PURGE_SIZE_MULTIPLIER nodes&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;idx_t&lt;/span&gt; &lt;span class="n"&gt;previous_purge_size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;purge_nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;purge_size&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;previous_purge_size&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;purge_size&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;previous_purge_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="n"&gt;purge_nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;purge_size&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;// Dequeue using consumer token — progresses through sub-queues sequentially&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;idx_t&lt;/span&gt; &lt;span class="n"&gt;actually_dequeued&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;try_dequeue_bulk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;purge_consumer_token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;purge_nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;purge_size&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;actually_dequeued&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;idx_t&lt;/span&gt; &lt;span class="n"&gt;dead_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;idx_t&lt;/span&gt; &lt;span class="n"&gt;alive_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;raw_sleep_micros&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;debug_eviction_queue_sleep&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;memory_order_relaxed&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;optional_idx&lt;/span&gt; &lt;span class="n"&gt;debug_sleep_micros&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;raw_sleep_micros&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;optional_idx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw_sleep_micros&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;optional_idx&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;idx_t&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;actually_dequeued&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;purge_nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsDeadNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;debug_sleep_micros&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&lt;span class="n"&gt;dead_count&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&lt;span class="c1"&gt;// Move alive nodes to the front for bulk re-enqueue&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&lt;span class="n"&gt;purge_nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;alive_count&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;total_dead_nodes&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;dead_count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;// Re-enqueue alive nodes via producer token — goes into a dedicated sub-queue&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;// that the consumer token has already passed&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alive_count&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;purge_producer_token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;valid&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nf"&gt;OutOfMemoryException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Failed to allocate eviction queue producer&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;enqueue_bulk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;purge_producer_token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;purge_nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;alive_count&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#10; &lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;p&gt;The algorithm is: dequeue a batch, partition it into dead and alive, and re-enqueue the&#10;alive ones.&lt;/p&gt;&#10;&lt;p&gt;The partition is the compaction trick: alive nodes are moved &lt;em&gt;to the front&lt;/em&gt; of the&#10;&lt;code&gt;purge_nodes&lt;/code&gt; vector (&lt;code&gt;purge_nodes[alive_count++] = std::move(node)&lt;/code&gt;), so the survivors&#10;end up packed in &lt;code&gt;[0, alive_count)&lt;/code&gt; and can be re-enqueued in one bulk call.&lt;/p&gt;&#10;&lt;p&gt;Now the part that deserves a slow look: &lt;strong&gt;why a separate producer token?&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;The &lt;code&gt;ConcurrentQueue&lt;/code&gt; in moodycamel&amp;rsquo;s design is a list of per-producer sub-queues, and a&#10;&lt;em&gt;consumer token&lt;/em&gt; walks them in a fixed order, remembering which one it was on. If the&#10;purger re-enqueued the survivors into the &lt;em&gt;same&lt;/em&gt; sub-queue the consumer was about to&#10;visit, the survivors would be dequeued again immediately, in a loop, forever. The purger&#10;would make no progress.&lt;/p&gt;&#10;&lt;p&gt;The fix is to give the purge its own producer token. That token is bound to a &lt;em&gt;different&lt;/em&gt;&#10;sub-queue — one the consumer token has already walked past. So the survivors are pushed&#10;&lt;em&gt;behind&lt;/em&gt; the consumer&amp;rsquo;s current position in the traversal, and the consumer will come back&#10;around to them only after it has finished with the sub-queues it has not yet visited.&lt;/p&gt;&#10;&lt;p&gt;The result: the purge preserves the queue&amp;rsquo;s FIFO order. The oldest blocks stay oldest, and&#10;the LRU characteristic the comment mentioned is preserved across a GC cycle.&lt;/p&gt;&#10;&lt;p&gt;The &lt;code&gt;total_dead_nodes&lt;/code&gt; bookkeeping also matters: the purger decrements the counter by&#10;exactly the number of dead nodes it removed. That counter is what drives the &amp;ldquo;purge more&#10;aggressively&amp;rdquo; loop in &lt;code&gt;Purge()&lt;/code&gt; — when the dead-to-alive ratio gets bad, the purger keeps&#10;going until it either reaches a healthy ratio or runs out of queue.&lt;/p&gt;&#10;&lt;h2 id="the-eviction-sweep-itself"&gt;The eviction sweep itself&lt;/h2&gt;&#10;&lt;p&gt;For completeness, here is the consumer side — the part that actually unloads blocks:&lt;/p&gt;&#10;&lt;div class="code-block"&gt;&#10; &lt;div class="code-block-head"&gt;&#10; &lt;span class="code-lang"&gt;cpp&lt;/span&gt;&#10; &lt;button class="code-copy" type="button" data-copy&gt;Copy&lt;/button&gt;&#10; &lt;/div&gt;&#10; &lt;div class="code-block-body"&gt;&#10; &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// src/storage/buffer/buffer_pool.cpp:455&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;template&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt; &lt;span class="n"&gt;FN&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;EvictionQueue&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;IterateUnloadableBlocks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FN&lt;/span&gt; &lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;debug_sleep_micros&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;debug_eviction_queue_sleep&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;memory_order_relaxed&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(;;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="c1"&gt;// get a block to unpin from the queue&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="n"&gt;BufferEvictionNode&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;try_dequeue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&lt;span class="c1"&gt;// we could not dequeue any eviction node, so we try one more time,&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&lt;span class="c1"&gt;// but more aggressively&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;TryDequeueWithLock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&#9;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="c1"&gt;// get a reference to the underlying block pointer&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;memory_p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;debug_sleep_micros&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&lt;span class="c1"&gt;// Debug race conditions regarding the ownership of the BlockMemory.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&lt;span class="c1"&gt;// Note that for this to trigger we need at least one purge iteration with the setting active.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&lt;span class="n"&gt;ThreadUtil&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;SleepMicroSeconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;debug_sleep_micros&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&lt;span class="n"&gt;DecrementDeadNodes&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="c1"&gt;// we might be able to free this block: grab the mutex and check if we can free it&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;lock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;GetLock&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;handle_sequence_number&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;GetEvictionSequenceNumber&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&lt;span class="c1"&gt;// A newer entry superseded this node: it was counted as dead when that entry was added.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&lt;span class="n"&gt;DecrementDeadNodes&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#10; &lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;p&gt;The same sequence-number test appears here, but now it is &lt;em&gt;inside&lt;/em&gt; the block lock. The&#10;difference matters:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;In the purger (lock-free), a mismatch means &amp;ldquo;this entry is stale, drop it&amp;rdquo;.&lt;/li&gt;&#10;&lt;li&gt;Here (holding the lock), a mismatch means &amp;ldquo;this entry is stale, drop it — and it was&#10;already counted as dead when the newer entry was added&amp;rdquo;, so the counter is decremented.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;And when the entry &lt;em&gt;is&lt;/em&gt; current, the block is unloaded, under the lock, and the block&#10;loses its queue entry (&lt;code&gt;SetHasLiveQueueEntry(lock, false)&lt;/code&gt;) so that a later unpin will&#10;re-enqueue it with a fresh sequence number.&lt;/p&gt;&#10;&lt;p&gt;Two failure paths are handled with care. If the block cannot be offloaded because there&#10;is no temporary directory, the node is re-enqueued and the sweep &lt;em&gt;stops&lt;/em&gt; — the block is&#10;not lost. And if the unload itself throws, the node is re-enqueued and the exception is&#10;rethrown, so a failed unload never leaves a block permanently un-evictable.&lt;/p&gt;&#10;&lt;h2 id="costs-and-trade-offs"&gt;Costs and trade-offs&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;&lt;strong&gt;The queue can grow without bound between purges.&lt;/strong&gt; That is the deliberate trade: a&#10;&lt;code&gt;weak_ptr&lt;/code&gt; entry costs 16 bytes and never keeps anything alive, so a queue with a&#10;million stale entries costs 16 MB and nothing else. The purger is the garbage&#10;collector, and it runs on a schedule rather than on every operation.&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;&lt;strong&gt;Purging is &lt;code&gt;O(dead nodes)&lt;/code&gt;, amortised.&lt;/strong&gt; Every 4096 insertions, up to 8192 nodes are&#10;examined. Each examination is one weak-pointer upgrade (an atomic CAS on the control&#10;block) plus one atomic load. There is no per-operation cost beyond the enqueue itself.&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;&lt;strong&gt;The weak-pointer upgrade is not free.&lt;/strong&gt; &lt;code&gt;memory_p.lock()&lt;/code&gt; is an atomic&#10;compare-and-swap on the control block, and it will &lt;em&gt;fail&lt;/em&gt; for dead nodes. But it is&#10;lock-free and wait-free, and it is the only way to know whether the block is still&#10;alive.&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;&lt;strong&gt;The sequence number is a &lt;code&gt;uint64_t&lt;/code&gt; on the block.&lt;/strong&gt; It costs 8 bytes per block and&#10;one atomic increment per enqueue. In exchange, the purger needs no lock and no&#10;epoch-based scheme.&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;&lt;strong&gt;The dead-node counter is approximate by design.&lt;/strong&gt; It is maintained under a mixture of&#10;locked and lock-free operations, and the source comments are explicit about the race&#10;and about which way the error is allowed to go. It is used to decide &lt;em&gt;how hard to&#10;purge&lt;/em&gt;, not for correctness.&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;&lt;strong&gt;The pool is not one queue but several.&lt;/strong&gt; &lt;code&gt;FileBufferTypeToEvictionQueueTypeIdx&lt;/code&gt; maps&#10;buffer types onto three queue &lt;em&gt;types&lt;/em&gt; — &lt;code&gt;BLOCK&lt;/code&gt;/&lt;code&gt;EXTERNAL_FILE&lt;/code&gt; (cheap to discard),&#10;&lt;code&gt;MANAGED_BUFFER&lt;/code&gt; (must be spilled to a temp file), and &lt;code&gt;TINY_BUFFER&lt;/code&gt; (last resort) —&#10;and the sweeper drains them in that order. &lt;code&gt;MANAGED_BUFFER&lt;/code&gt; alone is split into six&#10;queues so that the radix-partitioned row-group allocator can keep a partition&amp;rsquo;s&#10;blocks together. All of that priority lives in &lt;em&gt;which queue a block goes into&lt;/em&gt;, not in&#10;the queue algorithm itself.&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;&lt;strong&gt;The debug sleep hook exists because these races are real.&lt;/strong&gt; &lt;code&gt;IsDeadNode&lt;/code&gt; takes an&#10;optional sleep between upgrading the weak pointer and reading the sequence number,&#10;precisely so a test can widen that window and check that the accounting still balances.&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="the-bottom-line"&gt;The bottom line&lt;/h2&gt;&#10;&lt;p&gt;The eviction queue is a good example of a design where the &lt;em&gt;data structure&lt;/em&gt; is dumb and&#10;the &lt;em&gt;protocol&lt;/em&gt; is clever. The queue itself is a general-purpose lock-free MPMC container&#10;that knows nothing about blocks. All the block-specific intelligence lives in two fields&#10;of the node: a weak pointer, so the queue never keeps anything alive, and a monotonic&#10;version number, so a stale entry can be recognised without a lock.&lt;/p&gt;&#10;&lt;p&gt;The version number is the trick worth stealing. A weak pointer alone tells you &amp;ldquo;the block&#10;is gone&amp;rdquo;. A weak pointer plus a monotonically increasing per-block counter tells you&#10;&amp;ldquo;this entry is either from a dead block or from a previous generation of a live one&amp;rdquo; —&#10;and both of those questions can be answered with two atomic operations and no lock. No&#10;epochs, no hazard pointers, no generation lists.&lt;/p&gt;&#10;&lt;p&gt;The second trick worth stealing is the &lt;em&gt;separate producer token&lt;/em&gt;. Garbage collection that&#10;re-inserts survivors into the same queue it is draining is a livelock waiting to happen;&#10;giving the collector its own producer token so the survivors land &lt;em&gt;behind&lt;/em&gt; the consumer&amp;rsquo;s&#10;current position is a two-line fix that preserves the queue&amp;rsquo;s ordering guarantees.&lt;/p&gt;&#10;&lt;p&gt;And the general lesson about counters: DuckDB maintains a &lt;code&gt;total_dead_nodes&lt;/code&gt; counter&#10;across a boundary between locked and lock-free code, and the source comments spend more&#10;words explaining which way the error is allowed to go than the arithmetic itself. When a&#10;counter is only a heuristic, say so — loudly — and decide deliberately whether it may&#10;over- or under-count. The decision is written down: &lt;em&gt;under-count first, let the purger&amp;rsquo;s&#10;decrement fix it up&lt;/em&gt;. That is a much better failure mode than the opposite.&lt;/p&gt;&#10;</content:encoded></item><item><title>Pinning Is Ownership: DuckDB's Buffer Handle Is a shared_ptr</title><link>https://articles.9j.nz/posts/how-pinning-is-ownership-in-duckdbs-buffer-manager/</link><pubDate>Sat, 24 Oct 2026 12:40:00 +0000</pubDate><dc:creator>Jay Hubbert</dc:creator><guid isPermaLink="true">https://articles.9j.nz/posts/how-pinning-is-ownership-in-duckdbs-buffer-manager/</guid><category>duckdb</category><category>buffer-manager</category><category>memory</category><category>cache</category><category>internals</category><description>A DuckDB BufferHandle holds a shared_ptr that owns the bytes, so eviction can never happen under a live reader.</description><content:encoded>&lt;blockquote&gt;&#10;&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; In DuckDB, &amp;ldquo;pinning&amp;rdquo; a block means holding a &lt;code&gt;shared_ptr&lt;/code&gt; to it. A&#10;&lt;code&gt;BufferHandle&lt;/code&gt; owns a &lt;code&gt;shared_ptr&amp;lt;BlockHandle&amp;gt;&lt;/code&gt;; the &lt;code&gt;BlockHandle&lt;/code&gt; owns a&#10;&lt;code&gt;shared_ptr&amp;lt;BlockMemory&amp;gt;&lt;/code&gt;; and the &lt;code&gt;BlockMemory&lt;/code&gt; is the only place the actual &lt;code&gt;FileBuffer&lt;/code&gt;&#10;bytes live. While a reader holds the handle, the bytes cannot be destroyed, so the block&#10;&lt;em&gt;cannot&lt;/em&gt; be evicted underneath it. The &lt;code&gt;readers&lt;/code&gt; atomic counter is &lt;strong&gt;not&lt;/strong&gt; the safety&#10;mechanism — it is an advisory signal that lets the eviction sweeper skip pinned blocks&#10;without taking a lock. The safety comes free from the ownership graph.&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;h2 id="the-scenario"&gt;The scenario&lt;/h2&gt;&#10;&lt;p&gt;You run a query over a table that is much bigger than your memory limit:&lt;/p&gt;&#10;&lt;div class="code-block"&gt;&#10; &lt;div class="code-block-head"&gt;&#10; &lt;span class="code-lang"&gt;sql&lt;/span&gt;&#10; &lt;button class="code-copy" type="button" data-copy&gt;Copy&lt;/button&gt;&#10; &lt;/div&gt;&#10; &lt;div class="code-block-body"&gt;&#10; &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o_totalprice&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#10; &lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;p&gt;The buffer pool is under pressure. The eviction sweeper is running, deciding which blocks&#10;to throw out to make room for the next one. Meanwhile, the scan is holding several blocks&#10;open and is about to read a &lt;code&gt;DECIMAL&lt;/code&gt; out of one of them.&lt;/p&gt;&#10;&lt;p&gt;The question this article is about is narrow and important: &lt;strong&gt;how does DuckDB guarantee&#10;that the eviction sweeper cannot pull the rug out from under that read?&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;The naive answer — &amp;ldquo;it keeps a counter of active readers and refuses to evict a block&#10;with a non-zero count&amp;rdquo; — is how a lot of buffer managers work, and it is subtly wrong.&#10;A counter is a &lt;em&gt;hint&lt;/em&gt;. Between the moment the sweeper reads the counter and the moment it&#10;acts on it, the count can change. Any design that relies on the counter for &lt;em&gt;correctness&lt;/em&gt;&#10;has a race in it.&lt;/p&gt;&#10;&lt;p&gt;DuckDB does not rely on the counter for correctness. It relies on ownership.&lt;/p&gt;&#10;&lt;h2 id="the-ownership-chain"&gt;The ownership chain&lt;/h2&gt;&#10;&lt;p&gt;Start at the top. This is the entire &lt;code&gt;BufferHandle&lt;/code&gt; class:&lt;/p&gt;&#10;&lt;div class="code-block"&gt;&#10; &lt;div class="code-block-head"&gt;&#10; &lt;span class="code-lang"&gt;cpp&lt;/span&gt;&#10; &lt;button class="code-copy" type="button" data-copy&gt;Copy&lt;/button&gt;&#10; &lt;/div&gt;&#10; &lt;div class="code-block-body"&gt;&#10; &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// src/include/duckdb/storage/buffer/buffer_handle.hpp:53&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;shared_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;BlockHandle&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;GetBlockHandle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;//! The block handle&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;shared_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;BlockHandle&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;//! The managed buffer node&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;optional_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;FileBuffer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#10; &lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;p&gt;Two members. &lt;code&gt;handle&lt;/code&gt; is a &lt;code&gt;shared_ptr&amp;lt;BlockHandle&amp;gt;&lt;/code&gt; — a &lt;em&gt;shared&lt;/em&gt; ownership handle to the&#10;block&amp;rsquo;s metadata. &lt;code&gt;node&lt;/code&gt; is a raw &lt;code&gt;optional_ptr&amp;lt;FileBuffer&amp;gt;&lt;/code&gt; — a &lt;em&gt;non-owning&lt;/em&gt; pointer to the&#10;bytes.&lt;/p&gt;&#10;&lt;p&gt;That split is the whole design. The handle owns the block; the block owns the bytes; the&#10;handle merely &lt;em&gt;points at&lt;/em&gt; the bytes. The pointer is a convenience (it is what&#10;&lt;code&gt;Ptr()&lt;/code&gt; returns), not a lifetime guarantee.&lt;/p&gt;&#10;&lt;p&gt;Here is the &lt;code&gt;BlockHandle&lt;/code&gt; side:&lt;/p&gt;&#10;&lt;div class="code-block"&gt;&#10; &lt;div class="code-block-head"&gt;&#10; &lt;span class="code-lang"&gt;cpp&lt;/span&gt;&#10; &lt;button class="code-copy" type="button" data-copy&gt;Copy&lt;/button&gt;&#10; &lt;/div&gt;&#10; &lt;div class="code-block-body"&gt;&#10; &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// src/include/duckdb/storage/buffer/block_handle.hpp:292&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;//! Returns a const reference to the memory of a block.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;BlockMemory&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;GetMemory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;//! Returns a reference to the memory of a block.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;BlockMemory&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;GetMemory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;//! Returns a weak pointer to the memory of a block.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;weak_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;BlockMemory&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;GetMemoryWeak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;weak_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;BlockMemory&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;memory_p&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#10; &lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;p&gt;and the members at the bottom of the class:&lt;/p&gt;&#10;&lt;div class="code-block"&gt;&#10; &lt;div class="code-block-head"&gt;&#10; &lt;span class="code-lang"&gt;cpp&lt;/span&gt;&#10; &lt;button class="code-copy" type="button" data-copy&gt;Copy&lt;/button&gt;&#10; &lt;/div&gt;&#10; &lt;div class="code-block-body"&gt;&#10; &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// src/include/duckdb/storage/buffer/block_handle.hpp:324&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;//! Pointer to the underlying memory of the block.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;shared_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;BlockMemory&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;memory_p&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;//! Memory for fast access to the block memory.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;BlockMemory&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#10; &lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;p&gt;There are two views of the same &lt;code&gt;BlockMemory&lt;/code&gt;:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;memory_p&lt;/code&gt; is a &lt;code&gt;shared_ptr&amp;lt;BlockMemory&amp;gt;&lt;/code&gt; — the &lt;strong&gt;owner&lt;/strong&gt;.&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;memory&lt;/code&gt; is a &lt;code&gt;BlockMemory &amp;amp;&lt;/code&gt; — a raw reference, for fast access without an atomic&#10;refcount bump.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;And &lt;code&gt;BlockMemory&lt;/code&gt; is where the bytes actually live:&lt;/p&gt;&#10;&lt;div class="code-block"&gt;&#10; &lt;div class="code-block-head"&gt;&#10; &lt;span class="code-lang"&gt;cpp&lt;/span&gt;&#10; &lt;button class="code-copy" type="button" data-copy&gt;Copy&lt;/button&gt;&#10; &lt;/div&gt;&#10; &lt;div class="code-block-body"&gt;&#10; &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// src/include/duckdb/storage/buffer/block_handle.hpp:234&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;//! The number of concurrent readers. Writers hold the block lock; reads may be unlocked.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;atomic&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int32_t&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;readers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;//! The memory tag.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;MemoryTag&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;//! The file buffer type.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;FileBufferType&lt;/span&gt; &lt;span class="n"&gt;buffer_type&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;//! A pointer to the loaded data, if any.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;unique_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;FileBuffer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#10; &lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;p&gt;&lt;code&gt;buffer&lt;/code&gt; is a &lt;code&gt;unique_ptr&amp;lt;FileBuffer&amp;gt;&lt;/code&gt;. &lt;em&gt;That&lt;/em&gt; is the object that owns the memory the&#10;query is reading.&lt;/p&gt;&#10;&lt;p&gt;So the chain is:&lt;/p&gt;&#10;&lt;div class="code-block"&gt;&#10; &lt;div class="code-block-head"&gt;&#10; &lt;span class="code-lang"&gt;text&lt;/span&gt;&#10; &lt;button class="code-copy" type="button" data-copy&gt;Copy&lt;/button&gt;&#10; &lt;/div&gt;&#10; &lt;div class="code-block-body"&gt;&#10; &lt;pre tabindex="0"&gt;&lt;code&gt;BufferHandle&#10; └─ shared_ptr&amp;lt;BlockHandle&amp;gt;&#10; └─ shared_ptr&amp;lt;BlockMemory&amp;gt; (memory_p)&#10; └─ unique_ptr&amp;lt;FileBuffer&amp;gt; (buffer)&#10; └─ the actual bytes&lt;/code&gt;&lt;/pre&gt;&#10; &lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;p&gt;Three levels of ownership, and every level is a &lt;code&gt;shared_ptr&lt;/code&gt; or a &lt;code&gt;unique_ptr&lt;/code&gt;. When the&#10;last &lt;code&gt;shared_ptr&lt;/code&gt; to the &lt;code&gt;BlockMemory&lt;/code&gt; goes away, the &lt;code&gt;BlockMemory&lt;/code&gt; is destroyed, its&#10;&lt;code&gt;unique_ptr&amp;lt;FileBuffer&amp;gt;&lt;/code&gt; is destroyed, and the bytes are released. There is no other path&#10;to freeing the bytes, because &lt;code&gt;buffer&lt;/code&gt; is private to &lt;code&gt;BlockMemory&lt;/code&gt; and there is exactly&#10;one &lt;code&gt;BlockMemory&lt;/code&gt; per block.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;This is the invariant&lt;/strong&gt;: the bytes cannot be freed while any &lt;code&gt;BufferHandle&lt;/code&gt; exists,&#10;because a &lt;code&gt;BufferHandle&lt;/code&gt; transitively holds the only &lt;code&gt;shared_ptr&lt;/code&gt; chain to them.&lt;/p&gt;&#10;&lt;h2 id="why-the-readers-counter-is-only-a-hint"&gt;Why the readers counter is only a hint&lt;/h2&gt;&#10;&lt;p&gt;Here is the counter&amp;rsquo;s implementation:&lt;/p&gt;&#10;&lt;div class="code-block"&gt;&#10; &lt;div class="code-block-head"&gt;&#10; &lt;span class="code-lang"&gt;cpp&lt;/span&gt;&#10; &lt;button class="code-copy" type="button" data-copy&gt;Copy&lt;/button&gt;&#10; &lt;/div&gt;&#10; &lt;div class="code-block-body"&gt;&#10; &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// src/include/duckdb/storage/buffer/block_handle.hpp:79&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;//! Increments the number of readers prior to returning it.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="kt"&gt;int32_t&lt;/span&gt; &lt;span class="nf"&gt;IncrementReaders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BlockLock&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="n"&gt;VerifyMutex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="c1"&gt;// Tiny buffers do not decrement on unpin, so their reader count can wrap.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;new_readers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;static_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int32_t&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;static_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;readers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;memory_order_relaxed&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="n"&gt;readers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_readers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;memory_order_relaxed&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;new_readers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;//! Decrements the number of readers prior to returning it.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="kt"&gt;int32_t&lt;/span&gt; &lt;span class="nf"&gt;DecrementReaders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BlockLock&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="n"&gt;VerifyMutex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;new_readers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;static_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int32_t&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;static_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;readers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;memory_order_relaxed&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="n"&gt;readers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_readers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;memory_order_relaxed&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;new_readers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#10; &lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;p&gt;Two things to notice.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;The comment about tiny buffers.&lt;/strong&gt; &amp;ldquo;Tiny buffers do not decrement on unpin, so their&#10;reader count can wrap.&amp;rdquo; A &lt;code&gt;TINY_BUFFER&lt;/code&gt; is a small allocation that is not managed by the&#10;pool; it is never unloaded, so the counter would only ever grow. Rather than special-case&#10;it, the code explicitly allows the &lt;code&gt;int32_t&lt;/code&gt; to wrap around by doing the arithmetic in&#10;&lt;code&gt;uint32_t&lt;/code&gt; and casting back. This is a deliberate decision to make a &lt;em&gt;hint&lt;/em&gt; wrong rather&#10;than to add a branch to a hot path. And it is safe precisely &lt;em&gt;because&lt;/em&gt; the hint is not&#10;load-bearing for correctness.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;The memory ordering is &lt;code&gt;relaxed&lt;/code&gt;.&lt;/strong&gt; The counter is not a synchronisation primitive. It&#10;is a number that is approximately right. If two threads increment it concurrently, the&#10;result is some number that is not exactly the number of readers — and that is fine,&#10;because the counter is only used to answer &amp;ldquo;should I bother looking at this block?&amp;rdquo;.&lt;/p&gt;&#10;&lt;p&gt;And here is where it is consumed:&lt;/p&gt;&#10;&lt;div class="code-block"&gt;&#10; &lt;div class="code-block-head"&gt;&#10; &lt;span class="code-lang"&gt;cpp&lt;/span&gt;&#10; &lt;button class="code-copy" type="button" data-copy&gt;Copy&lt;/button&gt;&#10; &lt;/div&gt;&#10; &lt;div class="code-block-body"&gt;&#10; &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// src/storage/buffer/block_handle.cpp:105&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;CanUnloadResult&lt;/span&gt; &lt;span class="n"&gt;BlockMemory&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;CanUnload&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GetState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;BlockState&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;BLOCK_UNLOADED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="c1"&gt;// The block has already been unloaded.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;CanUnloadResult&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ALREADY_UNLOADED&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GetReaders&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="c1"&gt;// There are active readers.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;CanUnloadResult&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;PINNED&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BlockId&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;MAXIMUM_BLOCK&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;MustWriteToTemporaryFile&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;GetBufferManager&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;HasTemporaryDirectory&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="c1"&gt;// The block memory cannot be destroyed upon eviction/unpinning.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="c1"&gt;// In order to unload this block we need to write it to a temporary buffer.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="c1"&gt;// However, no temporary directory is specified, hence, we cannot unload.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;CanUnloadResult&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;NO_TEMP_DIRECTORY&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;CanUnloadResult&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;CAN_UNLOAD&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#10; &lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;p&gt;&lt;code&gt;GetReaders() &amp;gt; 0&lt;/code&gt; → &lt;code&gt;PINNED&lt;/code&gt;. The sweeper skips it.&lt;/p&gt;&#10;&lt;p&gt;But &lt;em&gt;how&lt;/em&gt; is this safe? The answer is that the sweeper does not free the bytes by&#10;destroying the &lt;code&gt;FileBuffer&lt;/code&gt; out from under a reader. It frees them by &lt;em&gt;unloading the&#10;block&lt;/em&gt; — and unloading requires taking the block&amp;rsquo;s lock, and the block&amp;rsquo;s state transition&#10;to &lt;code&gt;BLOCK_UNLOADED&lt;/code&gt; is guarded by that lock.&lt;/p&gt;&#10;&lt;p&gt;The real safety net is the combination:&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;A reader holds a &lt;code&gt;shared_ptr&lt;/code&gt; chain to the &lt;code&gt;BlockMemory&lt;/code&gt;, so the &lt;code&gt;BlockMemory&lt;/code&gt; — and&#10;therefore the &lt;code&gt;FileBuffer&lt;/code&gt; — cannot be destroyed.&lt;/li&gt;&#10;&lt;li&gt;The sweeper&amp;rsquo;s decision to unload is made under the block lock.&lt;/li&gt;&#10;&lt;li&gt;A reader that is &lt;em&gt;about&lt;/em&gt; to read takes the block lock when it loads or increments the&#10;reader count, so it cannot race with an unload.&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;The counter, meanwhile, tells the sweeper &amp;ldquo;don&amp;rsquo;t even bother taking the lock for this&#10;one&amp;rdquo;. It is an optimisation. If the counter were wrong, the sweeper would take the lock,&#10;see the true state, and do the right thing anyway.&lt;/p&gt;&#10;&lt;h2 id="pinning-the-double-checked-load"&gt;Pinning: the double-checked load&lt;/h2&gt;&#10;&lt;p&gt;Here is &lt;code&gt;Pin&lt;/code&gt;, the function that turns a &lt;code&gt;BlockHandle&lt;/code&gt; into a &lt;code&gt;BufferHandle&lt;/code&gt;:&lt;/p&gt;&#10;&lt;div class="code-block"&gt;&#10; &lt;div class="code-block-head"&gt;&#10; &lt;span class="code-lang"&gt;cpp&lt;/span&gt;&#10; &lt;button class="code-copy" type="button" data-copy&gt;Copy&lt;/button&gt;&#10; &lt;/div&gt;&#10; &lt;div class="code-block-body"&gt;&#10; &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// src/storage/standard_buffer_manager.cpp:369&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;BufferHandle&lt;/span&gt; &lt;span class="n"&gt;StandardBufferManager&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Pin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;QueryContext&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;shared_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;BlockHandle&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;// we need to be careful not to return the BufferHandle to this block while holding the BlockHandle&amp;#39;s lock&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;// as exiting this function&amp;#39;s scope may cause the destructor of the BufferHandle to be called while holding the lock&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;// the destructor calls Unpin, which grabs the BlockHandle&amp;#39;s lock again, causing a deadlock&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;BufferHandle&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;idx_t&lt;/span&gt; &lt;span class="n"&gt;required_memory&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block_memory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;GetMemory&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="c1"&gt;// lock the block&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;lock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;block_memory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetLock&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="c1"&gt;// check if the block is already loaded&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;block_memory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;BlockState&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;BLOCK_LOADED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&lt;span class="c1"&gt;// the block is loaded, increment the reader count and set the BufferHandle&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&lt;span class="n"&gt;buf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;Load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="n"&gt;required_memory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;block_memory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetMemoryUsage&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsValid&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// the block was already loaded, return it without holding the BlockHandle&amp;#39;s lock&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#10; &lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;p&gt;Read the comment at the top. It is a &lt;em&gt;self-deadlock&lt;/em&gt; warning, and it is the most&#10;instructive line in the whole file:&lt;/p&gt;&#10;&lt;blockquote&gt;&#10;&lt;p&gt;we need to be careful not to return the BufferHandle to this block while holding the&#10;BlockHandle&amp;rsquo;s lock&#10;as exiting this function&amp;rsquo;s scope may cause the destructor of the BufferHandle to be&#10;called while holding the lock&#10;the destructor calls Unpin, which grabs the BlockHandle&amp;rsquo;s lock again, causing a deadlock&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;p&gt;This is the price of the ownership design. &lt;code&gt;BufferHandle&lt;/code&gt;&amp;rsquo;s destructor calls &lt;code&gt;Unpin&lt;/code&gt;,&#10;which takes the block lock. If the handle were returned while the lock was held, the&#10;temporary&amp;rsquo;s destructor would run at the end of the scope — with the lock still held — and&#10;&lt;code&gt;Unpin&lt;/code&gt; would try to take the same non-recursive &lt;code&gt;std::mutex&lt;/code&gt; again. Boom.&lt;/p&gt;&#10;&lt;p&gt;So &lt;code&gt;Pin&lt;/code&gt; deliberately returns the handle &lt;em&gt;outside&lt;/em&gt; the lock&amp;rsquo;s scope. The lock is&#10;acquired in an inner block &lt;code&gt;{ ... }&lt;/code&gt; precisely so that it is released before the return.&lt;/p&gt;&#10;&lt;p&gt;Continue reading the function and you see the classic double-checked pattern:&lt;/p&gt;&#10;&lt;div class="code-block"&gt;&#10; &lt;div class="code-block-head"&gt;&#10; &lt;span class="code-lang"&gt;cpp&lt;/span&gt;&#10; &lt;button class="code-copy" type="button" data-copy&gt;Copy&lt;/button&gt;&#10; &lt;/div&gt;&#10; &lt;div class="code-block-body"&gt;&#10; &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// src/storage/standard_buffer_manager.cpp:392&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;// evict blocks until we have space for the current block&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;unique_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;FileBuffer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;reusable_buffer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;reservation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9; &lt;span class="n"&gt;EvictBlocksOrThrow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;block_memory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetMemoryTag&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;required_memory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;reusable_buffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9; &lt;span class="s"&gt;&amp;#34;failed to pin block of size %s%s&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StringUtil&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;BytesToHumanReadableString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;required_memory&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;// lock the handle again and repeat the check (in case anybody loaded in the meantime)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;lock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;block_memory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetLock&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;// check if the block is already loaded&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;block_memory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;BlockState&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;BLOCK_LOADED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="c1"&gt;// the block is loaded, increment the reader count and return a pointer to the handle&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="n"&gt;reservation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Resize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="n"&gt;buf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;Load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#10; &lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;p&gt;Between releasing the lock and re-acquiring it, we went and evicted blocks to make room —&#10;which takes an unbounded amount of time and releases the lock entirely. Another thread may&#10;have loaded the same block in the meantime. So the state is checked &lt;em&gt;again&lt;/em&gt; under the lock.&#10;If somebody beat us to it, the memory reservation we took is refunded (&lt;code&gt;reservation.Resize(0)&lt;/code&gt;)&#10;and we just take a reader count on the already-loaded block.&lt;/p&gt;&#10;&lt;p&gt;The reservation refund is a nice touch: the memory is charged to the pool the moment we&#10;decide we might need it, and un-charged the moment we discover we don&amp;rsquo;t. The charging is&#10;an RAII token, so the refund is a single call.&lt;/p&gt;&#10;&lt;p&gt;And here is the actual load:&lt;/p&gt;&#10;&lt;div class="code-block"&gt;&#10; &lt;div class="code-block-head"&gt;&#10; &lt;span class="code-lang"&gt;cpp&lt;/span&gt;&#10; &lt;button class="code-copy" type="button" data-copy&gt;Copy&lt;/button&gt;&#10; &lt;/div&gt;&#10; &lt;div class="code-block-body"&gt;&#10; &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// src/storage/buffer/block_handle.cpp:214&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;BufferHandle&lt;/span&gt; &lt;span class="n"&gt;BlockHandle&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BlockLock&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;QueryContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unique_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;FileBuffer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;reusable_buffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;VerifyMutex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;BlockState&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;BLOCK_LOADED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="c1"&gt;// The block has already been loaded.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="n"&gt;D_ASSERT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetBuffer&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IncrementReaders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;BufferHandle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shared_from_this&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetBuffer&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CanReload&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="c1"&gt;// the buffer was destroyed upon unpin/evict, or the handle was replaced and its disk block&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="c1"&gt;// may be rewritten in place - the caller must re-resolve the block id&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;BufferHandle&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#10; &lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;p&gt;&lt;code&gt;BufferHandle(shared_from_this(), memory.GetBuffer())&lt;/code&gt;. The &lt;code&gt;shared_from_this()&lt;/code&gt; is the&#10;crux: the &lt;code&gt;BlockHandle&lt;/code&gt; hands out a &lt;code&gt;shared_ptr&lt;/code&gt; to &lt;em&gt;itself&lt;/em&gt;, and the &lt;code&gt;BufferHandle&lt;/code&gt;&#10;stores it. That is what makes the whole chain hold.&lt;/p&gt;&#10;&lt;p&gt;Note also &lt;code&gt;memory.IncrementReaders(l)&lt;/code&gt; — the counter is bumped &lt;em&gt;here&lt;/em&gt;, under the block&#10;lock, at the same moment the handle is created. So the counter and the ownership are&#10;established atomically with respect to the lock. A sweeper that takes the lock and sees&#10;&lt;code&gt;readers == 0&lt;/code&gt; genuinely knows that at that instant no reader exists.&lt;/p&gt;&#10;&lt;h2 id="unpinning"&gt;Unpinning&lt;/h2&gt;&#10;&lt;div class="code-block"&gt;&#10; &lt;div class="code-block-head"&gt;&#10; &lt;span class="code-lang"&gt;cpp&lt;/span&gt;&#10; &lt;button class="code-copy" type="button" data-copy&gt;Copy&lt;/button&gt;&#10; &lt;/div&gt;&#10; &lt;div class="code-block-body"&gt;&#10; &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// src/storage/standard_buffer_manager.cpp:459&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;StandardBufferManager&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Unpin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shared_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;BlockHandle&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;purge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block_memory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;GetMemory&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;lock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;block_memory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetLock&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;block_memory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetBuffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;block_memory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetBufferType&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;FileBufferType&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;TINY_BUFFER&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="n"&gt;D_ASSERT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;block_memory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetReaders&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;new_readers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;block_memory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DecrementReaders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_readers&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&lt;span class="n"&gt;VerifyZeroReaders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;block_memory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MustAddToEvictionQueue&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&#9;&lt;span class="n"&gt;purge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;buffer_pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddToEvictionQueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&#9;&lt;span class="n"&gt;block_memory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;// We do not have to keep the handle locked while purging.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;purge&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="n"&gt;PurgeQueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#10; &lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;p&gt;Three things:&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;&lt;strong&gt;Tiny buffers return early.&lt;/strong&gt; They were never added to the pool, so there is nothing&#10;to unpin. (And, as we saw, that is why their reader counter is allowed to wrap.)&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;&lt;strong&gt;When the count hits zero, the block goes on the eviction queue.&lt;/strong&gt; Note the order:&#10;the count is decremented &lt;em&gt;first&lt;/em&gt;, and only then is the block offered to the sweeper.&#10;That ordering is what makes the counter a valid hint.&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;&lt;strong&gt;The purge happens outside the lock.&lt;/strong&gt; The comment says it: &amp;ldquo;We do not have to keep the&#10;handle locked while purging.&amp;rdquo; A purge is a full sweep of the eviction queue — it can&#10;take a while, and holding the block&amp;rsquo;s lock through it would block every other thread&#10;that wants to pin the same block. The &lt;code&gt;purge&lt;/code&gt; flag is set under the lock; the call&#10;happens after the lock is released.&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;And here is where the handle gives up its ownership:&lt;/p&gt;&#10;&lt;div class="code-block"&gt;&#10; &lt;div class="code-block-head"&gt;&#10; &lt;span class="code-lang"&gt;cpp&lt;/span&gt;&#10; &lt;button class="code-copy" type="button" data-copy&gt;Copy&lt;/button&gt;&#10; &lt;/div&gt;&#10; &lt;div class="code-block-body"&gt;&#10; &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// src/storage/buffer/buffer_handle.cpp:35&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;BufferHandle&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Destroy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;handle&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;IsValid&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;GetMemory&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;GetBufferManager&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;Unpin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reset&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;nullptr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#10; &lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;p&gt;&lt;code&gt;Unpin&lt;/code&gt; first, then &lt;code&gt;handle.reset()&lt;/code&gt;. The reset is what drops the &lt;code&gt;shared_ptr&lt;/code&gt; — and if&#10;that was the last reference to the &lt;code&gt;BlockMemory&lt;/code&gt;, the bytes are freed right there. If the&#10;block was still in use elsewhere, the &lt;code&gt;shared_ptr&lt;/code&gt; count simply stays above zero and the&#10;bytes survive.&lt;/p&gt;&#10;&lt;p&gt;Note the order: &lt;code&gt;Unpin&lt;/code&gt; &lt;em&gt;before&lt;/em&gt; &lt;code&gt;reset&lt;/code&gt;. If it were the other way round, the&#10;&lt;code&gt;BlockMemory&lt;/code&gt; could be destroyed before &lt;code&gt;Unpin&lt;/code&gt; had decremented the counter, and&#10;&lt;code&gt;Unpin&lt;/code&gt; would be touching freed memory.&lt;/p&gt;&#10;&lt;h2 id="costs-and-trade-offs"&gt;Costs and trade-offs&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;&lt;strong&gt;The reference counting is an atomic increment on the hot path.&lt;/strong&gt; Every &lt;code&gt;Pin&lt;/code&gt; that&#10;finds the block already loaded does one &lt;code&gt;shared_from_this()&lt;/code&gt; (an atomic increment on the&#10;&lt;code&gt;BlockHandle&lt;/code&gt;&amp;rsquo;s control block) and one &lt;code&gt;shared_ptr&lt;/code&gt; copy into the &lt;code&gt;BufferHandle&lt;/code&gt;. Every&#10;&lt;code&gt;Unpin&lt;/code&gt; does the matching decrement. On a hot scan, that is a couple of atomic&#10;read-modify-writes per block — cheap, but not free. It is worth it because it replaces&#10;a &lt;em&gt;correctness&lt;/em&gt; mechanism (locking, reference counting by hand, hazard pointers) with a&#10;&lt;em&gt;safety&lt;/em&gt; mechanism (the type system).&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;&lt;strong&gt;&lt;code&gt;shared_ptr&lt;/code&gt; is not free in code size either.&lt;/strong&gt; The &lt;code&gt;enable_shared_from_this&lt;/code&gt; base&#10;class on &lt;code&gt;BlockHandle&lt;/code&gt;, the &lt;code&gt;weak_ptr&lt;/code&gt; accessor for the eviction queue, the&#10;&lt;code&gt;ColumnBindingReplacer&lt;/code&gt;-style plumbing — all of it exists because the block is a&#10;&lt;code&gt;shared_ptr&lt;/code&gt; citizen.&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;&lt;strong&gt;The &lt;code&gt;readers&lt;/code&gt; counter is still worth keeping.&lt;/strong&gt; It is an &lt;code&gt;atomic&amp;lt;int32_t&amp;gt;&lt;/code&gt; with&#10;&lt;code&gt;relaxed&lt;/code&gt; ordering, and it lets the eviction sweeper skip pinned blocks without taking&#10;a lock and without constructing a &lt;code&gt;shared_ptr&lt;/code&gt; from the weak one. On a pool with&#10;thousands of blocks, most of which may be pinned, that saves a lot of lock traffic.&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;&lt;strong&gt;The counter is allowed to lie.&lt;/strong&gt; Tiny buffers wrap it. The &lt;code&gt;relaxed&lt;/code&gt; ordering means&#10;concurrent increments can lose a count. Both are fine &lt;em&gt;because&lt;/em&gt; nothing depends on its&#10;exactness. This is the design paying off: an approximate counter is cheap and safe, and&#10;a precise counter would need a lock.&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;&lt;strong&gt;The &lt;code&gt;Pin&lt;/code&gt; path takes the block lock at least once and often twice.&lt;/strong&gt; The&#10;double-checked pattern exists because the eviction step in between is slow. If the&#10;block was already loaded, only the first lock is taken.&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;&lt;strong&gt;The deadlock hazard is real and is handled by a comment and by scope.&lt;/strong&gt; Returning a&#10;handle whose destructor takes the same lock is the kind of bug you find in production&#10;once. The fix here — an inner scope — is subtle enough to deserve the three-line&#10;comment that explains it.&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="the-bottom-line"&gt;The bottom line&lt;/h2&gt;&#10;&lt;p&gt;There are two ways to keep a block alive while someone reads it.&lt;/p&gt;&#10;&lt;p&gt;The first is a counter: &amp;ldquo;readers: 3, do not evict&amp;rdquo;. The second is ownership: &amp;ldquo;here is a&#10;&lt;code&gt;shared_ptr&lt;/code&gt;; the memory is yours until you let go of it&amp;rdquo;. The first requires every&#10;participant to agree on the protocol and to update the counter at exactly the right&#10;moment; the second requires nothing but the discipline to use &lt;code&gt;shared_ptr&lt;/code&gt; correctly.&lt;/p&gt;&#10;&lt;p&gt;DuckDB uses the second for safety and the first for speed, and it is explicit about which&#10;is which. The &lt;code&gt;readers&lt;/code&gt; counter is &lt;code&gt;relaxed&lt;/code&gt;, is allowed to wrap, and is consulted only to&#10;decide whether to bother taking a lock. The &lt;code&gt;shared_ptr&lt;/code&gt; chain is the actual guarantee:&#10;&lt;code&gt;BufferHandle&lt;/code&gt; → &lt;code&gt;BlockHandle&lt;/code&gt; → &lt;code&gt;BlockMemory&lt;/code&gt; → &lt;code&gt;FileBuffer&lt;/code&gt; → the bytes, with a&#10;&lt;code&gt;shared_ptr&lt;/code&gt; at every level that has a lifetime to protect.&lt;/p&gt;&#10;&lt;p&gt;The general lesson: &lt;strong&gt;if you need a lock to make your data structure safe, you probably&#10;have the wrong data structure.&lt;/strong&gt; A lock-free &lt;code&gt;shared_ptr&lt;/code&gt; is not as free as a raw pointer,&#10;but it is free &lt;em&gt;enough&lt;/em&gt;, and it buys you the freedom to let the sweeper guess wrong&#10;occasionally without corrupting anything.&lt;/p&gt;&#10;</content:encoded></item></channel></rss>