<?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/"><channel><title>Demonstration on CS Theorems</title><link>https://cs.lozic.me/kinds/demonstration/</link><description>Recent content in Demonstration on CS Theorems</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Fri, 24 Dec 2027 12:00:00 +0100</lastBuildDate><atom:link href="https://cs.lozic.me/kinds/demonstration/index.xml" rel="self" type="application/rss+xml"/><item><title>Mutual Exclusion Without Hardware Support</title><link>https://cs.lozic.me/posts/t052-mutual-exclusion-without-hardware-support/</link><pubDate>Fri, 24 Dec 2027 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t052-mutual-exclusion-without-hardware-support/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;Two threads increment a shared counter a million times each. The final value is
1,374,522.&lt;/p&gt;
&lt;p&gt;You know why: the increment is a read, an add, and a write, and the interleavings
lose updates. The fix is a lock. But a lock is provided by your runtime, which
gets it from the OS, which gets it from a hardware instruction — &lt;code&gt;lock xchg&lt;/code&gt;,
&lt;code&gt;cmpxchg&lt;/code&gt;, &lt;code&gt;ldrex&lt;/code&gt;/&lt;code&gt;strex&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>Bloom Filters</title><link>https://cs.lozic.me/posts/t073-bloom-filters/</link><pubDate>Fri, 12 Nov 2027 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t073-bloom-filters/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;Every request to your service checks whether a user ID exists before doing
anything else. The check hits the database. Ninety-eight percent of the time the
answer is no, because most of the traffic is bots probing for accounts that were
never created.&lt;/p&gt;</description></item><item><title>Consistent Hashing</title><link>https://cs.lozic.me/posts/t072-consistent-hashing/</link><pubDate>Fri, 29 Oct 2027 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t072-consistent-hashing/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;You shard a cache across ten servers with the obvious rule:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;servers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;servers&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;&lt;p&gt;It works. Then you add an eleventh server, and &lt;code&gt;% 10&lt;/code&gt; becomes &lt;code&gt;% 11&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Every key now maps somewhere else. Not one tenth of them — essentially all of
them. A key landing on the same server after the change is a coincidence with
probability about $1/11$, so roughly 91% of your cache is instantly invalid.
Every request misses, every miss hits the database, and the database, sized for
a 95% cache hit rate, now receives twenty times its provisioned load and falls
over.&lt;/p&gt;</description></item><item><title>Paxos, Raft, and the Shape of Consensus</title><link>https://cs.lozic.me/posts/t064-paxos-raft-and-the-shape-of-consensus/</link><pubDate>Fri, 20 Aug 2027 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t064-paxos-raft-and-the-shape-of-consensus/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;Your database has two nodes that both believe they are the primary.&lt;/p&gt;
&lt;p&gt;Each has been accepting writes. Each has a coherent log. Neither has crashed.
The old primary was declared dead by a health check that timed out during a GC
pause, a new one was elected, and then the old one woke up still holding what it
thinks is a valid lease. You now have two divergent histories of the same data
and no principled way to merge them, because both contain acknowledged writes
that customers were told had succeeded.&lt;/p&gt;</description></item><item><title>Universal Hashing</title><link>https://cs.lozic.me/posts/t104-universal-hashing/</link><pubDate>Fri, 23 Apr 2027 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t104-universal-hashing/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;Your service went down under a hash collision attack.&lt;/p&gt;
&lt;p&gt;Somebody noticed your web framework put POST parameters into a hash table, found
thousands of distinct keys colliding under its hash function, and posted a form
with 20,000 of them. Every insert walked a chain. Quadratic behaviour, one CPU
pinned per request, service dead. This actually happened, across PHP, Python,
Ruby, Java and .NET in 2011, and again against Rust&amp;rsquo;s default &lt;code&gt;HashMap&lt;/code&gt; before
it switched to SipHash.&lt;/p&gt;</description></item></channel></rss>