<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Arpit Bhayani</title>
    <description>The latest articles on DEV Community by Arpit Bhayani (@arpit_bhayani).</description>
    <link>https://dev.to/arpit_bhayani</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F293593%2Ff5aa7e13-d00c-4f17-88de-54ab134ce53c.jpg</url>
      <title>DEV Community: Arpit Bhayani</title>
      <link>https://dev.to/arpit_bhayani</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/arpit_bhayani"/>
    <language>en</language>
    <item>
      <title>Bitcask - a log-structured fast KV store</title>
      <dc:creator>Arpit Bhayani</dc:creator>
      <pubDate>Sun, 19 Jul 2020 14:39:34 +0000</pubDate>
      <link>https://dev.to/arpit_bhayani/bitcask-a-log-structured-fast-kv-store-1mic</link>
      <guid>https://dev.to/arpit_bhayani/bitcask-a-log-structured-fast-kv-store-1mic</guid>
      <description>&lt;p&gt;Bitcask is one of the most efficient embedded Key-Value (KV) Databases designed to handle production-grade traffic. The paper that introduced Bitcask to the world says it is a &lt;em&gt;&lt;a href="https://en.wikipedia.org/wiki/Log-structured_file_system"&gt;Log-Structured&lt;/a&gt; &lt;a href="https://en.wikipedia.org/wiki/Hash_table"&gt;Hash Table&lt;/a&gt; for Fast Key/Value Data&lt;/em&gt; which, in a simpler language, means that the data will be written sequentially to an append-only log file and there will be pointers for each &lt;code&gt;key&lt;/code&gt; pointing to the &lt;code&gt;position&lt;/code&gt; of its log entry. Building a KV store off the append-only log files seems like a really weird design choice, but Bitcask does not only make it efficient but it also gives a really high Read-Write throughput.&lt;/p&gt;

&lt;p&gt;Bitcask was introduced as the backend for a distributed database named &lt;a href="https://riak.com/"&gt;Riak&lt;/a&gt; in which each node used to run one instance of Bitcask to hold the data that it was responsible for. In this essay, we take a detailed look into Bitcask, its design, and find the secret sauce that makes it so performant.&lt;/p&gt;

&lt;h1&gt;
  
  
  Design of Bitcask
&lt;/h1&gt;

&lt;p&gt;Bitcask uses a lot of principles from &lt;a href="https://en.wikipedia.org/wiki/Log-structured_file_system"&gt;log-structured file systems&lt;/a&gt; and draws inspiration from a number of designs that involve log file merging, for example - merging in LSM Trees. It essentially is just a directory of append-only (log) files with a fixed structure and an in-memory index holding the keys mapped to a bunch of information necessary for point lookups - referring to the entry in the datafile.&lt;/p&gt;

&lt;h2&gt;
  
  
  Datafiles
&lt;/h2&gt;

&lt;p&gt;Datafiles are append-only log files that hold the KV pairs along with some meta-information. A single Bitcask instance could have many datafiles, out of which just one will be active and opened for writing, while the others are considered immutable and are only used for reads.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lGvhaAj3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/87866701-78fdb800-c9a2-11ea-9c35-9a706ac96d97.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lGvhaAj3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/87866701-78fdb800-c9a2-11ea-9c35-9a706ac96d97.png" alt="Bitcask Datafiles"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Each entry in the datafile has a fixed structure illustrated above and it stores &lt;code&gt;crc&lt;/code&gt;, &lt;code&gt;timestamp&lt;/code&gt;, &lt;code&gt;key_size&lt;/code&gt;, &lt;code&gt;value_size&lt;/code&gt;, actual &lt;code&gt;key&lt;/code&gt;, and the actual &lt;code&gt;value&lt;/code&gt;. All the write operations - create, update and delete - made on the engine translates into entries in this active datafile. When this active datafile meets a size threshold, it is closed and a new active datafile is created; and as stated earlier, when closed (intentionally or unintentionally), the datafile is considered immutable and is never opened for writing again.&lt;/p&gt;

&lt;h2&gt;
  
  
  KeyDir
&lt;/h2&gt;

&lt;p&gt;KeyDir is an in-memory hash table that stores all the keys present in the Bitcask instance and maps it to the offset in the datafile where the log entry (value) resides; thus facilitating the point lookups. The mapped value in the Hash Table is a structure that holds &lt;code&gt;file_id&lt;/code&gt;, &lt;code&gt;offset&lt;/code&gt;, and some meta-information like &lt;code&gt;timestamp&lt;/code&gt;, as illustrated below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LrTcJ1CF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/87866707-96cb1d00-c9a2-11ea-9730-fc7f8cb79b92.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LrTcJ1CF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/87866707-96cb1d00-c9a2-11ea-9730-fc7f8cb79b92.png" alt="Bitcask KeyDir"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Operations on Bitcask
&lt;/h1&gt;

&lt;p&gt;Now that we have seen the overall design and components of Bitcask, we can jump into exploring the operations that it supports and details of their implementations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Putting a new Key Value
&lt;/h3&gt;

&lt;p&gt;When a new KV pair is submitted to be stored in the Bitcask, the engine first appends it to the active datafile and then creates a new entry in the KeyDir specifying the offset and file where the value is stored. Both of these actions are performed atomically which means either the entry is made in both the structures or none.&lt;/p&gt;

&lt;p&gt;Putting a new Key-Value pair requires just one atomic operation encapsulating one disk write and a few in-memory access and updates. Since the active datafile is an append-only file, the disk write operation does not have to perform any disk seek whatsoever making the write operate at an optimum rate providing a high write throughput.&lt;/p&gt;

&lt;h3&gt;
  
  
  Updating an existing Key Value
&lt;/h3&gt;

&lt;p&gt;This KV store does not support partial update, out of the box, but it does support full value replacement. Hence the update operation is very similar to putting a new KV pair, the only change being instead of creating an entry in KeyDir, the existing entry is updated with the new position in, possibly, the new datafile.&lt;/p&gt;

&lt;p&gt;The entry corresponding to the old value is now dangling and will be garbage collected explicitly during merging and compaction.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deleting a Key
&lt;/h3&gt;

&lt;p&gt;Deleting a key is a special operation where the engine atomically appends a new entry in the active datafile with value equalling a tombstone value, denoting deletion, and deleting the entry from the in-memory KeyDir. The tombstone value is chosen as something very unique so that it does not interfere with the existing value space.&lt;/p&gt;

&lt;p&gt;Delete operation, just like the update operation, is very lightweight and requires a disk write and an in-memory update. In delete operation as well, the older entries corresponding to the deleted keys are left dangling and will be garbage collected explicitly during merging and compaction.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reading a Key-Value
&lt;/h3&gt;

&lt;p&gt;Reading a KV pair from the store requires the engine to first find the datafile and the offset within it for the given key; which is done using the KeyDir. Once that information is available the engine then performs one disk read from the corresponding datafile at the offset to retrieve the log entry. The correctness of the value retrieved is checked against the CRC stored and the value is then returned to the client.&lt;/p&gt;

&lt;p&gt;The operation is inherently fast as it requires just one disk read and a few in-memory accesses, but it could be made faster using Filesystem read-ahead cache.&lt;/p&gt;

&lt;h1&gt;
  
  
  Merge and Compaction
&lt;/h1&gt;

&lt;p&gt;As we have seen during Update and Delete operations the old entries corresponding to the key remain untouched and dangling and this leads to Bitcask consuming a lot of disk space. In order to make things efficient for the disk utilization the engine once a while compacts the older closed datafiles into one or many merged files having the same structure as the existing datafiles.&lt;/p&gt;

&lt;p&gt;The merge process iterates over all the immutable files in the Bitcask and produces a set of datafiles having only &lt;em&gt;live&lt;/em&gt; and &lt;em&gt;latest&lt;/em&gt; versions of each present key. This way the unused and non-existent keys are ignored from the newer datafiles saving a bunch of disk space. Since the record now exists in a different merged datafile and at a new offset, its entry in KeyDir needs an atomic updation.&lt;/p&gt;

&lt;h1&gt;
  
  
  Performant bootup
&lt;/h1&gt;

&lt;p&gt;If the Bitcask crashes and needs a boot-up, it will have to read all the datafiles and build a new KeyDir. Merging and compaction here do help as it reduces the need to read data that is eventually going to be evicted. But there is another operation that could help in making the boot times faster.&lt;/p&gt;

&lt;p&gt;For every datafile a &lt;em&gt;hint&lt;/em&gt; file is created which holds everything in the datafile except the value i.e. it holds the key and its meta-information. This &lt;em&gt;hint&lt;/em&gt; file, hence, is just a file containing all the keys from the corresponding datafile. This &lt;em&gt;hint&lt;/em&gt; file is very small in size and hence by reading this file the engine could quickly create the entire KeyDir and complete the bootup process faster.&lt;/p&gt;

&lt;h1&gt;
  
  
  Strengths and Weaknesses of Bitcask
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Strengths
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Low latency for read and write operations&lt;/li&gt;
&lt;li&gt;High Write Throughput&lt;/li&gt;
&lt;li&gt;Single disk seek to retrieve any value&lt;/li&gt;
&lt;li&gt;Predictable lookup and insert performance&lt;/li&gt;
&lt;li&gt;Crash recovery is fast and bounded&lt;/li&gt;
&lt;li&gt;Backing up is easy - Just copy the directory would suffice&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Weaknesses
&lt;/h2&gt;

&lt;p&gt;The KeyDir holds all the keys in memory at all times and this adds a huge constraint on the system that it needs to have enough memory to contain the entire keyspace along with other essentials like Filesystem buffers. Thus the limiting factor for a Bitcask is the limited RAM available to hold the KeyDir.&lt;/p&gt;

&lt;p&gt;Although this weakness sees a major one but the solution to this is fairly simple. We can typically shard the keys and scale it horizontally without losing much of the basic operations like Create, Read, Update, and Delete.&lt;/p&gt;

&lt;h1&gt;
  
  
  References
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://riak.com/assets/bitcask-intro.pdf"&gt;Bitcask Paper&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Bitcask"&gt;Bitcask - Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://highscalability.com/blog/2011/1/10/riaks-bitcask-a-log-structured-hash-table-for-fast-keyvalue.html/"&gt;Riak's Bitcask - High Scalability&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://topic.alibabacloud.com/a/implementation-of-the-bitcask-storage-model-merge-and-hint-files_8_8_31516931.html"&gt;Implementation of the Bitcask storage model-merge and hint files&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Other articles that you might like
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/consistent-hashing"&gt;Consistent Hashing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/phi-accrual"&gt;Phi φ Accrual Failure Detection&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/copy-on-write"&gt;Copy-on-Write Semantics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/mysql-cache"&gt;What makes MySQL LRU cache scan resistant&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;If you liked what you read, consider subscribing to my weekly newsletter at &lt;a href="https://arpit.substack.com/"&gt;arpit.substack.com&lt;/a&gt; where, once a week, I write an essay about programming languages internals, or a deep dive on some super-clever algorithm, or just a few tips on building highly scalable distributed systems.&lt;/p&gt;

&lt;p&gt;You can always find me browsing through twitter &lt;a href="https://twitter.com/arpit_bhayani"&gt;@arpit_bhayani&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>database</category>
    </item>
    <item>
      <title>Phi φ Accrual Failure Detection</title>
      <dc:creator>Arpit Bhayani</dc:creator>
      <pubDate>Sun, 12 Jul 2020 09:50:56 +0000</pubDate>
      <link>https://dev.to/arpit_bhayani/phi-accrual-failure-detection-1aj1</link>
      <guid>https://dev.to/arpit_bhayani/phi-accrual-failure-detection-1aj1</guid>
      <description>&lt;p&gt;One of the most important virtues of any distributed system is its ability to detect failures in any of its subsystems before things go havoc. Early detection of failures helps in taking preventive actions and ensuring that the system stays fault-tolerant. The conventional way of failure detection is by using a bunch of heartbeat messages with a fixed timeout, indicating if a subsystem is down or not.&lt;/p&gt;

&lt;p&gt;In this essay, we take a look into an adaptive failure detection algorithm called &lt;em&gt;Phi Accrual Failure Detection&lt;/em&gt;, which was introduced in a &lt;a href="https://pdfs.semanticscholar.org/11ae/4c0c0d0c36dc177c1fff5eb84fa49aa3e1a8.pdf"&gt;paper&lt;/a&gt; by Naohiro Hayashibara, Xavier Défago, Rami Yared, and Takuya Katayama. The algorithm uses historical heartbeat information to make the threshold adaptive. Instead of generating a binary value, like conventional methods, it generates continuous values suggesting the confidence level it has in stating if the system crashed or not.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conventional Failure Detection
&lt;/h1&gt;

&lt;p&gt;Accurately detecting failures is an impossible problem to solve as we cannot ever say if a system crashed or is just very slow in responding. Conventional Failure Detection algorithms output a boolean value stating if the system is down or not; there is no middle ground.&lt;/p&gt;

&lt;h2&gt;
  
  
  Heartbeats with constants timeouts
&lt;/h2&gt;

&lt;p&gt;The conventional Failure Detection algorithms use &lt;em&gt;heartbeat&lt;/em&gt; messages with a fixed timeout in order to determine if a system is alive or not. The monitored system periodically sends a heartbeat message to the monitoring system, informing that it is still alive. The monitoring system will suspect that the process crashed if it fails to receive any heartbeat message within a configured timeout period.&lt;/p&gt;

&lt;p&gt;Here the value of timeout is very crucial as keeping it short means we detect failures quickly but with a lot of false positives; and while keeping it long means we reduce the false positives but the detection time takes a toll.&lt;/p&gt;

&lt;h1&gt;
  
  
  Phi Accrual Failure Detection
&lt;/h1&gt;

&lt;p&gt;Phi Accrual Failure Detection is an adaptive Failure Detection algorithm that provides a building block to implementing failure detectors in any distributed system. A generic Accrual Failure Detector, instead of providing output as a boolean (system being up or down), outputs the suspicion information (level) on a continuous scale such that higher the suspicion value, the higher are the chances that the system is down.&lt;/p&gt;

&lt;h2&gt;
  
  
  Detailing φ
&lt;/h2&gt;

&lt;p&gt;We define φ as the suspicion level output by this failure detector and as the algorithm is adaptive, the value will be dynamic and will reflect the current network conditions and system behavior. As we established earlier - lower are the chances of receiving the heartbeat, higher are the chances that the system crashed hence higher should be the value of φ; the details around expressing φ mathematically are as illustrated below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---whIau0e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/87240784-469c0a00-c43a-11ea-8689-9dc41eb1ccf1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---whIau0e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/87240784-469c0a00-c43a-11ea-8689-9dc41eb1ccf1.png" alt="Phi Accrual Failure Detection"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The illustration above mathematically expresses our establishments and shows how we can use &lt;code&gt;-log10(x)&lt;/code&gt; function applied to the probability to get a gradual negative slope indicating a decline in the value of φ. We observe how, as the probability of receiving heartbeat increases, the value of φ decreases and approaches &lt;code&gt;0&lt;/code&gt;, and when the probability of receiving heartbeat decreases and approaches &lt;code&gt;0&lt;/code&gt;, the value of φ tends to infinity ∞.&lt;/p&gt;

&lt;p&gt;The φ value computed using &lt;code&gt;-log10(x)&lt;/code&gt; also suggests our likeliness of making mistakes decreases exponentially as the value of φ increases. So if we say a system is down if φ crosses a certain threshold &lt;code&gt;X&lt;/code&gt; where &lt;code&gt;X&lt;/code&gt; is &lt;code&gt;1&lt;/code&gt;, it implies that our decision will be contradicted in the future by the reception of a late heartbeat is about &lt;code&gt;10%&lt;/code&gt;. For &lt;code&gt;X = 2&lt;/code&gt;, the likelihood of the mistake will be &lt;code&gt;1%&lt;/code&gt;, for &lt;code&gt;X = 3&lt;/code&gt; it will be &lt;code&gt;0.1%&lt;/code&gt;, and so on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Estimating the probability of receiving another heartbeat
&lt;/h2&gt;

&lt;p&gt;Now that we have defined what φ is, we need a way to compute the probability of receiving another heartbeat given we have seen some heartbeats before. This probability is proportional to the probability that the heartbeat will arrive more than &lt;code&gt;t&lt;/code&gt; units after the previous one i.e. longer the wait lesser are the chances of receiving the heartbeat.&lt;/p&gt;

&lt;p&gt;In order to implement this, we keep a sampled Sliding Window holding arrival times of past heartbeats. Whenever a new heartbeat arrives, its arrival time is stored into the window, and the data regarding the oldest heartbeat is deleted.&lt;/p&gt;

&lt;p&gt;We observe that the arrival intervals follow a &lt;a href="https://en.wikipedia.org/wiki/Normal_distribution"&gt;Normal Distribution&lt;/a&gt; indicating most of the heartbeats arrive within a specific range while there are a few that arrive late due to various network or system conditions. From the information stored in the window, we can easily compute the arrival intervals, mean, and variance which we require to estimate the probability.&lt;/p&gt;

&lt;p&gt;Since arrival intervals follow a Normal Distribution, we can integrate the &lt;a href="https://en.wikipedia.org/wiki/Probability_density"&gt;Probability Density Function&lt;/a&gt; over the interval &lt;code&gt;(t, ∞)&lt;/code&gt; to get the probability of receiving heartbeat after &lt;code&gt;t&lt;/code&gt; units of time. Thus the expression for deriving this can be illustrated below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4pkYMawT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/87231591-fbe8a680-c3d5-11ea-9427-d4cd66e8e717.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4pkYMawT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/87231591-fbe8a680-c3d5-11ea-9427-d4cd66e8e717.png" alt="Estimating probability of receiving another heartbeat"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We observe that if the process actually crashes, the value is guaranteed to accrue (accumulate) over time and will tend to infinity ∞. Since the accrual failure detectors output value in a continuous range, we need to explicitly define thresholds crossing which we say that the system crashed.&lt;/p&gt;

&lt;h1&gt;
  
  
  Benefits of using Accrual Failure Detectors
&lt;/h1&gt;

&lt;p&gt;We can define multiple thresholds, crossing which we can take precautionary measures defined for it. As the threshold becomes steeper the action could become more drastic. Another major benefit of using this system is that it favors a nearly complete decoupling between application requirements and monitoring as it leaves the applications to define threshold according to their QoS requirements.&lt;/p&gt;

&lt;h1&gt;
  
  
  References
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://pdfs.semanticscholar.org/11ae/4c0c0d0c36dc177c1fff5eb84fa49aa3e1a8.pdf"&gt;The φ Accrual Failure Detector&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Normal_distribution"&gt;Normal Distribution&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Other articles that you might like
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/copy-on-write"&gt;Copy-on-Write Semantics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/better-programmer"&gt;Eight rituals to be a better programmer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/isolation-forest"&gt;Isolation Forest algorithm for anomaly detection&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/inheritance-c"&gt;Powering inheritance in C using structure composition&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;If you liked what you read, consider subscribing to my weekly newsletter at &lt;a href="https://arpitbhayani.me/newsletter"&gt;arpitbhayani.me/newsletter&lt;/a&gt; where, once a week, I write an essay about programming languages internals, or a deep dive on some super-clever algorithm, or just a few tips on building highly scalable distributed systems.&lt;/p&gt;

&lt;p&gt;You can always find me browsing through twitter &lt;a href="https://twitter.com/arpit_bhayani"&gt;@arpit_bhayani&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>distributedsystems</category>
    </item>
    <item>
      <title>Deciphering Single-byte XOR Ciphertext</title>
      <dc:creator>Arpit Bhayani</dc:creator>
      <pubDate>Sun, 21 Jun 2020 13:22:09 +0000</pubDate>
      <link>https://dev.to/arpit_bhayani/deciphering-single-byte-xor-ciphertext-9kb</link>
      <guid>https://dev.to/arpit_bhayani/deciphering-single-byte-xor-ciphertext-9kb</guid>
      <description>&lt;p&gt;Encryption is a process of encoding messages such that it can only be read and understood by the intended parties. The process of extracting the original message from an encrypted one is called Decryption. Encryption usually scrambles the original message using a key, called encryption key, that the involved parties agree on.&lt;/p&gt;

&lt;p&gt;The strength of an encryption algorithm is determined by how hard it would be to extract the original message without knowing the encryption key. Usually, this depends on the number of bits in the key - bigger the key, the longer it takes to decrypt the enciphered data.&lt;/p&gt;

&lt;p&gt;In this essay, we will work with a very simple cipher (encryption algorithm) that uses an encryption key with a size of one byte, and try to decipher the ciphered text and retrieve the original message without knowing the encryption key. The problem statement, defined above, is based on &lt;a href="https://cryptopals.com/sets/1/challenges/3"&gt;Cryptopals Set 1 Challenge 3&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Single-byte XOR cipher
&lt;/h1&gt;

&lt;p&gt;The Single-byte XOR cipher algorithm works with an encryption key of size 1 byte - which means the encryption key could be one of the possible 256 values of a byte. Now we take a detailed look at how the encryption and decryption processes look like for this cipher.&lt;/p&gt;

&lt;h2&gt;
  
  
  Encryption
&lt;/h2&gt;

&lt;p&gt;As part of the encryption process, the original message is iterated bytewise and every single byte &lt;code&gt;b&lt;/code&gt; is XORed with the encryption key &lt;code&gt;key&lt;/code&gt; and the resultant stream of bytes is again translated back as characters and sent to the other party. These encrypted bytes need not be among the usual printable characters and should ideally be interpreted as a stream of bytes. Following is the python-based implementation of the encryption process.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;single_byte_xor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bytes&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="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="s"&gt;"""Given a plain text `text` as bytes and an encryption key `key` as a byte
    in range [0, 256) the function encrypts the text by performing
    XOR of all the bytes and the `key` and returns the resultant.
    """&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As an example, we can try to encrypt the plain text - &lt;code&gt;abcd&lt;/code&gt; - with encryption key &lt;code&gt;69&lt;/code&gt; and as per the algorithm, we perform XOR bytewise on the given plain text. For character &lt;code&gt;a&lt;/code&gt;, the byte i.e. ASCII value is &lt;code&gt;97&lt;/code&gt; which when XORed with &lt;code&gt;69&lt;/code&gt; results in &lt;code&gt;36&lt;/code&gt; whose character equivalent is &lt;code&gt;$&lt;/code&gt;, similarly for &lt;code&gt;b&lt;/code&gt; the encrypted byte is &lt;code&gt;'&lt;/code&gt;, for &lt;code&gt;c&lt;/code&gt; it is &lt;code&gt;&amp;amp;&lt;/code&gt; and for &lt;code&gt;d&lt;/code&gt; it is &lt;code&gt;!&lt;/code&gt;. Hence when &lt;code&gt;abcd&lt;/code&gt; is encrypted using single-byte XOR cipher and encryption key &lt;code&gt;69&lt;/code&gt;, the resultant ciphertext i.e. the encrypted message is &lt;code&gt;$'&amp;amp;!&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NQsN0GAA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/85209379-0b377f80-b355-11ea-8206-54ad558b4a6f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NQsN0GAA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/85209379-0b377f80-b355-11ea-8206-54ad558b4a6f.png" alt="https://user-images.githubusercontent.com/4745789/85209379-0b377f80-b355-11ea-8206-54ad558b4a6f.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Decryption
&lt;/h2&gt;

&lt;p&gt;Decryption is the process of extracting the original message from the encrypted ciphertext given the encryption key. XOR has a &lt;a href="https://brainly.in/question/3038497"&gt;property&lt;/a&gt; - if &lt;code&gt;a = b ^ c&lt;/code&gt; then &lt;code&gt;b = a ^ c&lt;/code&gt;, hence the decryption process is exactly the same as the encryption i.e. we iterate through the encrypted message bytewise and XOR each byte with the encryption key - the resultant will be the original message.&lt;/p&gt;

&lt;p&gt;Since encryption and decryption both have an exact same implementation - we pass the ciphertext to the function &lt;code&gt;single_byte_xor&lt;/code&gt;, defined above, to get the original message back.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;single_byte_xor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;b"$'&amp;amp;!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;69&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="s"&gt;b'abcd'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Deciphering without the encryption key
&lt;/h1&gt;

&lt;p&gt;Things become really interesting when we have to recover the original message given the ciphertext and having no knowledge of the encryption key; although we do know the encryption algorithm.&lt;/p&gt;

&lt;p&gt;As a sample plain text, we take the last couple of messages, sent across on their German military radio network during World War II. These messages were intercepted and decrypted by the British troops. During wartime, the messages were encrypted using &lt;a href="https://en.wikipedia.org/wiki/Enigma_machine"&gt;Enigma Machine&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Alan_Turing"&gt;Alan Turing&lt;/a&gt; famously &lt;a href="https://www.iwm.org.uk/history/how-alan-turing-cracked-the-enigma-code"&gt;cracked the Enigma Code&lt;/a&gt; (similar to encryption key) that was used to encipher German messages.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KjpX1QXs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/85209533-72096880-b356-11ea-8a84-97f2feb86b44.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KjpX1QXs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/85209533-72096880-b356-11ea-8a84-97f2feb86b44.png" alt="https://user-images.githubusercontent.com/4745789/85209533-72096880-b356-11ea-8a84-97f2feb86b44.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In this essay, instead of encrypting the message using the Enigma Code, we are going to use Single-byte XOR cipher and try to recover the original message back without any knowledge of the encryption key.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here, we assume that the original message, to be encrypted, is a genuine English lowercased sentence. The ciphertext that we would try to decipher can be obtained as&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;82&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;plain_text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;b'british troops entered cuxhaven at 1400 on 6 may - from now on all radio traffic will cease - wishing you all the best. lt kunkel.'&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;single_byte_xor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plain_text&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="s"&gt;b'0 ;&amp;amp;;!:r&amp;amp; =="!r7&amp;lt;&amp;amp;7 76r1&lt;/span&gt;&lt;span class="se"&gt;\'&lt;/span&gt;&lt;span class="s"&gt;*:3$7&amp;lt;r3&amp;amp;rcfbbr=&amp;lt;rdr?3+r&lt;/span&gt;&lt;span class="se"&gt;\x7f&lt;/span&gt;&lt;span class="s"&gt;r4 =?r&amp;lt;=%r=&amp;lt;r3&amp;gt;&amp;gt;r 36;=r&amp;amp; 344;1r%;&amp;gt;&amp;gt;r173!7r&lt;/span&gt;&lt;span class="se"&gt;\x7f&lt;/span&gt;&lt;span class="s"&gt;r%;!:;&amp;lt;5r+=&lt;/span&gt;&lt;span class="se"&gt;\'&lt;/span&gt;&lt;span class="s"&gt;r3&amp;gt;&amp;gt;r&amp;amp;:7r07!&amp;amp;|r&amp;gt;&amp;amp;r9&lt;/span&gt;&lt;span class="se"&gt;\'&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;97&amp;gt;|'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Bruteforce
&lt;/h2&gt;

&lt;p&gt;There are a very limited number of possible encryption keys - 256 to be exact - we can, very conveniently, go for the Bruteforce approach and try to decrypt the ciphered text with every single one of it. So we start iterating over all keys in the range &lt;code&gt;[0, 256)&lt;/code&gt; and decrypt the ciphertext and see which one resembles the original message the most.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sRgUb9K5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/85209704-ad586700-b357-11ea-8b7c-4d4616af609a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sRgUb9K5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/85209704-ad586700-b357-11ea-8b7c-4d4616af609a.png" alt="https://user-images.githubusercontent.com/4745789/85209704-ad586700-b357-11ea-8b7c-4d4616af609a.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the illustration above, we see that the message decrypted through key &lt;code&gt;82&lt;/code&gt; is, in fact, our original message, while the other retrieved plain texts look scrambled and garbage. Doing this visually is very easy; we, as humans, are able to comprehend familiarity but how will a computer recognize this?&lt;/p&gt;

&lt;p&gt;We need a way to quantify the closeness of a text to a genuine English sentence. Closer the decrypted text is to be a genuine English sentence, the closer it would be to our original plain text.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We can do this only because of our assumption - that the original plain text is a genuine English sentence.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  ETAOIN SHRDLU
&lt;/h2&gt;

&lt;p&gt;Letter Frequency is the number of times letters of an alphabet appear on average in written language. In the English language the letter frequency of letter &lt;code&gt;a&lt;/code&gt; is &lt;code&gt;8.239%&lt;/code&gt;, for &lt;code&gt;b&lt;/code&gt; it is &lt;code&gt;1.505%&lt;/code&gt; which means out of 100 letters written in English, the letter &lt;code&gt;a&lt;/code&gt;, on an average, will show up &lt;code&gt;8.239%&lt;/code&gt; of times while &lt;code&gt;b&lt;/code&gt; shows up &lt;code&gt;1.505%&lt;/code&gt; of times. Letter frequency (in percentage) for other letters is as shown below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;occurance_english&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;'a'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;8.2389258&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="s"&gt;'b'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;1.5051398&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="s"&gt;'c'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;2.8065007&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="s"&gt;'d'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;4.2904556&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;'e'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;12.813865&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="s"&gt;'f'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;2.2476217&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="s"&gt;'g'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;2.0327458&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="s"&gt;'h'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;6.1476691&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;'i'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;6.1476691&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="s"&gt;'j'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.1543474&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="s"&gt;'k'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.7787989&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="s"&gt;'l'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;4.0604477&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;'m'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;2.4271893&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="s"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;6.8084376&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="s"&gt;'o'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;7.5731132&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="s"&gt;'p'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;1.9459884&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;'q'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.0958366&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="s"&gt;'r'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;6.0397268&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="s"&gt;'s'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;6.3827211&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="s"&gt;'t'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;9.1357551&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;'u'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;2.7822893&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="s"&gt;'v'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.9866131&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="s"&gt;'w'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;2.3807842&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="s"&gt;'x'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.1513210&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;'y'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;1.9913847&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="s"&gt;'z'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.0746517&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This Letter Frequency analysis is a rudimentary way for language identification in which we see if the current letter frequency distribution of a text matches the average letter frequency distribution of the English language. &lt;a href="https://en.wikipedia.org/wiki/Etaoin_shrdlu"&gt;ETAOIN SHRDLU&lt;/a&gt; is the approximate order of frequency of the 12 most commonly used letters in the English language.&lt;/p&gt;

&lt;p&gt;The following chart shows Letter Frequency analysis for decrypted plain texts with encryption keys from &lt;code&gt;79&lt;/code&gt; to &lt;code&gt;84&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9zK0gUJv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/85209804-5a32e400-b358-11ea-8e1b-2b6bb3e22868.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9zK0gUJv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/85209804-5a32e400-b358-11ea-8e1b-2b6bb3e22868.png" alt="https://user-images.githubusercontent.com/4745789/85209804-5a32e400-b358-11ea-8e1b-2b6bb3e22868.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the illustration above, we could clearly see how well the Letter Frequency distribution for encryption key &lt;code&gt;82&lt;/code&gt; fits the distribution of the English language. Now that our hypothesis holds true, we need a way to quantify this measure and we call if the Fitting Quotient.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fitting Quotient
&lt;/h2&gt;

&lt;p&gt;Fitting Quotient is the measure that suggests how well the two Letter Frequency Distributions match. Heuristically, we define the Fitting Quotient as the average of the absolute difference between the frequencies (in percentage) of letters in &lt;code&gt;text&lt;/code&gt; and the corresponding letter in the English Language. Thus having a smaller value of Fitting Quotient implies the text is closer to the English Language.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--moz9lhZb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/85219888-f2ff4900-b3c4-11ea-933a-96e26580a3fb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--moz9lhZb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/85219888-f2ff4900-b3c4-11ea-933a-96e26580a3fb.png" alt="https://user-images.githubusercontent.com/4745789/85219888-f2ff4900-b3c4-11ea-933a-96e26580a3fb.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Python-based implementation of the, above defined, Fitting Quotient is as shown below. The function first computes the relative frequency for each letter in &lt;code&gt;text&lt;/code&gt; and then takes an average of the absolute difference between the two distributions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;dist_english&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;occurance_english&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;compute_fitting_quotient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="s"&gt;"""Given the stream of bytes `text` the function computes the fitting
    quotient of the letter frequency distribution for `text` with the
    letter frequency distribution of the English language.

    The function returns the average of the absolute difference between the
    frequencies (in percentage) of letters in `text` and the corresponding
    letter in the English Language.
    """&lt;/span&gt;
    &lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;dist_text&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;&lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;ord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ch&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; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&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;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;occurance_english&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nb"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dist_english&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dist_text&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;dist_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Deciphering
&lt;/h2&gt;

&lt;p&gt;Now that we have everything we require to directly get the plain text out of the given ciphertext we wrap it in a function that iterates over all possible encryption keys in the range &lt;code&gt;[0, 256)&lt;/code&gt;, decrypts the ciphertext, computes the fitting quotient for the plain text and returns the one that minimizes the quotient as the original message. Python-based implementation of this deciphering logic is as illustrated below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;decipher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bytes&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;Tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="s"&gt;"""The function deciphers an encrypted text using Single Byte XOR and returns
    the original plain text message and the encryption key.
    """&lt;/span&gt;
    &lt;span class="n"&gt;original_text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encryption_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;min_fq&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# we generate the plain text using encryption key `k`
&lt;/span&gt;        &lt;span class="n"&gt;_text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;single_byte_xor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# we compute the fitting quotient for this decrypted plain text
&lt;/span&gt;        &lt;span class="n"&gt;_fq&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;compute_fitting_quotient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# if the fitting quotient of this generated plain text is lesser
&lt;/span&gt;        &lt;span class="c1"&gt;# than the minimum seen till now `min_fq` we update.
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;min_fq&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;_fq&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;min_fq&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;encryption_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;original_text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;min_fq&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_fq&lt;/span&gt;

    &lt;span class="c1"&gt;# return the text and key that has the minimum fitting quotient
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;original_text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encryption_key&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This approach was also tested against 100 random English sentences with random Encryption keys and it was found that this deciphering technique fared well for all the samples. The approach would fail if the sentence is very short or contains a lot of symbols. The source code for this entire deciphering process is available in a Jupyter notebook at &lt;a href="https://github.com/arpitbbhayani/decipher-single-byte-xor/blob/master/decipher-single-byte-xor.ipynb"&gt;arpitbhayani.me/decipher-single-byte-xor&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  References
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Etaoin_shrdlu"&gt;Etaoin shrdlu&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Letter_frequency"&gt;English Letter Frequency&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wiki.bi0s.in/crypto/xor/#single-byte-xor-cipher"&gt;Single-byte XOR encryption&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cryptopals.com/sets/1/challenges/3"&gt;Cryptopals Challenge - Set 1 Challenge 3&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Other articles that you might like
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/idf"&gt;All you need to know about Inverse Document Frequency&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/fast-and-efficient-pagination-in-mongodb"&gt;Fast and Efficient Pagination in MongoDB&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/how-sleepsort-helped-me-understand-concurrency-in-golang"&gt;How Sleepsort helped me understand concurrency in Golang&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/super-long-integers"&gt;How python implements super long integers?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;If you liked what you read, consider subscribing to my weekly newsletter at &lt;a href="https://arpitbhayani.me/newsletter"&gt;arpitbhayani.me/newsletter&lt;/a&gt; where, once a week, I write an essay about programming languages internals, or a deep dive on some super-clever algorithm, or just a few tips on building highly scalable distributed systems.&lt;/p&gt;

&lt;p&gt;You can always find me browsing through twitter &lt;a href="https://twitter.com/arpit_bhayani"&gt;@arpit_bhayani&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>python</category>
      <category>security</category>
      <category>algorithm</category>
    </item>
    <item>
      <title>Making Python Integers Iterable</title>
      <dc:creator>Arpit Bhayani</dc:creator>
      <pubDate>Sun, 14 Jun 2020 09:35:53 +0000</pubDate>
      <link>https://dev.to/arpit_bhayani/making-python-integers-iterable-2lnl</link>
      <guid>https://dev.to/arpit_bhayani/making-python-integers-iterable-2lnl</guid>
      <description>&lt;p&gt;Iterables in Python are objects and containers that could be stepped through one item at a time, usually using a &lt;code&gt;for ... in&lt;/code&gt; loop. Not all objects can be iterated, for example - we cannot iterate an integer, it is a singular value. The best we can do here is iterate on a range of integers using the &lt;code&gt;range&lt;/code&gt; type which helps us iterate through all integers in the range &lt;code&gt;[0, n)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Since integers, individualistically, are not iterable, when we try to do a &lt;code&gt;for x in 7&lt;/code&gt;, it raises an exception stating &lt;code&gt;TypeError: 'int' object is not iterable&lt;/code&gt;. So what if, we change the Python's source code and make integers iterable, say every time we do a &lt;code&gt;for x in 7&lt;/code&gt;, instead of raising an exception it actually iterates through the values &lt;code&gt;[0, 7)&lt;/code&gt;. In this essay, we would be going through exactly that, and the entire agenda being:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What is a Python iterable?&lt;/li&gt;
&lt;li&gt;What is an iterator protocol?&lt;/li&gt;
&lt;li&gt;Changing Python's source code and make integers iterable, and&lt;/li&gt;
&lt;li&gt;Why it might be a bad idea to do so?&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Python Iterables
&lt;/h1&gt;

&lt;p&gt;Any object that could be iterated is an Iterable in Python. The list has to be the most popular iterable out there and it finds its usage in almost every single Python application - directly or indirectly. Even before the first user command is executed, the Python interpreter, while booting up, has already created &lt;code&gt;406&lt;/code&gt; lists, for its internal usage.&lt;/p&gt;

&lt;p&gt;In the example below, we see how a list &lt;code&gt;a&lt;/code&gt; is iterated through using a &lt;code&gt;for ... in&lt;/code&gt; loop and each element can be accessed via variable &lt;code&gt;x&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Similar to &lt;code&gt;list&lt;/code&gt;, &lt;code&gt;range&lt;/code&gt; is a python type that allows us to iterate on integer values starting with the value &lt;code&gt;start&lt;/code&gt; and going till &lt;code&gt;end&lt;/code&gt; while stepping over &lt;code&gt;step&lt;/code&gt; values at each time. &lt;code&gt;range&lt;/code&gt; is most commonly used for implementing a C-like &lt;code&gt;for&lt;/code&gt; loop in Python. In the example below, the &lt;code&gt;for&lt;/code&gt; loop iterates over a &lt;code&gt;range&lt;/code&gt; that starts from &lt;code&gt;0&lt;/code&gt;, goes till &lt;code&gt;7&lt;/code&gt; with a step of  &lt;code&gt;1&lt;/code&gt; - producing the sequence &lt;code&gt;[0, 7)&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# The range(0, 7, 1) will iterate through values 0 to 6 and every time
# it will increment the current value by 1 i.e. the step.
&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&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; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Apart from &lt;code&gt;list&lt;/code&gt; and &lt;code&gt;range&lt;/code&gt; other &lt;a href="https://docs.python.org/3/library/stdtypes.html#sequence-types-list-tuple-range"&gt;iterables&lt;/a&gt; are - &lt;code&gt;tuple&lt;/code&gt;, &lt;code&gt;set&lt;/code&gt;, &lt;code&gt;frozenset&lt;/code&gt;, &lt;code&gt;str&lt;/code&gt;, &lt;code&gt;bytes&lt;/code&gt;, &lt;code&gt;bytearray&lt;/code&gt;, &lt;code&gt;memoryview&lt;/code&gt;, and &lt;code&gt;dict&lt;/code&gt;. Python also allows us to create custom iterables by making objects and types follow the &lt;a href="https://docs.python.org/3/c-api/iter.html"&gt;Iterator Protocol&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Iterators and Iterator Protocol
&lt;/h1&gt;

&lt;p&gt;Python, keeping things simple, defines iterable as any object that follows the &lt;a href="https://docs.python.org/3/c-api/iter.html"&gt;Iterator Protocol&lt;/a&gt;; which means the object or a container implements the following functions&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;__iter__&lt;/code&gt; should return an iterator object having implemented the &lt;code&gt;__next__&lt;/code&gt; method&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;__next__&lt;/code&gt; should return the next item of the iteration and if items are exhausted then raise a &lt;code&gt;StopIteration&lt;/code&gt; exception.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, in a gist, &lt;code&gt;__iter__&lt;/code&gt; is something that makes any python object iterable; hence to make integers iterable we need to have &lt;code&gt;__iter__&lt;/code&gt; function set for integers.&lt;/p&gt;

&lt;h1&gt;
  
  
  Iterable in CPython
&lt;/h1&gt;

&lt;p&gt;The most famous and widely used implementation of Python is &lt;a href="https://github.com/python/cpython/"&gt;CPython&lt;/a&gt; where the core is implemented in pure C. Since we need to make changes to one of the core datatypes of Python, we will be modifying CPython, add &lt;code&gt;__iter__&lt;/code&gt; function to an Integer type, and rebuild the binary. But before jumping into the implementation, it is important to understand a few fundamentals.&lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;PyTypeObject&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Every object in Python is associated with a type and each &lt;a href="https://docs.python.org/3/c-api/typeobj.html#type-objects"&gt;type&lt;/a&gt; is an instance of a struct named &lt;a href="https://docs.python.org/3/c-api/typeobj.html"&gt;PyTypeObject&lt;/a&gt;. A new instance of this structure is effectively a new type in python. This structure holds a few meta information and a bunch of C function pointers - each implementing a small segment of the type's functionality. Most of these "slots" in the structure are optional which could be filled by putting appropriate function pointers and driving the corresponding functionality.&lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;tp_iter&lt;/code&gt; slot
&lt;/h2&gt;

&lt;p&gt;Among all the slots available, the slot that interests us is the &lt;code&gt;tp_iter&lt;/code&gt; slot which can hold a pointer to a function that returns an iterator object. This slot corresponds to the &lt;code&gt;__iter__&lt;/code&gt; function which effectively makes the object iterable. A non &lt;code&gt;NULL&lt;/code&gt; value of this slot indicates iterability. The &lt;code&gt;tp_iter&lt;/code&gt; holds the function with the following signature&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;PyObject&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;tp_iter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PyObject&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Integers in Python do not have a fixed size; rather the size of integer depends on the value it holds. &lt;a href="https://arpitbhayani.me/blogs/super-long-integers"&gt;How Python implements super long integers&lt;/a&gt; is a story on its own but the core implementation can be found at &lt;a href="https://github.com/python/cpython/blob/master/Objects/longobject.c"&gt;longobject.c&lt;/a&gt;. The instance of &lt;code&gt;PyTypeObject&lt;/code&gt; that defines integer/long type is &lt;code&gt;PyLong_Type&lt;/code&gt; and has its &lt;code&gt;tp_iter&lt;/code&gt; slot set to &lt;code&gt;0&lt;/code&gt; i.e. &lt;code&gt;NULL&lt;/code&gt; which asserts the fact that Integers in python are not iterable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;PyTypeObject&lt;/span&gt; &lt;span class="n"&gt;PyLong_Type&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;

    &lt;span class="s"&gt;"int"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                                      &lt;span class="cm"&gt;/* tp_name */&lt;/span&gt;
    &lt;span class="n"&gt;offsetof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PyLongObject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ob_digit&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;           &lt;span class="cm"&gt;/* tp_basicsize */&lt;/span&gt;
    &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;digit&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;                              &lt;span class="cm"&gt;/* tp_itemsize */&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;                                          &lt;span class="cm"&gt;/* tp_iter */&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This &lt;code&gt;NULL&lt;/code&gt; value for &lt;code&gt;tp_iter&lt;/code&gt; makes &lt;code&gt;int&lt;/code&gt; object not iterable and hence if this slot was occupied by an appropriate function pointer with the aforementioned signature, this could well make any integer iterable.&lt;/p&gt;

&lt;h1&gt;
  
  
  Implementing &lt;code&gt;long_iter&lt;/code&gt;
&lt;/h1&gt;

&lt;p&gt;Now we implement the &lt;code&gt;tp_iter&lt;/code&gt; function on integer type, naming it &lt;code&gt;long_iter&lt;/code&gt;, that returns an iterator object, as required by the convention. The core functionality we are looking to implement here is - when an integer &lt;code&gt;n&lt;/code&gt; is iterated, it should iterate through the sequence &lt;code&gt;[0, n)&lt;/code&gt; with step &lt;code&gt;1&lt;/code&gt;. This behavior is very close to the pre-defined &lt;code&gt;range&lt;/code&gt; type, that iterates over a range of integer values, more specifically a &lt;code&gt;range&lt;/code&gt; that starts at &lt;code&gt;0&lt;/code&gt;, goes till &lt;code&gt;n&lt;/code&gt; with a step of &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We define a utility function in &lt;code&gt;rangeobject.c&lt;/code&gt; that, given a python integer, returns an instance of &lt;code&gt;longrangeiterobject&lt;/code&gt; as per our specifications. This utility function will instantiate the &lt;code&gt;longrangeiterobject&lt;/code&gt; with start as &lt;code&gt;0&lt;/code&gt;, ending at the long value given in the argument, and step as &lt;code&gt;1&lt;/code&gt;. The utility function is as illustrated below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cm"&gt;/*
 *  PyLongRangeIter_ZeroToN creates and returns a range iterator on long
 *  iterating on values in the range [0, n).
 *
 *  The function creates and returns a range iterator from 0 till the
 *  provided long value.
 */&lt;/span&gt;
&lt;span class="n"&gt;PyObject&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="nf"&gt;PyLongRangeIter_ZeroToN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PyObject&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;long_obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// creating a new instance of longrangeiterobject&lt;/span&gt;
    &lt;span class="n"&gt;longrangeiterobject&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PyObject_New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;longrangeiterobject&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;PyLongRangeIter_Type&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// if unable to allocate memoty to it, return NULL.&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// we set the start to 0&lt;/span&gt;
    &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_PyLong_Zero&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// we set the step to 1&lt;/span&gt;
    &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_PyLong_One&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// we set the index to 0, since we want to always start from the first&lt;/span&gt;
    &lt;span class="c1"&gt;// element of the iteration&lt;/span&gt;
    &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_PyLong_Zero&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// we set the total length of iteration to be equal to the provided value&lt;/span&gt;
    &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;long_obj&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// we increment the reference count for each of the values referenced&lt;/span&gt;
    &lt;span class="n"&gt;Py_INCREF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;Py_INCREF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;Py_INCREF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;Py_INCREF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// downcast the iterator instance to PyObject and return&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PyObject&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The utility function &lt;code&gt;PyLongRangeIter_ZeroToN&lt;/code&gt; is defined in &lt;code&gt;rangeobject.c&lt;/code&gt; and will be declared in &lt;code&gt;rangeobject.h&lt;/code&gt; so that it can be used across the CPython. Declaration of function in &lt;code&gt;rangeobject.h&lt;/code&gt; using standard Python macros goes like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;PyAPI_FUNC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PyObject&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="n"&gt;PyLongRangeIter_ZeroToN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PyObject&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The function occupying the &lt;code&gt;tp_iter&lt;/code&gt; slot will receive the &lt;code&gt;self&lt;/code&gt; object as the input argument and is expected to return the iterator instance. Hence, the &lt;code&gt;long_iter&lt;/code&gt; function will receive the python integer object (self) that is being iterated as an input argument and it should return the iterator instance. Here we would use the utility function &lt;code&gt;PyLongRangeIter_ZeroToN&lt;/code&gt;, we just defined, which is returning us an instance of range iterator. The entire &lt;code&gt;long_iter&lt;/code&gt; function could be defined as&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cm"&gt;/*
 *  long_iter creates an instance of range iterator using PyLongRangeIter_ZeroToN
 *  and returns the iterator instance.
 *
 *  The argument to the `tp_iter` is the `self` object and since we are trying to
 *  iterate an integer here, the input argument to `long_iter` will be the
 *  PyObject of type PyLong_Type, holding the integer value.
 */&lt;/span&gt;
&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;PyObject&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;long_iter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PyObject&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;long_obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;PyLongRangeIter_ZeroToN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;long_obj&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now that we have &lt;code&gt;long_iter&lt;/code&gt; defined, we can place the function on the &lt;code&gt;tp_iter&lt;/code&gt; slot of &lt;code&gt;PyLong_Type&lt;/code&gt; that enables the required iterability on integers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;PyTypeObject&lt;/span&gt; &lt;span class="n"&gt;PyLong_Type&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;

    &lt;span class="s"&gt;"int"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                                      &lt;span class="cm"&gt;/* tp_name */&lt;/span&gt;
    &lt;span class="n"&gt;offsetof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PyLongObject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ob_digit&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;           &lt;span class="cm"&gt;/* tp_basicsize */&lt;/span&gt;
    &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;digit&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;                              &lt;span class="cm"&gt;/* tp_itemsize */&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="n"&gt;long_iter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                                  &lt;span class="cm"&gt;/* tp_iter */&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Consolidated flow
&lt;/h2&gt;

&lt;p&gt;Once we have everything in place, the entire flow goes like this -&lt;/p&gt;

&lt;p&gt;Every time an integer is iterated, using any iteration method - for example &lt;code&gt;for ... in&lt;/code&gt;, it would check the &lt;code&gt;tp_iter&lt;/code&gt; of the &lt;code&gt;PyLongType&lt;/code&gt; and since now it holds the function pointer &lt;code&gt;long_iter&lt;/code&gt;, the function will be invoked. This invocation will return an iterator object of type &lt;code&gt;longrangeiterobject&lt;/code&gt; with a fixed start, index, and step values - which in pythonic terms is effectively a &lt;code&gt;range(0, n, 1)&lt;/code&gt;.  Hence the &lt;code&gt;for x in 7&lt;/code&gt; is inherently evaluated as &lt;code&gt;for x in range(0, 7, 1)&lt;/code&gt; allowing us to iterate integers.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;These changes are also hosted on a remote branch &lt;a href="https://github.com/arpitbbhayani/cpython/tree/02-long-iter"&gt;cpython@02-long-iter&lt;/a&gt; and Pull Request holding the &lt;code&gt;diff&lt;/code&gt; can be found &lt;a href="https://github.com/arpitbbhayani/cpython/pull/7"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Integer iteration in action
&lt;/h1&gt;

&lt;p&gt;Once we build a new python binary with the aforementioned changes, we can see iterable integers in actions. Now when we do &lt;code&gt;for x in 7&lt;/code&gt;, instead of raising an exception, it actually iterates through values &lt;code&gt;[0, 7)&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;print&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; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;

&lt;span class="cp"&gt;# Since integers are now iterable, we can create a list of [0, 7) using `list`
# Internally `list` tries to iterate on the given object i.e. `7`
# now that the iteration is defined as [0, 7) we get the list from
# from iteration, instead of an exception
&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)&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; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Why it is not a good idea
&lt;/h1&gt;

&lt;p&gt;Although it seems fun, and somewhat useful, to have iterable integers, it is really not a great idea. The core reason for this is that it makes unpacking unpredictable. Unpacking is when you unpack an iterable and assign it to multiple variables. For example: &lt;code&gt;a, b = 3, 4&lt;/code&gt; will assign 3 to a and 4 to b. So assigning &lt;code&gt;a, b = 7&lt;/code&gt; should be an error because there is just one value on the right side and multiple on the left.&lt;/p&gt;

&lt;p&gt;Unpacking treats right-hand size as iterable and tries to iterate on it; and now since Integers are iterable the right-hand side, post iteration yields 7 values which the left-hand side has mere 2 variables; Hence it raises an exception &lt;code&gt;ValueError: too many values to unpack (expected 2)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Things would work just fine if we do &lt;code&gt;a, b = 2&lt;/code&gt; as now the right-hand side, post iteration, has two values, and the left-hand side has two variables. Thus two very similar statements result in two very different outcomes, making unpacking unpredictable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;
&lt;span class="n"&gt;Traceback&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;most&lt;/span&gt; &lt;span class="n"&gt;recent&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s"&gt;"&amp;lt;stdin&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nb"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;too&lt;/span&gt; &lt;span class="n"&gt;many&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;unpack&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&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;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;In this essay, we modified the Python's source code and made integers iterable. Even though it is not a good idea to do so, but it is fun to play around with the code and make changes in our favorite programming language. It helps us get a detailed idea about core python implementation and may pave the way for us to become a Python core developer. This is one of many articles in Python Internals series - &lt;a href="https://arpitbhayani.me/blogs/super-long-integers"&gt;How python implements super long integers?&lt;/a&gt; and &lt;a href="https://arpitbhayani.me/blogs/python-caches-integers"&gt;Python Caches Integers&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  References
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3/c-api/type.html#c.PyTypeObject"&gt;PyTypeObject&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3/c-api/typeobj.html"&gt;Python Type Objects&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3/c-api/iter.html"&gt;Python Iterator Protocol&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/arpitbbhayani/cpython/pull/7"&gt;CPython with long_iter&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Other articles that you might like
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/python-caches-integers"&gt;Python Caches Integers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/super-long-integers"&gt;How python implements super long integers?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/i-changed-my-python"&gt;I changed my Python and made it dubious | Python Internals&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/fsm"&gt;Building Finite State Machines with Python Coroutines&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/python-prompts"&gt;Personalize your python prompt&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you liked what you read, consider subscribing to my weekly newsletter at &lt;a href="https://arpitbhayani.me/newsletter"&gt;arpitbhayani.me/newsletter&lt;/a&gt; were, once a week, I write an essay about programming languages internals, or a deep dive on some super-clever algorithm, or just a few tips on building highly scalable distributed systems.&lt;/p&gt;

&lt;p&gt;You can always find me browsing through twitter &lt;a href="https://twitter.com/arpit_bhayani"&gt;@arpit_bhayani&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>python</category>
      <category>cpython</category>
      <category>internals</category>
    </item>
    <item>
      <title>Powering inheritance in C using structure composition</title>
      <dc:creator>Arpit Bhayani</dc:creator>
      <pubDate>Sun, 07 Jun 2020 08:41:11 +0000</pubDate>
      <link>https://dev.to/arpit_bhayani/powering-inheritance-in-c-using-structure-composition-20jk</link>
      <guid>https://dev.to/arpit_bhayani/powering-inheritance-in-c-using-structure-composition-20jk</guid>
      <description>&lt;p&gt;C language does not support inheritance however it does support Structure Compositions which can be tweaked to serve use-cases requiring parent-child relationships. In this article, we find out how Structure Compositions help us emulate inheritance in C and keep our code extensible. We will also find how it powers two of the most important things to have ever been invented in the field of computer science.&lt;/p&gt;

&lt;h1&gt;
  
  
  What is structure composition?
&lt;/h1&gt;

&lt;p&gt;Structure Composition is when we put one structure within another, not through its pointer but as a native member - something like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// this structure defines a node of a linked list and&lt;/span&gt;
&lt;span class="c1"&gt;// it only holds the pointers to the next and the previous&lt;/span&gt;
&lt;span class="c1"&gt;// nodes in the linked list.&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;list_head&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;list_head&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// pointer to the node next to the current one&lt;/span&gt;
    &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;list_head&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// pointer to the node previous to the current one&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// list_int holds an list_head and an integer data member&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;list_int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;list_head&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// common next and prev pointers&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;              &lt;span class="c1"&gt;// specific member as per implementation&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// list_int holds an list_head and an char * data member&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;list_str&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;list_head&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// common next and prev pointers&lt;/span&gt;
    &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;             &lt;span class="c1"&gt;// specific member as per implementation&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the example above, we define a node of a linked list using structure composition. Usually, a linked list node has 3 members - two pointers to adjacent nodes (next and previous) and a third one could either be the data or a pointer to it.  The defining factor of a linked list is the two pointers that logically form a chain of nodes. To keep things abstract we create a struct named &lt;code&gt;list_head&lt;/code&gt; which holds these two pointers  &lt;code&gt;next&lt;/code&gt; and &lt;code&gt;prev&lt;/code&gt; and omits the specifics i.e. data.&lt;/p&gt;

&lt;p&gt;Using &lt;code&gt;list_head&lt;/code&gt; structure, if we were to define a node of a linked list holding an integer value we could create another struct, named &lt;code&gt;list_int&lt;/code&gt; that holds a member of type &lt;code&gt;list_head&lt;/code&gt; and an integer value &lt;code&gt;value&lt;/code&gt;. The next and previous pointers are brought into this struct through &lt;code&gt;list_head list&lt;/code&gt; and could be referred to as &lt;code&gt;list.next&lt;/code&gt; and &lt;code&gt;list.prev&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There is a very genuine reason for picking such weird names for a linked list node and members of structures; the reason to do so will be cleared in the later sections of this essay.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Because of the above structure definition, building a linked list node holding of any type becomes a breeze. For example, a node holding string could be quickly defined as a struct &lt;code&gt;list_str&lt;/code&gt; having &lt;code&gt;list_head&lt;/code&gt; and a &lt;code&gt;char *&lt;/code&gt;. This ability to extend &lt;code&gt;list_head&lt;/code&gt; and build a node holding data of any type and any specifics make low-level code simple, uniform, and extensible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Memory Representation of &lt;code&gt;list_int&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Structures in C are not padded and they do not even hold any meta information, not even for the member names; hence during allocation, they are allocated the space just enough to hold the actual data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F4745789%2F83953834-694a6a00-a861-11ea-8ff7-fa69af6af7d6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F4745789%2F83953834-694a6a00-a861-11ea-8ff7-fa69af6af7d6.png" alt="https://user-images.githubusercontent.com/4745789/83953834-694a6a00-a861-11ea-8ff7-fa69af6af7d6.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the illustration above we see how members of &lt;code&gt;list_int&lt;/code&gt; are mapped on the allocated space - required by its individual members. It is allocated a contiguous space of 12 bytes - 4 bytes for each of the two pointers and another 4 bytes for the integer value. The contiguity of space allocation and order of members during allocation could be verified by printing out their addresses as shown below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;print_addrs&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// creating a node of the list_int holding value 41434&lt;/span&gt;
    &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;list_int&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ll&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new_list_int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;41434&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// printing the address of individual members&lt;/span&gt;
    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%p: head&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;             &lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%p: head-&amp;gt;list.next&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%p: head-&amp;gt;list.prev&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%p: head-&amp;gt;value&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;~&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;make&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;
&lt;span class="mh"&gt;0x4058f0&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt;
&lt;span class="mh"&gt;0x4058f0&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;
&lt;span class="mh"&gt;0x4058f4&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prev&lt;/span&gt;
&lt;span class="mh"&gt;0x4058f8&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We clearly see all the 3 members, occupying 12 bytes contiguous memory segments in order of their definition within the struct.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The above code was executed on a machine where the size of integer and pointers were 4 bytes each. The results might differ depending on the machine and CPU architecture.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Casting pointers pointing to struct
&lt;/h2&gt;

&lt;p&gt;In C language, when a pointer to a struct is cast to a pointer to another struct, the engine maps the individual members of a target struct type, depending on their order and offsets, on to the slice of memory of the source struct instance.&lt;/p&gt;

&lt;p&gt;When we cast &lt;code&gt;list_int *&lt;/code&gt; into &lt;code&gt;list_head *&lt;/code&gt;, the engine maps the space required by target type i.e. &lt;code&gt;list_head&lt;/code&gt; on space occupied by &lt;code&gt;list_int&lt;/code&gt;. This means it maps the 8 bytes required by &lt;code&gt;list_head&lt;/code&gt; on the first 8 bytes occupied by &lt;code&gt;list_int&lt;/code&gt; instance. Going by the memory representation discussed above, we find that the first 8 bytes of &lt;code&gt;list_int&lt;/code&gt; are in fact &lt;code&gt;list_head&lt;/code&gt;, and hence casting &lt;code&gt;list_int *&lt;/code&gt; to &lt;code&gt;list_head *&lt;/code&gt; is effectively just referencing the &lt;code&gt;list_head&lt;/code&gt; member of &lt;code&gt;list_int&lt;/code&gt; through a new variable.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F4745789%2F83943610-2e254800-a81b-11ea-8b25-056e1b1df85e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F4745789%2F83943610-2e254800-a81b-11ea-8b25-056e1b1df85e.png" alt="https://user-images.githubusercontent.com/4745789/83943610-2e254800-a81b-11ea-8b25-056e1b1df85e.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This effectively builds a parent-child relationship between the two structs where we can safely typecast a child &lt;code&gt;list_int&lt;/code&gt; to its parent &lt;code&gt;list_head&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It is important to note here that the parent-child relationship is established only because the first member of &lt;code&gt;list_int&lt;/code&gt; is of type &lt;code&gt;list_head&lt;/code&gt;. it would not have worked if we change the order of members in &lt;code&gt;list_int&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  How does this drive inheritance?
&lt;/h1&gt;

&lt;p&gt;As established above, by putting one struct within another as its first element we are effectively creating a parent-child relationship between the two. Since this gives us an ability to safely typecast child to its parent we can define functions that accept a pointer to parent struct as an argument and perform operations that do not really require to deal with specifics. This allows us to &lt;strong&gt;NOT&lt;/strong&gt; rewrite the functional logic for every child extensions and thus avoid redundant code.&lt;/p&gt;

&lt;p&gt;From the context we have set up, say we want to write a function that adds a node between the two in a linked list. The core logic to perform this operation does not really need to deal with any specifics all it takes is a few pointer manipulations of &lt;code&gt;next&lt;/code&gt; and &lt;code&gt;prev&lt;/code&gt;. Hence, we could just define the function accepting arguments of type &lt;code&gt;list_head *&lt;/code&gt;  and write the function as&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cm"&gt;/*
 * Insert a new entry between two known consecutive entries.
 *
 * This is only for internal list manipulation where we know
 * the prev/next entries already!
 */&lt;/span&gt;
&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;__list_add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;list_head&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                       &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;list_head&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                       &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;list_head&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;prev&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;prev&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since we can safely typecase &lt;code&gt;list_int *&lt;/code&gt; and &lt;code&gt;list_str *&lt;/code&gt; to &lt;code&gt;list_head *&lt;/code&gt; we can pass any of the specific implementations the function &lt;code&gt;__list_add&lt;/code&gt; and it would still add the node between the other two seamlessly.&lt;/p&gt;

&lt;p&gt;Since the core operations on linked lists only require pointer manipulations, we can define these operations as functions accepting &lt;code&gt;list_head *&lt;/code&gt; instead of specific types like &lt;code&gt;list_int *&lt;/code&gt;.  Thus we need not write similar functions for specifics. A function to delete a node could be written as&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cm"&gt;/*
 * Delete a list entry by making the prev/next entries
 * point to each other.
 *
 * This is only for internal list manipulation where we know
 * the prev/next entries already!
 */&lt;/span&gt;
&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kr"&gt;inline&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;__list_del&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;list_head&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;list_head&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;prev&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Other linked list utilities like &lt;em&gt;adding a node to tail&lt;/em&gt;, &lt;em&gt;swapping nodes&lt;/em&gt;, &lt;em&gt;splicing the list&lt;/em&gt;, &lt;em&gt;rotating the list&lt;/em&gt;, etc only require manipulations of &lt;code&gt;next&lt;/code&gt; and &lt;code&gt;prev&lt;/code&gt; pointers. Hence they could also be written in a very similar way i.e accepting &lt;code&gt;list_head *&lt;/code&gt; and thus eliminating the need to reimplement function logic for every single child implementation.&lt;/p&gt;

&lt;p&gt;This behavior is very similar to how inheritance in modern OOP languages, like Python and Java, work where the child is allowed to invoke any parent function.&lt;/p&gt;

&lt;h1&gt;
  
  
  Who uses structure compositions?
&lt;/h1&gt;

&lt;p&gt;There are a ton of practical usage of using Structure Compositions but the most famous ones are&lt;/p&gt;

&lt;h2&gt;
  
  
  Linux Kernel
&lt;/h2&gt;

&lt;p&gt;In order to keep things abstract and extensible, Linux Kernel uses Structure Composition at several places. One of the most important places where it uses composition is for managing and maintaining Linked Lists, exactly how we saw things above. The struct definitions and code snippets are taken as-is from the &lt;a href="https://elixir.bootlin.com/linux/latest/source/include/linux/list.h" rel="noopener noreferrer"&gt;Kernel's source code&lt;/a&gt;, and hence the structure and variable names look different than usual.&lt;/p&gt;

&lt;h2&gt;
  
  
  Python Type and Object Hierarchy
&lt;/h2&gt;

&lt;p&gt;Python, one of the most important languages in today's world, uses Structure Composition to build Type Hierarchy. Python defines a root structure called &lt;code&gt;PyObject&lt;/code&gt; which holds reference count, defining the number of places from which the object is referenced - and object type - determining the type of the object i.e. &lt;code&gt;int&lt;/code&gt;, &lt;code&gt;str&lt;/code&gt;, &lt;code&gt;list&lt;/code&gt;, &lt;code&gt;dict&lt;/code&gt;, etc.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;_object&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Py_ssize_t&lt;/span&gt;     &lt;span class="n"&gt;ob_refcnt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// holds reference count of the object&lt;/span&gt;
    &lt;span class="n"&gt;PyTypeObject&lt;/span&gt;   &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ob_type&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// holds the type of the object&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;PyObject&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since Python wants these fields to be present in every single object that is created during runtime, it uses structure composition to ensure that objects like integers, floats, string, etc put &lt;code&gt;PyObject&lt;/code&gt; as their first element and thus establishing a parent-child relationship. A Float object in Python is defined as&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#define PyObject_HEAD PyObject ob_base;
&lt;/span&gt;
&lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;PyObject_HEAD&lt;/span&gt;
    &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;ob_fval&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;    &lt;span class="c1"&gt;// holds the actual float value&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;PyFloatObject&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now writing utility functions that increments and decrements references count on every access of any object could be written as just a single function accepting &lt;code&gt;PyObject *&lt;/code&gt; as shown below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kr"&gt;inline&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;_Py_INCREF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PyObject&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ob_refcnt&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;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Thus we eradicate a need of rewriting &lt;code&gt;INCREF&lt;/code&gt; for every single object type and just write it once for &lt;code&gt;PyObject&lt;/code&gt; and it will work for every single Python object type that is extended through &lt;code&gt;PyObject&lt;/code&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  References
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://elixir.bootlin.com/linux/latest/source/include/linux/list.h" rel="noopener noreferrer"&gt;LinkedList in Linux Source Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3/c-api/structures.html#c.PyObject" rel="noopener noreferrer"&gt;PyObject - Python Internals Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3/c-api/float.html" rel="noopener noreferrer"&gt;PyFloatObject - Python Internals Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Other articles that you might like
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/copy-on-write" rel="noopener noreferrer"&gt;Copy-on-Write Semantics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/efficient-way-to-stop-an-iterating-loop" rel="noopener noreferrer"&gt;An efficient way to stop an iterating loop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/mongodb-cursor-skip-is-slow" rel="noopener noreferrer"&gt;Why MongoDB's cursor.skip() is slow?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/fast-and-efficient-pagination-in-mongodb" rel="noopener noreferrer"&gt;Fast and Efficient Pagination in MongoDB&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;If you liked what you read, consider subscribing to my weekly newsletter at &lt;a href="https://arpitbhayani.me/newsletter" rel="noopener noreferrer"&gt;arpitbhayani.me/newsletter&lt;/a&gt; were, once a week, I write an essay about programming languages internals, or a deep dive on some super-clever algorithm, or just a few tips on building highly scalable distributed systems.&lt;/p&gt;

&lt;p&gt;You can always find me browsing through twitter &lt;a href="https://twitter.com/arpit_bhayani" rel="noopener noreferrer"&gt;@arpit_bhayani&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>python</category>
      <category>cpp</category>
      <category>oop</category>
      <category>linux</category>
    </item>
    <item>
      <title>The RUM Conjecture</title>
      <dc:creator>Arpit Bhayani</dc:creator>
      <pubDate>Sun, 31 May 2020 12:10:37 +0000</pubDate>
      <link>https://dev.to/arpit_bhayani/the-rum-conjecture-33gf</link>
      <guid>https://dev.to/arpit_bhayani/the-rum-conjecture-33gf</guid>
      <description>&lt;p&gt;The RUM Conjecture states that we cannot design an access method for a storage system that is optimal in all the following three aspects - Reads, Updates, and, Memory. The conjecture puts forth that we always have to trade one to make the other two optimal and this makes the three constitutes a competing triangle, very similar to the famous &lt;a href="https://en.wikipedia.org/wiki/CAP_theorem"&gt;CAP theorem&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--r7iOKxeW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/83323578-6eb21e00-a27d-11ea-941b-43e875169c97.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--r7iOKxeW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/83323578-6eb21e00-a27d-11ea-941b-43e875169c97.png" alt="https://user-images.githubusercontent.com/4745789/83323578-6eb21e00-a27d-11ea-941b-43e875169c97.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Access Method
&lt;/h1&gt;

&lt;p&gt;Data access refers to an ability to access and retrieve data stored within a storage system driven by an optional storage engine. Usually, a storage system is designed to be optimal for serving a niche use case and achieve that by carefully and judiciously deciding the memory and disk storage requirements, defining well-structured access and retrieval pattern, designing data structures for primary and auxiliary data and picking additional techniques like compression, encryption, etc. These decisions define, and to some extent restricts, the possible ways the storage engine can read and update the data in the system.&lt;/p&gt;

&lt;h1&gt;
  
  
  RUM Overheads
&lt;/h1&gt;

&lt;p&gt;An ideal storage system would be the one that has an access method that provides lowest Read Overhead, minimal Update Cost, and does not require any extra Memory or Storage space, over the main data. In the real-world, achieving this is near impossible and that is something that is dictated by this conjecture.&lt;/p&gt;

&lt;h3&gt;
  
  
  Read Overhead
&lt;/h3&gt;

&lt;p&gt;Read Overhead occur when the storage engine performs reads on auxiliary data to fetch the required intended main data. This usually happens when we use an auxiliary data structure like a Secondary Index to speed up reads. The reads happening on this auxiliary structure constitutes read overheads.&lt;/p&gt;

&lt;p&gt;Read Overhead is measured through Read Amplification and it is defined as the ratio between the total amount of data read (main + auxiliary) and the amount of main data intended to be read.&lt;/p&gt;

&lt;h3&gt;
  
  
  Update Overhead
&lt;/h3&gt;

&lt;p&gt;Update Overhead occur when the storage engine performs writes on auxiliary data or on some unmodified main data along with intended updates on the main data. A typical example of Update Overheads is the writes that happen on an auxiliary structure like Secondary Index alongside the write happening on intended main data. &lt;/p&gt;

&lt;p&gt;Update Overhead is measured through Write Amplification and it is defined as the ratio between the total amount of data written (main + auxiliary) and the amount of main data intended to be updated.&lt;/p&gt;

&lt;h3&gt;
  
  
  Memory Overhead
&lt;/h3&gt;

&lt;p&gt;Memory overhead occurs when the storage system uses an auxiliary data structure to speed up reads, writes, or to serve common access patterns. This storage is in addition to the storage needs of the main data.&lt;/p&gt;

&lt;p&gt;Memory Overhead is measured through Space Amplification and it is defined as the ratio between the space utilized for auxiliary and main data and space utilized by the main data. &lt;/p&gt;

&lt;h1&gt;
  
  
  The Conjecture
&lt;/h1&gt;

&lt;p&gt;The RUM Conjecture, in a formal way, states that&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;An access method that can set an upper bound for two out of the read, update, and memory overheads, also sets a lower bound for the third overhead.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is not a hard rule that is followed and hence it is not a theorem but a conjecture - widely observed but not proven. But we can safely keep this in mind while designing the next big storage system serving a use case.&lt;/p&gt;

&lt;h1&gt;
  
  
  Categorizing Storage Systems
&lt;/h1&gt;

&lt;p&gt;Now that we have seen RUM overheads and the RUM Conjecture we take a look at examples of Storage Systems that classify into one of the three types.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read Optimised
&lt;/h2&gt;

&lt;p&gt;Read Optimised storage systems offer very low read overhead but require some extra auxiliary space to gain necessary performance that again comes at a cost of updates required to keep auxiliary data in sync with main data which adds to update overheads. When the updates, on main data, become frequent the performance of a read optimized storage system takes a dip.&lt;/p&gt;

&lt;p&gt;A fine example of a read optimized storage system is the one that supports Point Indexes, also called Hash-based indexes, offering constant time access. The systems that provide logarithmic time access, like &lt;a href="https://en.wikipedia.org/wiki/B-tree"&gt;B-Trees&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Skip_list"&gt;Skiplists&lt;/a&gt;, also fall into this category.&lt;/p&gt;

&lt;h2&gt;
  
  
  Update Optimised
&lt;/h2&gt;

&lt;p&gt;Update Optimised storage systems offer very low Update Overhead by usually using an auxiliary space holding differential data (delta) and flushing them over main data in a bulk operation. The need of having an auxiliary data to keep track of delta to perform a bulk update adds to Memory Overhead.&lt;/p&gt;

&lt;p&gt;A few examples of Update Optimised systems are &lt;a href="https://en.wikipedia.org/wiki/Log-structured_merge-tree"&gt;LSM Trees&lt;/a&gt;, &lt;a href="http://cs.emis.de/LNI/Proceedings/Proceedings26/GI-Proceedings.26-47.pdf"&gt;Partitioned B Trees&lt;/a&gt;, and &lt;a href="http://pages.cs.wisc.edu/~yinan/fdtree.html"&gt;FD Tree&lt;/a&gt;. These structures offer very good performance for an update-heavy system but suffer from an increased read and space overheads. While reading data from LSM Tree, the engine needs to perform read on all the tiers and then perform a conflict resolution, and maintaining tiers of data itself is a huge Space Overhead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Memory Optimised
&lt;/h2&gt;

&lt;p&gt;Memory Optimised storage systems are designed to minimize auxiliary memory required for access and updates on the main data. To be memory-optimized the systems usually use compress the main data and auxiliary storages, or allow some error rate, like false positives.&lt;/p&gt;

&lt;p&gt;A few examples of Memory Optimises systems are lossy index structures like &lt;a href="https://en.wikipedia.org/wiki/Bloom_filter"&gt;Bloom Filters&lt;/a&gt;, &lt;a href="https://en.wikipedia.org/wiki/Count%E2%80%93min_sketch"&gt;Count-min sketches&lt;/a&gt;, Lossy encodings, and Sparse Indexes. Keeping either main or auxiliary data compressed, to be memory efficient, the system takes a toll on writes and reads as they now have additionally performed compression and decompressions adding to the Update and Read overheads.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aH9P2q1E--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/83323560-55a96d00-a27d-11ea-9d33-4001c672b920.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aH9P2q1E--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/83323560-55a96d00-a27d-11ea-9d33-4001c672b920.png" alt="https://user-images.githubusercontent.com/4745789/83323560-55a96d00-a27d-11ea-9d33-4001c672b920.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Storage System examples for RUM Conjecture&lt;/p&gt;

&lt;h1&gt;
  
  
  Block-based Clustered Indexing
&lt;/h1&gt;

&lt;p&gt;Block-based Clustered Indexing, sits comfortably between these three optimized systems types. It is not read Read efficient but also efficient on Updates and Memory. It builds a very short tree for its auxiliary data, by storing a few pointers to pages and since the data is clustered i.e. the main data itself is stored in the index,  the system does not go to fetch the main data from the main storage and hence provides a minimal Read overhead.&lt;/p&gt;

&lt;h1&gt;
  
  
  Being RUM Adaptive
&lt;/h1&gt;

&lt;p&gt;Storage systems have always been rigid with respect to the kind of use cases it aims to solve. the application, the workload, and the hardware should dictate how we access our data, and not the constraints of our systems. Storage systems could be designed to be RUM Adaptive and they should possess an ability to be tuned to reduce the RUM overheads depending on the data access pattern and computation knowledge. RUM Adaptive storage systems are part of the discussion for some other day.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;There will always be trade-offs, between Read, Update, and Memory, while either choosing one storage system over others; the RUM conjecture facilitates and to some extent formalizes the entire process. Although this is just a conjecture, it still helps us disambiguate and make an informed, better and viable decision that will go a long way.&lt;/p&gt;

&lt;p&gt;This essay was heavily based on the original research paper introducing The RUM Conjecture.&lt;/p&gt;

&lt;h1&gt;
  
  
  References
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://stratos.seas.harvard.edu/files/stratos/files/rum.pdf"&gt;Designing Access Methods: The RUM Conjecture&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Other articles that you might like
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/copy-on-write"&gt;Copy-on-Write Semantics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/mysql-cache"&gt;What makes MySQL LRU cache scan resistant&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/isolation-forest"&gt;Isolation Forest algorithm for anomaly detection&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/image-steganography"&gt;Everything that you need to know about Image Steganography&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;If you liked what you read, consider subscribing to my weekly newsletter at &lt;a href="https://arpit.substack.com/"&gt;arpit.substack.com&lt;/a&gt; were, once a week, I write an essay about programming languages internals, or a deep dive on some super-clever algorithm, or just a few tips on building highly scalable distributed systems.&lt;/p&gt;

&lt;p&gt;You can always find me browsing through twitter &lt;a href="https://twitter.com/arpit_bhayani"&gt;@arpit_bhayani&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>database</category>
      <category>distributedsystems</category>
    </item>
    <item>
      <title>Consistent Hashing</title>
      <dc:creator>Arpit Bhayani</dc:creator>
      <pubDate>Sun, 24 May 2020 17:11:28 +0000</pubDate>
      <link>https://dev.to/arpit_bhayani/consistent-hashing-with-binary-search-47ik</link>
      <guid>https://dev.to/arpit_bhayani/consistent-hashing-with-binary-search-47ik</guid>
      <description>&lt;p&gt;Consistent hashing is a hashing technique that performs really well when operated in a dynamic environment where the distributed system scales up and scales down frequently. The core concept of Consistent Hashing was introduced in the paper &lt;a href="https://www.akamai.com/us/en/multimedia/documents/technical-publication/consistent-hashing-and-random-trees-distributed-caching-protocols-for-relieving-hot-spots-on-the-world-wide-web-technical-publication.pdf"&gt;Consistent Hashing and RandomTrees: Distributed Caching Protocols for Relieving Hot Spots on the World Wide Web&lt;/a&gt; but it gained popularity after the famous paper introducing DynamoDB - &lt;a href="https://www.allthingsdistributed.com/files/amazon-dynamo-sosp2007.pdf"&gt;Dynamo: Amazon’s Highly Available Key-value Store&lt;/a&gt;. Since then the consistent hashing gained traction and found a ton of use cases in designing and scaling distributed systems efficiently. The two famous examples that exhaustively use this technique are Bit Torrent, for their peer-to-peer networks and Akamai, for their web caches. In this article we dive deep into the need of Consistent Hashing, the internals of it, and more importantly along the way implement it using arrays and &lt;a href="https://en.wikipedia.org/wiki/Binary_search_algorithm"&gt;Binary Search&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Hash Functions
&lt;/h1&gt;

&lt;p&gt;Before we jump into the core Consistent Hashing technique we first get a few things cleared up, one of which is Hash Functions. Hash Functions are any functions that map value from an arbitrarily sized domain to another fixed-sized domain, usually called the Hash Space. For example, mapping URLs to 32-bit integers or web pages' HTML content to a 256-byte string. The values generated as an output of these hash functions are typically used as keys to enable efficient lookups of the original entity.&lt;/p&gt;

&lt;p&gt;An example of a simple hash function is a function that maps a 32-bit integer into an 8-bit integer hash space. The function could be implemented using the arithmetic operator &lt;code&gt;modulo&lt;/code&gt; and we can achieve this by taking a &lt;code&gt;modulo 256&lt;/code&gt; which yields numbers in the range &lt;code&gt;[0, 255]&lt;/code&gt; taking up 8-bits for its representation. A hash function, that maps keys to such integer domain, more often than not applies the &lt;code&gt;modulo N&lt;/code&gt; so as to restrict the values, or the hash space, to a range &lt;code&gt;[0, N-1]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A good hash function has the following properties&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The function is computationally efficient and the values generated are easy for lookups&lt;/li&gt;
&lt;li&gt;The function, for most general use cases, behaves like a pseudorandom generator that spreads data out evenly without any noticeable correlation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now that we have seen what a hash function is, we take a look into how we could use them and build a somewhat scalable distributed system.&lt;/p&gt;

&lt;h1&gt;
  
  
  Building a distributed storage system
&lt;/h1&gt;

&lt;p&gt;Say we are building a distributed storage system in which users can upload files and access them on demand. The service exposes the following APIs to the users&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;upload&lt;/code&gt; to upload the file&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;fetch&lt;/code&gt; to fetch the file and return its content&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Behind the scenes the system has Storage Nodes on which the files are stored and accessed. These nodes expose the functions &lt;code&gt;put_file&lt;/code&gt; and &lt;code&gt;fetch_file&lt;/code&gt; that puts and gets the file content to/from the disk and sends the response to the main API server which in turn sends it back to the user.&lt;/p&gt;

&lt;p&gt;To sustain the initial load, the system has 5 Stogare Nodes which stores the uploaded files in a distributed manner. Having multiple nodes ensures that the system, as a whole, is not overwhelmed, and the storage is distributed almost evenly across.&lt;/p&gt;

&lt;p&gt;When the user invokes &lt;code&gt;upload&lt;/code&gt; function with the path of the file, the system first needs to identify the storage node that will be responsible for holding the file and we do this by applying a hash function to the path and in turn getting the storage node index. Once we get the storage node, we read the content of the file and put that file on the node by invoking the &lt;code&gt;put_file&lt;/code&gt; function of the node.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# storage_nodes holding instances of actual storage node objects
&lt;/span&gt;&lt;span class="n"&gt;storage_nodes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="n"&gt;StorageNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'A'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'10.131.213.12'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;StorageNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'B'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'10.131.217.11'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;StorageNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'C'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'10.131.142.46'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;StorageNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'D'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'10.131.114.17'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;StorageNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'E'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'10.131.189.18'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hash_fn&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="s"&gt;"""The function sums the bytes present in the `key` and then
    take a mod with 5. This hash function thus generates output
    in the range [0, 4].
    """&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;bytearray&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="n"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'utf-8'&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;upload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# we use the hash function to get the index of the storage node
&lt;/span&gt;    &lt;span class="c1"&gt;# that would hold the file
&lt;/span&gt;    &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hash_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# we get the StorageNode instance
&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;storage_nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="c1"&gt;# we put the file on the node and return
&lt;/span&gt;    &lt;span class="k"&gt;return&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;put_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# we use the hash function to get the index of the storage node
&lt;/span&gt;    &lt;span class="c1"&gt;# that would hold the file
&lt;/span&gt;    &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hash_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# we get the StorageNode instance
&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;storage_nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="c1"&gt;# we fetch the file from the node and return
&lt;/span&gt;    &lt;span class="k"&gt;return&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;fetch_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The hash function used over here simply sums the bytes and takes the modulo by &lt;code&gt;5&lt;/code&gt; (since there are 5 storage nodes in the system) and thus generating the output in the hash space &lt;code&gt;[0, 4]&lt;/code&gt;. This output value now represents the index of the storage engine that will be responsible for holding the file.&lt;/p&gt;

&lt;p&gt;Say we have 5 files 'f1.txt', 'f2.txt', 'f3.txt', 'f4.txt', 'f5.txt' if we apply the hash function to these we find that they are stored on storage nodes E, A, B, C, and D respectively.&lt;/p&gt;

&lt;p&gt;Things become interesting when the system gains some traction and it needs to be scaled to 7 nodes, which means now the hash function should do &lt;code&gt;mod 7&lt;/code&gt; instead of a &lt;code&gt;mod 5&lt;/code&gt;. Changing the hash function implies changing the mapping and association of files with storage nodes. We first need to administer the new associations and see which files required to be moved from one node to another.&lt;/p&gt;

&lt;p&gt;With the new hash function the same 5 files 'f1.txt', 'f2.txt', 'f3.txt', 'f4.txt', 'f5.txt' will now be associated with storage nodes D, E, F, G, A. Here we see that changing the hash function requires us to move every single one of the 5 files to a different node.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dxkdD2kz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/82746677-16c47480-9db0-11ea-8dea-7b5a3cb73e91.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dxkdD2kz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/82746677-16c47480-9db0-11ea-8dea-7b5a3cb73e91.png" alt="File association changed"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If we have to change the hash function every time we scale up or down and if this requires us to move not all but even half of the data, the process becomes super expensive and in longer run infeasible. So we need a way to minimize the data movement required during scale-ups or scale-downs, and this is where Consistent Hashing fits in and minimizes the required data transfer.&lt;/p&gt;

&lt;h1&gt;
  
  
  Consistent Hashing
&lt;/h1&gt;

&lt;p&gt;The major pain point of the above system is that it is prone to events like scale-ups and scale-downs as it requires a lot of alterations in associations. These associations are purely driven by the underlying Hash Function and hence if we could somehow make this hash function independent of the number of the storage nodes in the system, we address this flaw.&lt;/p&gt;

&lt;p&gt;Consistent Hashing addresses this situation by keeping the Hash Space huge and constant, somewhere in the order of &lt;code&gt;[0, 2^128 - 1]&lt;/code&gt; and the storage node and objects both map to one of the slots in this huge Hash Space. Unlike in the traditional system where the file was associated with storage node at index where it got hashed to, in this system the chances of a collision between a file and a storage node are infinitesimally small and hence we need a different way to define this association.&lt;/p&gt;

&lt;p&gt;Instead of using a collision-based approach we define the association as - the file will be associated with the storage node which is present to the immediate right of its hashed location. Defining association in this way helps us&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;keep the hash function independent of the number of storage nodes&lt;/li&gt;
&lt;li&gt;keep associations relative and not driven by absolute collisions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UX0KLu_l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/82748149-4d54bc00-9dbd-11ea-8f06-6710a5c98f20.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UX0KLu_l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/82748149-4d54bc00-9dbd-11ea-8f06-6710a5c98f20.png" alt="Associations in Consistent Hashing"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Consistent Hashing on an average requires only k/n units of data to be migrated during scale up and down; where k is the total number of keys and n is the number of nodes in the system.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A very naive way to implement this is by allocating an array of size equal to the Hash Space and putting files and storage node literally in the array on the hashed location. In order to get association we iterate from the item's hashed location towards the right and find the first Storage Node. If we reach the end of the array and do not find any Storage Node we circle back to index 0 and continue the search. The approach is very easy to implement but suffers from the following limitations&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;requires huge memory to hold such a large array&lt;/li&gt;
&lt;li&gt;finding association by iterating every time to the right is &lt;code&gt;O(hash_space)&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A better way of implementing this is by using two arrays: one to hold the Storage Nodes, called &lt;code&gt;nodes&lt;/code&gt; and another one to hold the positions of the Storage Nodes in the hash space, called &lt;code&gt;keys&lt;/code&gt;. There is a one-to-one correspondence between the two arrays - the Storage Node &lt;code&gt;nodes[i]&lt;/code&gt; is present at position &lt;code&gt;keys[i]&lt;/code&gt; in the hash space. Both the arrays are kept sorted as per the &lt;code&gt;keys&lt;/code&gt; array.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hash Function in Consistent Hashing
&lt;/h2&gt;

&lt;p&gt;We define &lt;code&gt;total_slots&lt;/code&gt; as the size of this entire hash space, typically of the order &lt;code&gt;2^256&lt;/code&gt; and the hash function could be implemented by taking &lt;a href="https://en.wikipedia.org/wiki/SHA-2"&gt;SHA-256&lt;/a&gt; followed by a &lt;code&gt;mod total_slots&lt;/code&gt;. Since the &lt;code&gt;total_slots&lt;/code&gt; is huge and a constant the following hash function implementation is independent of the actual number of Storage Nodes present in the system and hence remains unaffected by events like scale-ups and scale-downs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hash_fn&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="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total_slots&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="s"&gt;"""hash_fn creates an integer equivalent of a SHA256 hash and
    takes a modulo with the total number of slots in hash space.
    """&lt;/span&gt;
    &lt;span class="n"&gt;hsh&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sha256&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;# converting data into bytes and passing it to hash function
&lt;/span&gt;    &lt;span class="n"&gt;hsh&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;bytes&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="n"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'utf-8'&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

    &lt;span class="c1"&gt;# converting the HEX digest into equivalent integer value
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hsh&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hexdigest&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;total_slots&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Adding a new node in the system
&lt;/h2&gt;

&lt;p&gt;When there is a need to scale up and add a new node in the system, in our case a new Storage Node, we&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;find the position of the node where it resides in the Hash Space&lt;/li&gt;
&lt;li&gt;populate the new node with data it is supposed to serve&lt;/li&gt;
&lt;li&gt;add the node in the Hash Space&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When a new node is added in the system it only affects the files that hash at the location to the left and associated with the node to the right, of the position the new node will fit in. All other files and associations remain unaffected, thus minimizing the amount of data to be migrated and mapping required to be changed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--04MExfKy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/82751279-c959fe80-9dd3-11ea-86de-62d162519262.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--04MExfKy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/82751279-c959fe80-9dd3-11ea-86de-62d162519262.png" alt="Adding a new node in the system - Consistent Hashing"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From the illustration above, we see when a new node K is added between nodes B and E, we change the associations of files present in the segment B-K and assign them to node K. The data belonging to the segment B-K could be found at node E to which they were previously associated with. Thus the only files affected and that needs migration are in the segment B-K; and their association changes from node E to node K.&lt;/p&gt;

&lt;p&gt;In order to implement this at a low-level using &lt;code&gt;nodes&lt;/code&gt; and &lt;code&gt;keys&lt;/code&gt; array, we first get the position of the new node in the Hash Space using the hash function. We then find the index of the smallest key greater than the position in the sorted &lt;code&gt;keys&lt;/code&gt; array using binary search. This index will be where the key and the new Storage node will be placed in &lt;code&gt;keys&lt;/code&gt; and &lt;code&gt;nodes&lt;/code&gt; array respectively.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&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;StorageNode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="s"&gt;"""add_node function adds a new node in the system and returns the key
    from the hash space where it was placed
    """&lt;/span&gt;

    &lt;span class="c1"&gt;# handling error when hash space is full.
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_keys&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total_slots&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hash space is full"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hash_fn&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;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total_slots&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# find the index where the key should be inserted in the keys array
&lt;/span&gt;    &lt;span class="c1"&gt;# this will be the index where the Storage Node will be added in the
&lt;/span&gt;    &lt;span class="c1"&gt;# nodes array.
&lt;/span&gt;    &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bisect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_keys&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="c1"&gt;# if we have already seen the key i.e. node already is present
&lt;/span&gt;    &lt;span class="c1"&gt;# for the same key, we raise Collision Exception
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;index&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="ow"&gt;and&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_keys&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&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; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"collision occurred"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Perform data migration
&lt;/span&gt;
    &lt;span class="c1"&gt;# insert the node_id and the key at the same `index` location.
&lt;/span&gt;    &lt;span class="c1"&gt;# this insertion will keep nodes and keys sorted w.r.t keys.
&lt;/span&gt;    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&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="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_keys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Removing a new node from the system
&lt;/h2&gt;

&lt;p&gt;When there is a need to scale down and remove an existing node from the system, we&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;find the position of the node to be removed from the Hash Space&lt;/li&gt;
&lt;li&gt;populate the node to the right with data that was associated with the node to be removed&lt;/li&gt;
&lt;li&gt;remove the node from the Hash Space&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When a node is removed from the system it only affects the files associated with the node itself. All other files and associations remain unaffected, thus minimizing the amount of data to be migrated and mapping required to be changed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fYERFLew--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/82751261-b0e9e400-9dd3-11ea-81ee-3fd3f0187857.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fYERFLew--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/82751261-b0e9e400-9dd3-11ea-81ee-3fd3f0187857.png" alt="Removing a new node from the system - Consistent Hashing"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From the illustration above, we see when node K is removed from the system, we change the associations of files associated with node K to the node that lies to its immediate right i.e. node E. Thus the only files affected and needs migration are the ones associated with node K.&lt;/p&gt;

&lt;p&gt;In order to implement this at a low-level using &lt;code&gt;nodes&lt;/code&gt; and &lt;code&gt;keys&lt;/code&gt; array, we get the index where the node K lies in the &lt;code&gt;keys&lt;/code&gt; array using binary search. Once we have the index we remove the key from the &lt;code&gt;keys&lt;/code&gt; array and Storage Node from the &lt;code&gt;nodes&lt;/code&gt; array present on that index.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;remove_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&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;StorageNode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="s"&gt;"""remove_node removes the node and returns the key
    from the hash space on which the node was placed.
    """&lt;/span&gt;

    &lt;span class="c1"&gt;# handling error when space is empty
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_keys&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;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hash space is empty"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hash_fn&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;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total_slots&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# we find the index where the key would reside in the keys
&lt;/span&gt;    &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bisect_left&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_keys&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="c1"&gt;# if key does not exist in the array we raise Exception
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_keys&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_keys&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"node does not exist"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Perform data migration
&lt;/span&gt;
    &lt;span class="c1"&gt;# now that all sanity checks are done we popping the
&lt;/span&gt;    &lt;span class="c1"&gt;# keys and nodes at the index and thus removing the presence of the node.
&lt;/span&gt;    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_keys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Associating an item to a node
&lt;/h2&gt;

&lt;p&gt;Now that we have seen how consistent hashing helps in keeping data migration, during scale-ups and scale-downs, to a bare minimum; it is time we see how to efficiently we can find the "node to the right" for a given item. The operation to find the association has to be super fast and efficient as it is something that will be invoked for every single read and write that happens on the system.&lt;/p&gt;

&lt;p&gt;To implement this at low-level we again take leverage of binary search and perform this operation in &lt;code&gt;O(log(n))&lt;/code&gt;. We first pass the item to the hash function and fetch the position where the item is hashed in the hash space. This position is then binary searched in the &lt;code&gt;keys&lt;/code&gt; array to obtain the index of the first key which is greater than the position (obtained from the hash function). if there are no keys greater than the position, in the &lt;code&gt;keys&lt;/code&gt; array, we circle back and return the 0th index. The index thus obtained will be the index of the storage node in the &lt;code&gt;nodes&lt;/code&gt; array associated with the item.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="s"&gt;"""Given an item, the function returns the node it is associated with.
    """&lt;/span&gt;
    &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hash_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total_slots&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# we find the first node to the right of this key
&lt;/span&gt;    &lt;span class="c1"&gt;# if bisect_right returns index which is out of bounds then
&lt;/span&gt;    &lt;span class="c1"&gt;# we circle back to the first in the array in a circular fashion.
&lt;/span&gt;    &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bisect_right&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_keys&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="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_keys&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# return the node present at the index
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The source code with the implementation of Consistent Hashing in Python could be found at &lt;a href="https://github.com/arpitbbhayani/consistent-hashing/blob/master/consistent-hashing.ipynb"&gt;github.com/arpitbbhayani/consistent-hashing&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Consistent Hashing is one of the most important algorithms to help us horizontally scale and manage any distributed system. The algorithm does not only work in sharded systems but also finds its application in load balancing, data partitioning, managing server-based sticky sessions, routing algorithms, and many more. A lot of databases owe their scale, performance, and ability to handle the humongous load to Consistent Hashing.&lt;/p&gt;

&lt;h1&gt;
  
  
  References
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Hash_function"&gt;Hash Functions - Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Consistent_hashing"&gt;Consistent Hashing - Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://web.stanford.edu/class/cs168/l/l1.pdf"&gt;Consistent Hashing - Stanford&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.akamai.com/us/en/multimedia/documents/technical-publication/consistent-hashing-and-random-trees-distributed-caching-protocols-for-relieving-hot-spots-on-the-world-wide-web-technical-publication.pdf"&gt;Consistent Hashing and RandomTrees&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.allthingsdistributed.com/files/amazon-dynamo-sosp2007.pdf"&gt;Dynamo: Amazon’s Highly Available Key-value Store&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Other articles you might like:
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/python-caches-integers"&gt;Python Caches Integers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/fractional-cascading"&gt;Fractional Cascading - Speeding up Binary Searches&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/copy-on-write"&gt;Copy-on-Write Semantics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/mysql-cache"&gt;What makes MySQL LRU cache scan resistant&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/fsm"&gt;Building Finite State Machines with Python Coroutines&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;This article was originally published on my &lt;a href="https://arpitbhayani.me/blogs/consistent-hashing"&gt;blog - Consistent Hashing&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you liked what you read, subscribe to my newsletter and get the post delivered directly to your inbox and give me a shout-out &lt;a href="https://twitter.com/arpit_bhayani"&gt;@arpit_bhayani&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://arpit.substack.com"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lIXNVWfY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/81502081-6eb3a380-92f9-11ea-8039-fe665d145b2d.png" alt="Subscribe to Arpit's newsletter"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>distributedsystems</category>
    </item>
    <item>
      <title>Python Caches Integers</title>
      <dc:creator>Arpit Bhayani</dc:creator>
      <pubDate>Sun, 17 May 2020 17:35:00 +0000</pubDate>
      <link>https://dev.to/arpit_bhayani/python-caches-integers-3chh</link>
      <guid>https://dev.to/arpit_bhayani/python-caches-integers-3chh</guid>
      <description>&lt;p&gt;An integer in Python is not a traditional 2, 4, or 8-byte implementation but rather it is implemented as an array of digits in base 2^30 which enables Python to support &lt;a href="https://arpitbhayani.me/blogs/super-long-integers"&gt;super long integers&lt;/a&gt;. Since there is no explicit limit on the size, working with integers in Python is extremely convenient as we can carry out operations on very long numbers without worrying about integer overflows. This convenience comes at a cost of allocation being expensive and trivial operations like addition, multiplication, division being inefficient.&lt;/p&gt;

&lt;p&gt;Each integer in python is implemented as a C structure illustrated below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;_longobject&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="n"&gt;Py_ssize_t&lt;/span&gt;    &lt;span class="n"&gt;ob_refcnt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;      &lt;span class="c1"&gt;// &amp;lt;--- holds reference count&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="n"&gt;Py_ssize_t&lt;/span&gt;    &lt;span class="n"&gt;ob_size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;        &lt;span class="c1"&gt;// &amp;lt;--- holds number of digits&lt;/span&gt;
    &lt;span class="n"&gt;digit&lt;/span&gt;         &lt;span class="n"&gt;ob_digit&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;    &lt;span class="c1"&gt;// &amp;lt;--- holds the digits in base 2^30&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It is observed that smaller integers in the range -5 to 256, are used very frequently as compared to other longer integers and hence to gain performance benefit Python preallocates this range of integers during initialization and makes them singleton and hence every time a smaller integer value is referenced instead of allocating a new integer it passes the reference of the corresponding singleton.&lt;/p&gt;

&lt;p&gt;Here is what &lt;a href="https://docs.python.org/3/c-api/long.html#c.PyLong_FromLong"&gt;Python's official documentation&lt;/a&gt; says about this preallocation&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The current implementation keeps an array of integer objects for all integers between -5 and 256 when you create an int in that range you actually just get back a reference to the existing object.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In the CPython's &lt;a href="https://github.com/python/cpython/"&gt;source code&lt;/a&gt; this optimization can be traced in the macro &lt;code&gt;IS_SMALL_INT&lt;/code&gt; and the function &lt;a href="https://github.com/python/cpython/blob/master/Objects/longobject.c#L40"&gt;&lt;code&gt;get_small_int&lt;/code&gt;&lt;/a&gt; in &lt;a href="https://github.com/python/cpython/blob/master/Objects/longobject.c"&gt;longobject.c&lt;/a&gt;. This way python saves a lot of space and computation for commonly used integers.&lt;/p&gt;

&lt;h1&gt;
  
  
  Verifying smaller integers are indeed a singleton
&lt;/h1&gt;

&lt;p&gt;For a CPython implementation, the in-built &lt;a href="https://docs.python.org/3/library/functions.html#id"&gt;&lt;code&gt;id&lt;/code&gt; function&lt;/a&gt; returns the address of the object in memory. This means if the smaller integers are indeed singleton then the &lt;code&gt;id&lt;/code&gt; function should return the same memory address for two instances of the same value while multiple instances of larger values should return different ones, and this is indeed what we observe&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;36&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;36&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="bp"&gt;True&lt;/span&gt;


&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;257&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;257&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="bp"&gt;False&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The singletons can also be seen in action during computations. In the example below, we reach the same target value &lt;code&gt;6&lt;/code&gt; by performing two operations on three different numbers, 2, 4, and 10, and we see the &lt;code&gt;id&lt;/code&gt; function returning the same memory reference in both the cases.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&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; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="bp"&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Verifying if these integers are indeed referenced often
&lt;/h1&gt;

&lt;p&gt;We have established that Python indeed is consuming smaller integers through their corresponding singleton instances, without reallocating them every time. Now we verify the hypothesis that Python indeed saves a bunch of allocations during its initialization through these singletons. We do this by checking the reference counts of each of the integer values.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reference Counts
&lt;/h2&gt;

&lt;p&gt;Reference count holds the number of different places there are that have a reference to the object. Every time an object is referenced the &lt;code&gt;ob_refcnt&lt;/code&gt;, in its structure, is increased by &lt;code&gt;1&lt;/code&gt;, and when dereferenced the count is decreased by &lt;code&gt;1&lt;/code&gt;. When the reference count becomes &lt;code&gt;0&lt;/code&gt; the object is garbage collected.&lt;/p&gt;

&lt;p&gt;In order to get the current reference count of an object, we use the function &lt;code&gt;getrefcount&lt;/code&gt; from the &lt;code&gt;sys&lt;/code&gt; module.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ref_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getrefcount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;11&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;When we do this for all the integers in range -5 to 300 we get the following distribution&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zkftF-mC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/82141240-1e38ca80-9852-11ea-8133-fd8e1b26fc01.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zkftF-mC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/82141240-1e38ca80-9852-11ea-8133-fd8e1b26fc01.png" alt="Reference counts of interger values"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The above graph suggests that the reference count of smaller integer values is high indicating heavy usage and it decreases as the value increases which asserts the fact that there are many objects referencing smaller integer values as compared to larger ones during python initialization.&lt;/p&gt;

&lt;p&gt;The value &lt;code&gt;0&lt;/code&gt; is referenced the most - &lt;code&gt;359&lt;/code&gt; times while along the long tail we see spikes in reference counts at powers of 2 i.e. 32, 64, 128, and 256. Python during its initialization itself requires small integer values and hence by creating singletons it saves about &lt;code&gt;1993&lt;/code&gt; allocations.&lt;/p&gt;

&lt;p&gt;The reference counts were computed on a freshly spun python which means during initialization it requires some integers for computations and these are facilitated by creating singleton instances of smaller values.&lt;/p&gt;

&lt;p&gt;In usual programming, the smaller integer values are accessed much more frequently than larger ones, having singleton instances of these saves python a bunch of computation and allocations.&lt;/p&gt;

&lt;h1&gt;
  
  
  References
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3/c-api/intro.html#objects-types-and-reference-counts"&gt;Python Object Types and Reference Counts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/super-long-integers"&gt;How python implements super-long integers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://jakevdp.github.io/blog/2014/05/09/why-python-is-slow/"&gt;Why Python is Slow: Looking Under the Hood&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Other articles you may like
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/fractional-cascading"&gt;Fractional Cascading - Speeding up Binary Searches&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/copy-on-write"&gt;Copy-on-Write Semantics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/mysql-cache"&gt;What makes MySQL LRU cache scan resistant&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/fsm"&gt;Building Finite State Machines with Python Coroutines&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/bayesian-average"&gt;Solving an age-old problem using Bayesian Average&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;This article was originally published on my &lt;a href="https://arpitbhayani.me/blogs/python-caches-integers"&gt;blog - Python Caches Integers&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you liked what you read, subscribe to my newsletter and get the post delivered directly to your inbox and give me a shout-out &lt;a href="https://twitter.com/arpit_bhayani"&gt;@arpit_bhayani&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://arpit.substack.com"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lIXNVWfY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/81502081-6eb3a380-92f9-11ea-8039-fe665d145b2d.png" alt="Subscribe to Arpit's newsletter"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
    </item>
    <item>
      <title>Fractional Cascading - Speeding up Binary Searches</title>
      <dc:creator>Arpit Bhayani</dc:creator>
      <pubDate>Mon, 11 May 2020 03:33:30 +0000</pubDate>
      <link>https://dev.to/arpit_bhayani/fractional-cascading-speeding-up-binary-searches-4cma</link>
      <guid>https://dev.to/arpit_bhayani/fractional-cascading-speeding-up-binary-searches-4cma</guid>
      <description>&lt;p&gt;Binary Search is an algorithm that finds the position of a target value in a sorted list. The algorithm exploits the fact that the list is sorted, and is devised such that is does not have to even look at all the &lt;code&gt;n&lt;/code&gt; elements, to decide if a value is present or not. In the worst case, the algorithm checks the &lt;code&gt;log(n)&lt;/code&gt; number of elements to make the decision.&lt;/p&gt;

&lt;p&gt;Binary Search could be tweaked to output the position of the target value, or return the position of the smallest number greater than the target value i.e. position where the target value should have been present in the list.&lt;/p&gt;

&lt;p&gt;Things become more interesting when we have to perform an iterative binary search on &lt;code&gt;k&lt;/code&gt; lists in which we find the target value in each of the &lt;code&gt;k&lt;/code&gt; lists independently. The problem statement could be formally defined as&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Given &lt;code&gt;k&lt;/code&gt; lists of &lt;code&gt;n&lt;/code&gt; sorted integers each, and a target value &lt;code&gt;x&lt;/code&gt;, return the position of the smallest value greater than or equal to &lt;code&gt;x&lt;/code&gt; in each of the &lt;code&gt;k&lt;/code&gt; lists. Preprocessing of the list is allowed before answering the queries.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  The naive approach - k binary searches
&lt;/h1&gt;

&lt;p&gt;The expected output of this iterative search is the position of the smallest value greater than or equal to &lt;code&gt;x&lt;/code&gt; in each of the &lt;code&gt;k&lt;/code&gt; lists. This is a classical Binary Search problem and hence in this approach, we fire &lt;code&gt;k&lt;/code&gt; binary searches on &lt;code&gt;k&lt;/code&gt; lists for the target value &lt;code&gt;x&lt;/code&gt; and collect the positions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6rRf9Yxr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/81492614-dbf21500-92b6-11ea-9f75-29eb3522186f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6rRf9Yxr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/81492614-dbf21500-92b6-11ea-9f75-29eb3522186f.png" alt="k-binary searches"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Python has an in-built module called &lt;code&gt;bisect&lt;/code&gt; which has the function &lt;code&gt;bisect_left&lt;/code&gt; which outputs the smallest value greater than or equal to &lt;code&gt;x&lt;/code&gt; in a list which is exactly what we need to output and hence python-based solution using this k-binary searches approach could be&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;bisect&lt;/span&gt;

&lt;span class="n"&gt;arr&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;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;54&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;79&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;93&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;27&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;35&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;46&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;47&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;72&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;44&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;62&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;66&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;94&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;35&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;46&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;79&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;83&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_positions_k_bin_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; 
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;bisect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bisect_left&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; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;get_positions_k_bin_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Time and Space Complexity
&lt;/h2&gt;

&lt;p&gt;Each of the &lt;code&gt;k&lt;/code&gt; lists have size &lt;code&gt;n&lt;/code&gt; and we know the time complexity of performing a binary search in one list of &lt;code&gt;n&lt;/code&gt; elements is &lt;code&gt;O(log(n))&lt;/code&gt;. Hence we deduce that the time complexity of this k-binary searches approach is &lt;code&gt;O(klog(n))&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;This approach does not really require any additional space and hence the space complexity is &lt;code&gt;O(1)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The k-binary searches approach is thus super-efficient on space but not so much on time. Hence by trading some space, we could reap some benefits on time, and on this exact principle, the unified binary search approach is based.&lt;/p&gt;

&lt;h1&gt;
  
  
  Unified binary search
&lt;/h1&gt;

&lt;p&gt;This approach uses some extra space, preprocessing and computations to reduce search time. The preprocessing actually involves precomputing the positions of all elements in all the &lt;code&gt;k&lt;/code&gt; lists. This precomputation enables us to perform just one binary search and get the required precalculated positions in one go.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preprocess
&lt;/h2&gt;

&lt;p&gt;The preprocessing is done in two phases; in the first phase, we compute a position tuple for each element and associate it with the same. In phase two of preprocessing, we create an auxiliary list containing all the elements of all the lists, on which we then perform a binary search for the given target value.&lt;/p&gt;

&lt;h3&gt;
  
  
  Computing position tuple for each element
&lt;/h3&gt;

&lt;p&gt;Position tuple is a &lt;code&gt;k&lt;/code&gt; item tuple where every &lt;code&gt;i&lt;/code&gt;th item denotes the position of the associated element in the &lt;code&gt;i&lt;/code&gt;th list. We compute this tuple by performing a binary search on all the &lt;code&gt;k&lt;/code&gt; lists treating the element as the target value.&lt;/p&gt;

&lt;p&gt;From the example above, the position tuple of 4th element in the 4th list i.e 79 will be &lt;code&gt;[3, 5, 4, 3]&lt;/code&gt; which denotes its position in all 4 lists. In list 1, 79 is at index &lt;code&gt;3&lt;/code&gt;, in list 2, 79 is actually out of bounds but would be inserted at index &lt;code&gt;5&lt;/code&gt; hence the output &lt;code&gt;5&lt;/code&gt;, we could also have returned a value marking out of bounds, like &lt;code&gt;-2&lt;/code&gt;, in list 3, 79 is not present but the smallest number greater than 79 is 94 and which is at index &lt;code&gt;4&lt;/code&gt; and in list 4, 79 is present at index &lt;code&gt;3&lt;/code&gt;. This makes the position tuple for 79 to be &lt;code&gt;[3, 5, 4, 3]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Given a 2-dimensional array &lt;code&gt;arr&lt;/code&gt; we compute the position tuple for an element &lt;code&gt;(i, j)&lt;/code&gt; by performing a binary search on all &lt;code&gt;k&lt;/code&gt; lists as shown in python code below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;enumerate&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;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;positions&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;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bisect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bisect_left&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Creating a huge list
&lt;/h3&gt;

&lt;p&gt;Once we have all the position tuples and they are well associated with the corresponding elements, we create an auxiliary list of size &lt;code&gt;k * n&lt;/code&gt; that holds all the elements from all the &lt;code&gt;k&lt;/code&gt; lists. This auxiliary list is again kept sorted so that we could perform a binary search on it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Working
&lt;/h2&gt;

&lt;p&gt;Given a target value, we perform a binary search in the above auxiliary list and get the smallest element greater than or equal to this target value. Once we get the element, we now get the associated position tuple. This position tuple is precisely the position of the target element in all the &lt;code&gt;k&lt;/code&gt; lists. Thus by performing one binary search in this huge list, we are able to get the required positions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MMdVQZRd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/81492609-ca107200-92b6-11ea-8fdf-999852f4d9b1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MMdVQZRd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/81492609-ca107200-92b6-11ea-8fdf-999852f4d9b1.png" alt="unified binary search"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Complexity
&lt;/h2&gt;

&lt;p&gt;We are performing binary search just once on the list of size &lt;code&gt;k * n&lt;/code&gt; hence, the time complexity of this approach is &lt;code&gt;O(log(kn))&lt;/code&gt; which is a huge improvement over the k-binary searches approach where it was &lt;code&gt;O(klog(n))&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This approach, unlike k-binary searches, requires an additional space of &lt;code&gt;O(k.kn)&lt;/code&gt; since each element holds &lt;code&gt;k&lt;/code&gt; item position tuple and there are in all &lt;code&gt;k * n&lt;/code&gt; elements.&lt;/p&gt;

&lt;p&gt;Fractional cascading is something that gives us the best of both worlds by creating bridges between the lists and narrowing the scope of binary searches on subsequent iterations. Let's find out how.&lt;/p&gt;

&lt;h1&gt;
  
  
  Fractional Cascading
&lt;/h1&gt;

&lt;p&gt;Fractional cascading is a technique through which we speed up the iterative binary searches by creating bridges between the lists. The main idea behind this approach is to dampen the need to perform binary searches on subsequent lists after performing the search on one.&lt;/p&gt;

&lt;p&gt;In the k-binary searches approach, we solved the problem by performing &lt;code&gt;k&lt;/code&gt; binary searches on &lt;code&gt;k&lt;/code&gt; lists. If, after the binary search on the first list, we would have known a range within which the target value was present in the 2nd list, we would have limited our search within that subset which helps us save a bunch of computation time. The bridges, defined above, provides us with a shortcut to reach the subset of the other list where that target value would be present.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dEqx2UmV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/81495324-241c3200-92cd-11ea-9d7d-9c9b0911071b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dEqx2UmV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/81495324-241c3200-92cd-11ea-9d7d-9c9b0911071b.png" alt="Fractional Cascading the Idea"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fractional cascading is just an idea through which we could speed up binary searches, implementations vary with respect to the underlying data. The bridges could be implemented using pointers, graphs, or array indexes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preprocess
&lt;/h2&gt;

&lt;p&gt;Preprocessing is a super-critical step in fractional cascading because it is responsible for speeding up the iterative binary searches. Preprocessing actually sets up all the bridges from all the elements from one list to the range of items in the lower list where the element could be found. These bridges then cascade to all the lists on the lower levels.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create Auxiliary Lists
&lt;/h3&gt;

&lt;p&gt;The first step in pre-processing is to create &lt;code&gt;k&lt;/code&gt; auxiliary lists from &lt;code&gt;k&lt;/code&gt; original lists. These lists are created bottom-up which means lists on the lower levels are created first - &lt;code&gt;M(i+1)&lt;/code&gt; is created before &lt;code&gt;M(i)&lt;/code&gt;. An auxiliary list &lt;code&gt;M(i)&lt;/code&gt; is created as a sorted list of elements of the original list &lt;code&gt;L(i)&lt;/code&gt; and half of the previously created auxiliary list &lt;code&gt;M(i+1)&lt;/code&gt;. The half elements of auxiliary lists are chosen by picking every other element from it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--K7_TALO_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/81494077-8112ea80-92c3-11ea-9416-bb2422334744.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--K7_TALO_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/81494077-8112ea80-92c3-11ea-9416-bb2422334744.png" alt="Create Auxiliary Lists"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By picking every other element from lower-level lists, we fill the gaps in value ranges in the original list &lt;code&gt;L(i)&lt;/code&gt;, giving us a uniform spread of values across all auxiliary lists. Another advantage of picking every other element is that we eradicate the need for performing binary searches on subsequent lists altogether. Now we only need to perform a binary search for list &lt;code&gt;M(0)&lt;/code&gt; and for every other list, we only need to check the element we reach via the bridge and an element before that - a constant time comparison.&lt;/p&gt;

&lt;h3&gt;
  
  
  Position tuples
&lt;/h3&gt;

&lt;p&gt;A position tuple for Fractional Cascading is a 2 item tuple, associated with each element of the auxiliary list, where the first item is the position of the element in the original list on the same level - serving as the required position - and the second element is the position of the element in the auxiliary list on the lower level - serving as the bridge from one level to another.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_tk8nQxT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/81494709-92122a80-92c8-11ea-89c0-e180a735eb2d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_tk8nQxT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/81494709-92122a80-92c8-11ea-89c0-e180a735eb2d.png" alt="Create position pointerss"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The position tuple for each element in the auxiliary array can be created by doing a binary search on the original list and the auxiliary list on the lower level. Given a 2-dimensional array &lt;code&gt;arr&lt;/code&gt; and auxiliary lists &lt;code&gt;m_arr&lt;/code&gt; we compute the position tuples for element &lt;code&gt;(i, j)&lt;/code&gt; by performing a binary search on all &lt;code&gt;k&lt;/code&gt; original and auxiliary lists as shown in python code below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_arr&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_arr&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;
        &lt;span class="n"&gt;pointers&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;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="n"&gt;bisect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bisect_left&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&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; &lt;span class="n"&gt;m_arr&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;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
            &lt;span class="n"&gt;bisect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bisect_left&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_arr&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;m_arr&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;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Fractional Cascading in action
&lt;/h2&gt;

&lt;p&gt;We start by performing a binary search on the first auxiliary list &lt;code&gt;M(0)&lt;/code&gt; from which we get the element corresponding to the target value. The position tuple for this element contains the position corresponding to the original list &lt;code&gt;L(0)&lt;/code&gt; and bridge that will take us to the list &lt;code&gt;M(1)&lt;/code&gt;. Now when we move to the list &lt;code&gt;M(1)&lt;/code&gt; through the bridge and have reached the index &lt;code&gt;b&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Since auxiliary lists have uniform range spread, because of every other element being promoted, we are sure that the target value should be checked again at the index &lt;code&gt;b&lt;/code&gt; and &lt;code&gt;b - 1&lt;/code&gt;; because if the value was any lower it would have been promoted and bridged to other value and hence the trail we trace would be different from what we are tracing now.&lt;/p&gt;

&lt;p&gt;Once we know which of the &lt;code&gt;b&lt;/code&gt; and &lt;code&gt;b-1&lt;/code&gt; index to pick (depending on the values at the index and the target value) we add the first item of the position tuple to the solution set and move the auxiliary list on the lower level and the entire process continues.&lt;/p&gt;

&lt;p&gt;Once we reach the last auxiliary list and process the position tuple there and pick the element, our solution set contains the required positions and we can stop the iteration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_locations_fractional_cascading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; 
    &lt;span class="n"&gt;locations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

    &lt;span class="c1"&gt;# the first and only binary search on the auxiliary list M[0]
&lt;/span&gt;    &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bisect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bisect_left&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_arr&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; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# loc always holds the required location from the original list on same level
&lt;/span&gt;    &lt;span class="c1"&gt;# next_loc holds the bridge index on the lower level
&lt;/span&gt;    &lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;next_loc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pointers&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;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="c1"&gt;# adding loc to the solution
&lt;/span&gt;    &lt;span class="n"&gt;locations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&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;m_arr&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
        &lt;span class="c1"&gt;# we check for the element we reach through the bridge
&lt;/span&gt;        &lt;span class="c1"&gt;# and the one before it and make the decision to go with one
&lt;/span&gt;        &lt;span class="c1"&gt;# depending on the target value.
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;m_arr&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;&lt;span class="n"&gt;next_loc&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;
            &lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;next_loc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pointers&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;&lt;span class="n"&gt;next_loc&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;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;next_loc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pointers&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;&lt;span class="n"&gt;next_loc&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

        &lt;span class="c1"&gt;# adding loc to the solution
&lt;/span&gt;        &lt;span class="n"&gt;locations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# returning the required locations
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;locations&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The entire working code could be found here &lt;a href="https://github.com/arpitbbhayani/fractional-cascading/blob/master/fractional-cascading.ipynb"&gt;github.com/arpitbbhayani/fractional-cascading&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Time and space complexity
&lt;/h2&gt;

&lt;p&gt;In Fractional Cascading, we perform binary search once on the auxiliary list &lt;code&gt;M(0)&lt;/code&gt; and then make &lt;code&gt;k&lt;/code&gt; constant comparisons for each of the subsequent levels; hence the time complexity is &lt;code&gt;O(k + log(n))&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The auxiliary lists could at most contain all the elements from the original list plus &lt;code&gt;1/2 |L(n)| + 1/4 |L(n-1)| + 1/8 |L(n-2)| + ...&lt;/code&gt; which is less than all elements of the original list combined. Thus the total size of the auxiliary list cannot exceed twice the original lists. The position tuple for each of the elements is also a constant 2 item tuple thus the space complexity of Fractional Cascading is &lt;code&gt;O(kn)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Thus Fractional Cascading has time complexity very close to the k-binary searches approach with a very low space complexity as compared to the unified binary searches approach; thus giving us the best of both worlds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fractional Cascading in real world
&lt;/h2&gt;

&lt;p&gt;Fractional Cascading is used in &lt;a href="http://pages.cs.wisc.edu/~yinan/fdtree.html"&gt;FD-Trees&lt;/a&gt; which are used in databases to address the asymmetry of read-write speeds in tree indexing on the flash disk. Fractional cascading is typically used in &lt;a href="https://en.wikipedia.org/wiki/Range_searching"&gt;range search&lt;/a&gt; data structures like &lt;a href="https://en.wikipedia.org/wiki/Segment_tree"&gt;Segment Trees&lt;/a&gt; to speed up lookups and filters.&lt;/p&gt;

&lt;h1&gt;
  
  
  References
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Fractional_cascading"&gt;Fractional Cascading - Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.cs.princeton.edu/~chazelle/pubs/FractionalCascading1.pdf"&gt;Fractional Cascading - Original Paper by Bernard Chazelle and Leonidas Guibas&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.cse.iitd.ernet.in/~ssen/journals/frac.pdf"&gt;Fractional Cascading Revisited&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://cs.brown.edu/courses/cs252/misc/resources/lectures/pdf/notes08.pdf"&gt;Fractional Cascading - Brown University&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Other articles you might like:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/copy-on-write"&gt;Copy-on-Write Semantics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/mysql-cache"&gt;What makes MySQL LRU cache scan resistant&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/fsm"&gt;Building Finite State Machines with Python Coroutines&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/bayesian-average"&gt;Solving an age-old problem using Bayesian Average &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/rule-30"&gt;Pseudorandom numbers using Cellular Automata - Rule 30&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;This article was originally published on my &lt;a href="https://arpitbhayani.me/blogs/fractional-cascading"&gt;blog - Fractional Cascading - Speeding up Binary Searches&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you liked what you read, subscribe to my newsletter and get the post delivered directly to your inbox and give me a shout-out &lt;a href="https://twitter.com/arpit_bhayani"&gt;@arpit_bhayani&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://arpit.substack.com"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lIXNVWfY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/81502081-6eb3a380-92f9-11ea-8039-fe665d145b2d.png" alt="Subscribe to Arpit's newsletter"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>algorithm</category>
    </item>
    <item>
      <title>Copy-on-Write Semantics</title>
      <dc:creator>Arpit Bhayani</dc:creator>
      <pubDate>Sun, 03 May 2020 12:56:18 +0000</pubDate>
      <link>https://dev.to/arpit_bhayani/copy-on-write-semantics-opj</link>
      <guid>https://dev.to/arpit_bhayani/copy-on-write-semantics-opj</guid>
      <description>&lt;p&gt;Copy-On-Write, abbreviately referred to as CoW suggests deferring the copy process until the first modification. A resource is usually copied when we do not want the changes made in the either to be visible to the other. A resource here could be anything - an in-memory page, a database disk block, an item in a structure, or even the entire data structure.&lt;/p&gt;

&lt;p&gt;CoW suggests that we first copy by reference and let both instances share the same resource and just before the first modification we clone the original resource and then apply the updates.&lt;/p&gt;

&lt;h1&gt;
  
  
  Deep copying
&lt;/h1&gt;

&lt;p&gt;The process of creating a pure clone of the resource is called &lt;a href="https://en.wikipedia.org/wiki/Object_copying#Deep_copy"&gt;Deep Copying&lt;/a&gt; and it copies not only the immediate content but also all the remote resources that are referenced within it. Thus if we were to deep copy a &lt;a href="https://en.wikipedia.org/wiki/Linked_list"&gt;Linked List&lt;/a&gt; we do not just copy the head pointer, rather we clone all the nodes of the list and create an entirely new list from the original one. A C++ function for deep copying a Linked List is as illustrated below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;node&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;node&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &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;head&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;node&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;nhead&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;node&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;calloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;node&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;nhead&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;node&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;node&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nhead&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;node&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;calloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;node&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;nhead&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qwO6uSQ6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/80907205-76d87580-8d32-11ea-88a8-153a94d92d72.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qwO6uSQ6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/80907205-76d87580-8d32-11ea-88a8-153a94d92d72.png" alt="deep copying a linked list"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Going by the details, we understand that deep copying is a very memory-intensive operation, and hence we try to not do it very often.&lt;/p&gt;

&lt;h1&gt;
  
  
  Why Copy-on-Write
&lt;/h1&gt;

&lt;p&gt;Copy-on-Write, as established earlier, suggests we defer the copy operation until the first modification is requested. The approach suits the best when the traversal and access operations vastly outnumber the mutations. CoW has a number of advantages, some of them are&lt;/p&gt;

&lt;h2&gt;
  
  
  Perceived performance gain
&lt;/h2&gt;

&lt;p&gt;By having a CoW, the process need not wait for the deep copy to happen, instead, it could directly proceed by just doing a copy-by-reference, where the resource is shared between the two, which is much faster than a deep copy and thus gaining a performance boost. Although we cannot totally get rid of deep copy because once some modification is requested the deep copy has to be triggered.&lt;/p&gt;

&lt;p&gt;A particular example where we gain a significant performance boost is during the &lt;code&gt;fork&lt;/code&gt; system call.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;fork&lt;/code&gt; system call creates a child process that is a spitting copy of its parent. During this call, if the parent's program space is huge and we trigger a deep copy, the time taken to create the child process will shoot up. But if we just do copy-by-reference the child process could be spun super fast. Once the child decides to make some modifications to its program space, then we trigger the deep copy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Better resource management
&lt;/h2&gt;

&lt;p&gt;CoW gives us an optimistic way to manage memory. One peculiar property that CoW exploits are how, before any modifications to the copied instance, both the original and the copied resources are exactly the same. The readers, thus, cannot distinguish if they are reading from the original resource or the copied one.&lt;/p&gt;

&lt;p&gt;Things change when the first modification is made to the copied instance and that's where readers of the corresponding resource would expect to see things differently. But what if the copied instance is never modified?&lt;/p&gt;

&lt;p&gt;Since there are no modifications, in CoW, the deep copy would never happen and hence the only operation that ever happened was a super-fast copy-by-reference of the original resource; and thus we just saved an expensive deep copy operation.&lt;/p&gt;

&lt;p&gt;One very common pattern in OS is called &lt;a href="https://en.wikipedia.org/wiki/Fork%E2%80%93exec"&gt;fork-exec&lt;/a&gt; in which a child process is forked as a spitting copy of its parent but it immediately executes another program, using &lt;code&gt;exec&lt;/code&gt; family of functions, replacing its entire program space. Since the child does not intend to modify its program space ever, inherited from the parent, and just wants to replace it with the new program, deep copy plays no part and is a waste. So if we defer the deep copy operation until modification, the deep copy would never happen and we thus save a bunch of memory and CPU cycles.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include &amp;lt;stdio.h&amp;gt;
&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="c1"&gt;// fork spins the child process and both child and the parent&lt;/span&gt;
    &lt;span class="c1"&gt;// continues to co-exist from this point with the same&lt;/span&gt;
    &lt;span class="c1"&gt;// program space.&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;pid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fork&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;pid&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;
        &lt;span class="c1"&gt;// The entire child program space is replace by the&lt;/span&gt;
        &lt;span class="c1"&gt;// execvp function call.&lt;/span&gt;
        &lt;span class="c1"&gt;// The child continues to execute the `ls` command.&lt;/span&gt;
        &lt;span class="n"&gt;execvp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ls"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Child process will never reach here.&lt;/span&gt;
    &lt;span class="c1"&gt;// hence all memory that was copied from its parent's&lt;/span&gt;
    &lt;span class="c1"&gt;// program space is of no use.&lt;/span&gt;

    &lt;span class="c1"&gt;// The parent will continue its execution and print the&lt;/span&gt;
    &lt;span class="c1"&gt;// following message.&lt;/span&gt;
    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"parent finishes...&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&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;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Updating without locks
&lt;/h2&gt;

&lt;p&gt;Locks are required when we have in-place updates. Multiple writers try to modify the same instance of the resource and hence we need to define a &lt;a href="https://en.wikipedia.org/wiki/Critical_section"&gt;critical section&lt;/a&gt; where the updations happen. This critical section is bounded by locks and any writer who wishes to modify would have to acquire the lock. This streamlines the writers and ensures only one writer could enter the critical section at any point in time, creating a chokepoint.&lt;/p&gt;

&lt;p&gt;If we follow CoW aggressively, which suggests we copy before we write, there will be no in-place updates. All variables during every single write will create a clone, apply updates to it and then in one atomic &lt;a href="https://en.wikipedia.org/wiki/Compare-and-swap"&gt;compare-and-swap&lt;/a&gt; operation switch and start pointing to this newer version; thus eradicating the need for locking entirely. Garbage collection on unused items, with old values, could happen from time to time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0oF89GFV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/80912595-9fc13080-8d5b-11ea-9b73-599b673e6715.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0oF89GFV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/80912595-9fc13080-8d5b-11ea-9b73-599b673e6715.png" alt="Updating variables without locks"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Versioning and point in time snapshots
&lt;/h2&gt;

&lt;p&gt;If we aggressively follow CoW then on every write we create a clone of the original resource and apply updates to it. If we do not garbage collect the older unused instances, what we get is the history of the resource that shows us how it has been changing with time (every write operation).&lt;/p&gt;

&lt;p&gt;Each update creates a new version of the resource and thus we get resource versioning; enabling us to take point-in-time snapshots. This particular behavior is used by all collaborative document tools, like &lt;a href="https://en.wikipedia.org/wiki/Google_Docs"&gt;Google Docs&lt;/a&gt;, to provide document versioning. Point-in-time snapshots are also used in the databases to take timely backups allowing us to have a rollback and recovery plan in case of some data loss or worse a database failure.&lt;/p&gt;

&lt;h1&gt;
  
  
  Implementing CoW
&lt;/h1&gt;

&lt;p&gt;CoW is just a technique and it tells us what and not how. The implementation is all in the hands of the system and depending on the type of resource being CoW'ed the implementation details differ.&lt;/p&gt;

&lt;p&gt;The naive way to perform copy operation is by doing a deep copy which, as established before, is a super inefficient way. We can do a lot better than this by understanding the nuances of the underlying resource. To gain a deeper understanding we see how efficiently we could make CoW Binary Tree &lt;a href="https://en.wikipedia.org/wiki/Binary_tree"&gt;Binary Tree&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Efficient Copy-on-write on a Binary Tree
&lt;/h2&gt;

&lt;p&gt;Given a Binary Tree &lt;code&gt;A&lt;/code&gt; we create a copy &lt;code&gt;B&lt;/code&gt; such that any modifications by &lt;code&gt;A&lt;/code&gt; are not visible to &lt;code&gt;B&lt;/code&gt; and any modifications on &lt;code&gt;B&lt;/code&gt; are not visible to &lt;code&gt;A&lt;/code&gt;. The simplest way to achieve this is by cloning all the nodes of the tree, their pointer references, and create a second tree which is then pointed by &lt;code&gt;B&lt;/code&gt; - as illustrated in the diagram below. Any modifications made to either tree will not be visible to the other because their entire space is mutually exclusive.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0icJ2aLC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/80859895-b3986400-8c81-11ea-9ebe-829540df77d5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0icJ2aLC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/80859895-b3986400-8c81-11ea-9ebe-829540df77d5.png" alt="Deep Copying a Binary Tree"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Copy-on-Write semantics suggest an optimistic approach where &lt;code&gt;B&lt;/code&gt; instead of pointing to the cloned &lt;code&gt;A&lt;/code&gt;, shares the same reference as &lt;code&gt;A&lt;/code&gt; which means it also points to the exact same tree as &lt;code&gt;A&lt;/code&gt;. Now say, we modify the node &lt;code&gt;2&lt;/code&gt; in tree &lt;code&gt;B&lt;/code&gt; and change its value to &lt;code&gt;9&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Observing closely we find that a lot of pointers could be reused and hence a better approach would be to only copy the path from the updating node till the root, keeping all other pointers references same, and let &lt;code&gt;B&lt;/code&gt; point to this new root, as shown in the illustration.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qtcF6r9w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/80869877-7606fb80-8cc0-11ea-8a9b-2b7312a59f11.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qtcF6r9w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/80869877-7606fb80-8cc0-11ea-8a9b-2b7312a59f11.png" alt="Copy-on-Write a Binary Tree"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thus instead of maintaining two separate mutually exclusive trees, we make space partially exclusive depending on which node is updated and in the process make things efficient with respect to memory and time. This behavior is core to a family of data structures called &lt;a href="https://en.wikipedia.org/wiki/Persistent_data_structure"&gt;Persistent Data Structures&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Fun fact: You can model Time Travel using Copy-on-Write semantics.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Why shouldn't we Copy-on-Write
&lt;/h1&gt;

&lt;p&gt;CoW is an expensive process if done aggressively. If on every single write, we create a copy then in a system that is write-heavy, things could go out of hand very soon. A lot of CPU cycles will be occupied for doing garbage collections and thus stalling the core processes. Picking which battles to win is important while choosing something as critical as Copy-on-Write.&lt;/p&gt;

&lt;h1&gt;
  
  
  References
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Copy-on-write"&gt;Copy on Write&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Persistent_data_structure"&gt;Persistent Data Structures&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Fork%E2%80%93exec"&gt;Fork Exec Pattern&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Other articles you might like:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/mysql-cache"&gt;What makes MySQL LRU cache scan resistant&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/fsm"&gt;Building Finite State Machines with Python Coroutines&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/bayesian-average"&gt;Solving an age-old problem using Bayesian Average &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/rule-30"&gt;Pseudorandom numbers using Cellular Automata - Rule 30&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/function-overloading"&gt;Overload Functions in Python&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;This article was originally published on my &lt;a href="https://arpitbhayani.me/blogs/copy-on-write"&gt;blog - Copy-on-Write Semantics&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you liked what you read, subscribe to my newsletter and get the post delivered directly to your inbox and give me a shout-out &lt;a href="https://twitter.com/arpit_bhayani"&gt;@arpit_bhayani&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://arpit.substack.com"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WpJKYG2m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/79068776-07e59f00-7ce7-11ea-8eff-3918556a3682.png" alt="Subscribe to Arpit's newsletter"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>database</category>
      <category>operatingsystems</category>
      <category>datastructures</category>
      <category>locks</category>
    </item>
    <item>
      <title>What makes MySQL LRU cache scan resistant</title>
      <dc:creator>Arpit Bhayani</dc:creator>
      <pubDate>Sun, 26 Apr 2020 11:43:40 +0000</pubDate>
      <link>https://dev.to/arpit_bhayani/what-makes-mysql-lru-cache-scan-resistant-2cjl</link>
      <guid>https://dev.to/arpit_bhayani/what-makes-mysql-lru-cache-scan-resistant-2cjl</guid>
      <description>&lt;p&gt;Disk reads are 4x (for SSD) to 80x (for magnetic disk) &lt;a href="https://gist.github.com/hellerbarde/2843375"&gt;slower&lt;/a&gt; as compared to main memory (RAM) reads and hence it becomes extremely important for a database to utilize main memory as much as it can, and be super-performant while keeping its latencies to a bare minimum. Engines cannot simply replace disks with RAM because of volatility and cost, hence it needs to strike a balance between the two - maximize main-memory utilization and minimize the disk access.&lt;/p&gt;

&lt;p&gt;The database engine virtually splits the data files into pages. A page is a unit which represents how much data the engine transfers at any one time between the disk (the data files) and the main memory. It is usually a few kilobytes 4KB, 8KB, 16KB, 32KB, etc. and is configurable via engine parameters. Because of its bulky size, a page can hold one or multiple rows of a table depending on how much data is in each row i.e. the length of the row.&lt;/p&gt;

&lt;h1&gt;
  
  
  Locality of reference
&lt;/h1&gt;

&lt;p&gt;Database systems exhibit a strong and predictable behaviour called &lt;a href="https://en.wikipedia.org/wiki/Locality_of_reference"&gt;locality of reference&lt;/a&gt; which suggests the access pattern of a page and its neighbours.&lt;/p&gt;

&lt;h2&gt;
  
  
  Spatial Locality of Reference
&lt;/h2&gt;

&lt;p&gt;The spatial locality of reference suggests if a row is accessed, there is a high probability that the neighbouring rows will be accessed in the near future.&lt;/p&gt;

&lt;p&gt;Having a larger page size addresses this situation to some extent. As one page could fit multiple rows, this means when that page is cached in main memory, the engine saves a disk read if the neighbouring rows residing on the same page are accessed.&lt;/p&gt;

&lt;p&gt;Another way to address this situation is to &lt;a href="https://dev.mysql.com/doc/refman/8.0/en/innodb-disk-io.html"&gt;read-ahead&lt;/a&gt; pages that are very likely to be accessed in the future and keep them available in the main memory. This way if the read-ahead pages are referenced, the engine needs to go to the disk to fetch the page, rather it will find the page residing in the main memory and thus saving a bunch of disk reads.&lt;/p&gt;

&lt;h2&gt;
  
  
  Temporal Locality of Reference
&lt;/h2&gt;

&lt;p&gt;The temporal locality of reference suggests that if a page is recently accessed, it is very likely that the same page will be accessed again in the near future.&lt;/p&gt;

&lt;p&gt;Caching exploits this behaviour by putting every single page accessed from the disk into main-memory (cache). Hence the next time a page which is available in the cache is referenced, the engine need not make a disk read to get the page, rather it could reference it from the cache directly, again saving a disk read.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Hk0rHT3s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/80286313-4e57e680-8748-11ea-88c2-dcb67f6ac566.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Hk0rHT3s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/80286313-4e57e680-8748-11ea-88c2-dcb67f6ac566.png" alt="Disk cache-control flow"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since the cache is very costly, it is in magnitude smaller in capacity than the disk. It can only hold some fixed number of pages which means the cache suffers from the problem of getting full very quickly. Once the cache gets full, the engine needs to evict an old page so that the new page, which according to the temporal locality of reference is going to be accessed in the near future, could get a place in the cache.&lt;/p&gt;

&lt;p&gt;The most common strategy that decides the page that will be evicted from the cache is the &lt;a href="https://en.wikipedia.org/wiki/Cache_replacement_policies#Least_recently_used_(LRU)"&gt;Least Recently Used cache eviction strategy&lt;/a&gt;. This strategy uses Temporal Locality of Reference to the core and hence evicts the page which was not accessed the longest, thus maximizing the time the most-recently accessed pages are held in the cache.&lt;/p&gt;

&lt;h1&gt;
  
  
  LRU Cache
&lt;/h1&gt;

&lt;p&gt;The LRU cache holds the items in the order of its last access, allowing us to identify which item is not being used the longest. When the cache is full and a newer item needs to make an entry in the cache, the item which is not accessed the longest is evicted and hence the name Least Recently Used.&lt;/p&gt;

&lt;p&gt;The one end (head) of the list holds the most-recently referenced page while the fag end (tail) of the list holds the least-recently referenced one. A new page, being most-recently accessed, is always added at the head of the list while the eviction happens at the tail. If a page from the cache is referenced again, it is moved to the head of the list as it is now the most-recently referenced.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;LRU cache is often implemented by pairing a &lt;a href="https://en.wikipedia.org/wiki/Doubly_linked_list"&gt;doubly-linked list&lt;/a&gt; with a &lt;a href="https://en.wikipedia.org/wiki/Hash_table"&gt;hash map&lt;/a&gt;. The cache is thus just a linked list of pages and the hashmap maps the &lt;code&gt;page_id&lt;/code&gt; to the node in the linked list, enabling &lt;code&gt;O(1)&lt;/code&gt; lookups.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oDyrb8cl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/80288324-d7751a80-8754-11ea-96ab-6a8e25730bff.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oDyrb8cl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/80288324-d7751a80-8754-11ea-96ab-6a8e25730bff.png" alt="LRU Cache"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  InnoDB's Buffer Pool
&lt;/h2&gt;

&lt;p&gt;MySQL InnoDB's cache is called &lt;a href="https://dev.mysql.com/doc/refman/8.0/en/innodb-buffer-pool.html"&gt;Buffer Pool&lt;/a&gt; which does exactly what has been established earlier. Pseudocode implementation of &lt;code&gt;get_page&lt;/code&gt; function, using which the engine gets the page for further processing, could be summarized as&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nb"&gt;int&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;Page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Check if the page is available in the cache
&lt;/span&gt;    &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# if the page is retrieved from the main memory
&lt;/span&gt;    &lt;span class="c1"&gt;# return the page.
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;

    &lt;span class="c1"&gt;# retrieve the page from the disk
&lt;/span&gt;    &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;disk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# put the page in the cache,
&lt;/span&gt;    &lt;span class="c1"&gt;# if the cache is full, evict a page which is
&lt;/span&gt;    &lt;span class="c1"&gt;# least recently used.
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_full&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;evict_page&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;# put the page in the cache
&lt;/span&gt;    &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put_page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# return the pages
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  A notorious problem with Sequential Scans
&lt;/h2&gt;

&lt;p&gt;Above caching strategy works wonders and helps the engine to be super-performant. &lt;a href="https://www.stix.id.au/wiki/Cache_Hit_Ratio"&gt;Cache hit ratio&lt;/a&gt; is usually more than 80% for mid-sized production-level traffic, which means 80% of the times the pages were served from the main memory (cache) and the engine did not require to make the disk read.&lt;/p&gt;

&lt;p&gt;What would happen if an entire table is scanned? say, while talking a &lt;a href="(https://dev.mysql.com/doc/refman/8.0/en/mysqldump.html)"&gt;DB dump&lt;/a&gt;, or running a &lt;code&gt;SELECT&lt;/code&gt; without &lt;code&gt;WHERE&lt;/code&gt; to perform some statistical computations.&lt;/p&gt;

&lt;p&gt;Going by the MySQL's aforementioned behaviour, the engine iterates on all the pages and since each page which is accessed now is the most recent one, it puts it at the head of the cache while evicting one from the tail.&lt;/p&gt;

&lt;p&gt;If the table is bigger than the cache, this process will wipe out the entire cache and fill it with the pages from just one table. If these pages are not referenced again, this is a total loss and performance of the database takes a hit. The performance will pickup once these pages are evicted from the cache and other pages make an entry.&lt;/p&gt;

&lt;h1&gt;
  
  
  Midpoint Insertion Strategy
&lt;/h1&gt;

&lt;p&gt;MySQL InnoDB Engine ploys an extremely smart solution to solve the notorious problem with Sequential Scans. Instead of keeping its Buffer Pool a strict LRU, it tweaks it a little bit.&lt;/p&gt;

&lt;p&gt;Instead of treating the Buffer Pool as a single doubly-linked list, it treats it as a combination of two smaller sublists - usually 5/8th and 3/8th of the total size. One sublist holds the younger data while the other one holds the older data. The head of the Young sublist holds the most recent pages and the recency decreases as we reach the tail of the Old sublist.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wxqgf18U--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/80299447-138a9880-87b2-11ea-9b0a-888e0ccf4b49.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wxqgf18U--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/80299447-138a9880-87b2-11ea-9b0a-888e0ccf4b49.png" alt="MySQL InnoDB Midpoint Insertion Strategy"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Eviction
&lt;/h2&gt;

&lt;p&gt;The tail of the Old Sublist holds the Least Recently Used page and the eviction thus happens as per the LRU Strategy i.e. at the tail of the Old Sublist.&lt;/p&gt;

&lt;h2&gt;
  
  
  Insertion
&lt;/h2&gt;

&lt;p&gt;This is where this strategy differs from Strict LRU. The insertion, instead of happening at "newest" end of the list i.e. head of Young sublist, happens at the head of Old sublist i.e. in the "middle" of the list. This position of the list where the tail of the Young sublist meets the head of the Old sublist is referred to as the "midpoint", and hence the name of the strategy is Midpoint Insertion Strategy.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;By inserting in the middle, the pages that are only read once, such as during a full table scan, can be aged out of the Buffer Pool sooner than with a strict LRU algorithm.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Moving page from Old to the Young sublist
&lt;/h2&gt;

&lt;p&gt;In this strategy, like in Strict LRU implementation, whenever the page is accessed it moves to the newest end of the list i.e. the head of the Young sublist. During the first access, the pages make an entry in the cache in the "middle" position.&lt;/p&gt;

&lt;p&gt;If the page is referenced the second time it is moved to the head of Young sublist and hence stays in the cache for a longer time. If the page, after being inserted in the middle, is never referenced again (during full scans), it is evicted sooner because the Old sublist is usually shorter than the Young sublist.&lt;/p&gt;

&lt;p&gt;The Young sublist thus remains unaffected by table scans bringing in new blocks that might or might not be accessed afterwards. The engine thus remains performant as more frequently accessed pages continue to remain in the cache (Young sublist).&lt;/p&gt;

&lt;h2&gt;
  
  
  MySQL parameter to tune the midpoint
&lt;/h2&gt;

&lt;p&gt;InnoDB allows us to tune the midpoint of the buffer pool through the parameter &lt;code&gt;innodb_old_blocks_pct&lt;/code&gt;. This parameter controls the percentage of Old sublist to Buffer Pool. The default value is 37 which corresponds to the ratio 3/8.&lt;/p&gt;

&lt;p&gt;In order to get greater insights about Buffer Pool we can invoke the following command as&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ SHOW ENGINE INNODB STATUS

----------------------
BUFFER POOL AND MEMORY
----------------------
Total memory allocated 137363456; in additional pool allocated 0
Dictionary memory allocated 159646
Buffer pool size   8191
Free buffers       7741
Database pages     449
Old database pages 0

...

Pages made young 12, not young 0
43.00 youngs/s, 27.00 non-youngs/s

...

Buffer pool hit rate 997 / 1000, young-making rate 0 / 1000 not 0 / 1000
Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s

...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The command &lt;code&gt;SHOW ENGINE INNODB STATUS&lt;/code&gt; outputs a lot of interesting metrics but the most interesting and critical ones, w.r.t Memory and Buffer Pool, are&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;number of pages that were made young&lt;/li&gt;
&lt;li&gt;rate of eviction without access&lt;/li&gt;
&lt;li&gt;cache hit ratio&lt;/li&gt;
&lt;li&gt;read ahead rate&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;We see how by changing just one aspect of LRU cache, MySQL InnoDB makes itself Scan Resistant. Sequential scanning was a critical issue for the cache but it was addressed in a very elegant way.&lt;/p&gt;

&lt;h1&gt;
  
  
  References
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://gist.github.com/hellerbarde/2843375"&gt;Latency numbers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Locality_of_reference"&gt;Locality of reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://serge.frezefond.com/2009/12/innodb-making-buffer-cache-scan-resistant/"&gt;InnoDB: Making Buffer Cache Scan Resistant&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.mysql.com/doc/refman/8.0/en/innodb-buffer-pool.html"&gt;MySQL Dev - Buffer Pool&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.mysql.com/doc/refman/8.0/en/innodb-performance-midpoint_insertion.html"&gt;MySQL Dev - Making the Buffer Pool Scan Resistant&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.mysql.com/doc/refman/8.0/en/innodb-disk-io.html"&gt;MySQL Dev - InnoDB Disk I/O&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Other articles you might like:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/fsm"&gt;Building Finite State Machines with Python Coroutines&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/bayesian-average"&gt;Solving an age-old problem using Bayesian Average &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/better-programmer"&gt;Eight rituals to be a better programmer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/rule-30"&gt;Pseudorandom numbers using Cellular Automata - Rule 30&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/function-overloading"&gt;Overload Functions in Python&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;This article was originally published on my &lt;a href="https://arpitbhayani.me/blogs/mysql-cache"&gt;blog - What makes MySQL LRU cache scan resistant&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you liked what you read, subscribe to my newsletter and get the post delivered directly to your inbox and give me a shout-out &lt;a href="https://twitter.com/arpit_bhayani"&gt;@arpit_bhayani&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://arpit.substack.com"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WpJKYG2m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/79068776-07e59f00-7ce7-11ea-8eff-3918556a3682.png" alt="Subscribe to Arpit's newsletter"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>database</category>
      <category>algorithms</category>
      <category>mysql</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>Building Finite State Machines with Python Coroutines</title>
      <dc:creator>Arpit Bhayani</dc:creator>
      <pubDate>Sun, 19 Apr 2020 10:15:48 +0000</pubDate>
      <link>https://dev.to/arpit_bhayani/building-finite-state-machines-with-python-coroutines-5gm2</link>
      <guid>https://dev.to/arpit_bhayani/building-finite-state-machines-with-python-coroutines-5gm2</guid>
      <description>&lt;p&gt;Finite State Machine is a mathematical model of computation that models a sequential logic. FSM consists of a finite number of states, transition functions, input alphabets, a start state and end state(s). In the field of computer science, the FSMs are used in designing Compilers, Linguistics Processing, Step workflows, Game Design, Protocols Procedures (like TCP/IP), Event-driven programming, Conversational AI and many more.&lt;/p&gt;

&lt;p&gt;To understand what a finite machine is, we take a look at Traffic Signal. Finite State Machine for a Traffic Signal is designed and rendered below. &lt;code&gt;Green&lt;/code&gt; is the start/initial state, which upon receiving a trigger moves to &lt;code&gt;Yellow&lt;/code&gt;, which, in turn, upon receiving a trigger, transitions to &lt;code&gt;Red&lt;/code&gt;. The &lt;code&gt;Red&lt;/code&gt; then circles back to &lt;code&gt;Green&lt;/code&gt; and the loop continues.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--92t9oZF4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/79678813-d572ff00-821c-11ea-8437-b4a3b7fd1a60.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--92t9oZF4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/79678813-d572ff00-821c-11ea-8437-b4a3b7fd1a60.png" alt="traffic signal fsm"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An FSM must be in exactly one of the finite states at any given point in time and then in response to an input, it receives, the machine transitions to another state. In the example above, the traffic signal is exactly in one of the 3 states - &lt;code&gt;Green&lt;/code&gt;, &lt;code&gt;Yellow&lt;/code&gt; or &lt;code&gt;Red&lt;/code&gt;. The transition rules are defined for each state which defines what sequential logic will be played out upon input.&lt;/p&gt;

&lt;p&gt;Implementing an FSM is crucial to solving some of the most interesting problems in Computer Science and in this article, we dive deep into modeling a Finite State Machine using Python coroutines.&lt;/p&gt;

&lt;h1&gt;
  
  
  Python Coroutines
&lt;/h1&gt;

&lt;p&gt;Before diving into the implementation we take a detour and look at what Generators and Coroutines are, how they keep implementation intuitive and fits into the scheme of things.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generators
&lt;/h2&gt;

&lt;p&gt;Generators are &lt;strong&gt;resumable functions&lt;/strong&gt; that yield values as long as someone, by calling &lt;code&gt;next&lt;/code&gt; function, keeps asking it. If there are no more values to yield, the generator raises a &lt;code&gt;StopIteration&lt;/code&gt; exception.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&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="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
        &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;yield&lt;/code&gt; statement is where the magic happens. Upon reaching the &lt;code&gt;yield&lt;/code&gt; statement, the generator function execution is paused and the yielded value is returned to the caller and the caller continues its execution. The flow returns back to the generator when the caller function asks from the next value. Once the next value is requested by calling &lt;code&gt;next&lt;/code&gt; (explicitly or implicitly), the generator function resumes from where it left off i.e. &lt;code&gt;yield&lt;/code&gt; statement.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;fgen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fgen&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)]&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; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;34&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Using a Fibonacci generator is memory-efficient as now we need not compute a lot of Fibonacci numbers and hold them in memory, in a list, rather the requesting process could ask for as many values as it needs and the generator would keep on yielding values one by one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Coroutines
&lt;/h2&gt;

&lt;p&gt;Coroutines, just like generators, are resumable functions but instead of generating values, they consume values on the fly. The working of it is very similar to the generator and again the &lt;code&gt;yield&lt;/code&gt; statement is where the magic happens. When a coroutine is paused at the &lt;code&gt;yield&lt;/code&gt; statement, we could send the value it using &lt;code&gt;send&lt;/code&gt; function and the value could be used using the assignment operator &lt;code&gt;=&lt;/code&gt; on &lt;code&gt;yield&lt;/code&gt; as shown below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;grep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;substr&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;f"found &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;substr&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In the example above, we wrote a simple &lt;code&gt;grep&lt;/code&gt; utility that checks for a substring in a given stream of text. When the coroutine &lt;code&gt;grep&lt;/code&gt; is paused at the &lt;code&gt;yield&lt;/code&gt; statement, using the &lt;code&gt;send&lt;/code&gt; function, we send the text to it, and it will be referenced by the variable &lt;code&gt;line&lt;/code&gt;. The coroutine then continues its execution to check if &lt;code&gt;substr&lt;/code&gt; is in &lt;code&gt;line&lt;/code&gt; or not. Once the flow reaches the &lt;code&gt;yield&lt;/code&gt; statement again, the coroutine pauses and waits for the caller to &lt;code&gt;send&lt;/code&gt; it a new value.&lt;/p&gt;

&lt;p&gt;Note that, this is not a thread that keeps on running and hogging the CPU. It is just a function whose execution is paused at the &lt;code&gt;yield&lt;/code&gt; statement waiting for the value; the state is persisted and the control is passed back to the caller. When resumed the coroutine starts from the same state where it left off.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Before sending the value to a coroutine we need to "prime" it so that the flow reaches the yield statement and the execution is paused while waiting for the value to be sent.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;grep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"users/created"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# priming the generator
&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"users/get api took 1 ms."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"users/created api took 3 ms."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;found&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;created&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"users/get api took 1 ms."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"users/created api took 4 ms."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;found&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;created&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"users/get api took 1 ms."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In the function invocations above we see how we could keep on sending the text to the coroutine and it continues to spit out if it found the given substring &lt;code&gt;users/created&lt;/code&gt; in the text. This ability of coroutine to pause the execution and accept input on the fly helps us model FSM in a very intuitive way.&lt;/p&gt;

&lt;h1&gt;
  
  
  Building a Finite State Machine
&lt;/h1&gt;

&lt;p&gt;While building FSMs, the most important thing is how we decide to model and implement states and transition functions. States could be modeled as Python Coroutines that run an infinite loop within which they accept the input, decides the transition and updates the current state of the FSM. The transition function could be as simple as a bunch of &lt;code&gt;if&lt;/code&gt; and &lt;code&gt;elif&lt;/code&gt; statements and in a more complex system it could be a decision function.&lt;/p&gt;

&lt;p&gt;To dive into low-level details, we build an FSM for the regular expression &lt;code&gt;ab*c&lt;/code&gt;, which means if the given string matches the regex then the machine should end at the end state, only then we say that the string matches the regex.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GTzDZbgI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/79634655-84fe9180-8189-11ea-9b94-f9ee563394bf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GTzDZbgI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/79634655-84fe9180-8189-11ea-9b94-f9ee563394bf.png" alt="fsm for ab*c"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  State
&lt;/h2&gt;

&lt;p&gt;From the FSM above we model the state &lt;code&gt;q2&lt;/code&gt; as&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_create_q2&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Wait till the input is received.
&lt;/span&gt;        &lt;span class="c1"&gt;# once received store the input in `char`
&lt;/span&gt;        &lt;span class="n"&gt;char&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt;

        &lt;span class="c1"&gt;# depending on what we received as the input
&lt;/span&gt;        &lt;span class="c1"&gt;# change the current state of the fsm
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;'b'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# on receiving `b` the state moves to `q2`
&lt;/span&gt;            &lt;span class="n"&gt;current_state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;q2&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;'c'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# on receiving `c` the state moves to `q3`
&lt;/span&gt;            &lt;span class="n"&gt;current_state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;q3&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# on receiving any other input, break the loop
&lt;/span&gt;            &lt;span class="c1"&gt;# so that next time when someone sends any input to
&lt;/span&gt;            &lt;span class="c1"&gt;# the coroutine it raises StopIteration
&lt;/span&gt;            &lt;span class="k"&gt;break&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The coroutine runs as an infinite loop in which it waits for the input token at the &lt;code&gt;yield&lt;/code&gt; statement. Upon receiving the input, say &lt;code&gt;b&lt;/code&gt; it changes the current state of FSM to &lt;code&gt;q2&lt;/code&gt; and on receiving &lt;code&gt;c&lt;/code&gt; changes the state to &lt;code&gt;q3&lt;/code&gt; and this precisely what we see in the FSM diagram.&lt;/p&gt;

&lt;h2&gt;
  
  
  FSM Class
&lt;/h2&gt;

&lt;p&gt;To keep things encapsulated we will define a class for FSM which holds all the states and maintains the current state of the machine. It will also have a method called &lt;code&gt;send&lt;/code&gt; which reroutes the received input to the current state. The current state upon receiving this input makes a decision and updates the &lt;code&gt;current_state&lt;/code&gt; of the FSM as shown above.&lt;/p&gt;

&lt;p&gt;Depending on the use-case the FSM could also have a function that answers the core problem statement, for example, does the given line matches the regular expression? or is the number divisible by 3?&lt;/p&gt;

&lt;p&gt;The FSM class for the regular expression &lt;code&gt;ab*c&lt;/code&gt; could be modeled as&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FSM&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# initializing states
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_create_start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;q1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_create_q1&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;q2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_create_q2&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;q3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_create_q3&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="c1"&gt;# setting current state of the system
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current_state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;

        &lt;span class="c1"&gt;# stopped flag to denote that iteration is stopped due to bad
&lt;/span&gt;        &lt;span class="c1"&gt;# input against which transition was not defined.
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stopped&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="s"&gt;"""The function sends the curretn input to the current state
        It captures the StopIteration exception and marks the stopped flag.
        """&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current_state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;char&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;StopIteration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stopped&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;does_match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="s"&gt;"""The function at any point in time returns if till the current input
        the string matches the given regular expression.

        It does so by comparing the current state with the end state `q3`.
        It also checks for `stopped` flag which sees that due to bad input the iteration of FSM had to be stopped.
        """&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stopped&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current_state&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;q3&lt;/span&gt;

    &lt;span class="p"&gt;...&lt;/span&gt;

    &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;prime&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_create_q2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# Wait till the input is received.
&lt;/span&gt;            &lt;span class="c1"&gt;# once received store the input in `char`
&lt;/span&gt;            &lt;span class="n"&gt;char&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt;

            &lt;span class="c1"&gt;# depending on what we received as the input
&lt;/span&gt;            &lt;span class="c1"&gt;# change the current state of the fsm
&lt;/span&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;'b'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="c1"&gt;# on receiving `b` the state moves to `q2`
&lt;/span&gt;                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current_state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;q2&lt;/span&gt;
            &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;'c'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="c1"&gt;# on receiving `c` the state moves to `q3`
&lt;/span&gt;                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current_state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;q3&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="c1"&gt;# on receiving any other input, break the loop
&lt;/span&gt;                &lt;span class="c1"&gt;# so that next time when someone sends any input to
&lt;/span&gt;                &lt;span class="c1"&gt;# the coroutine it raises StopIteration
&lt;/span&gt;                &lt;span class="k"&gt;break&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Similar to how we have defined the function &lt;code&gt;_create_q2&lt;/code&gt; we could define functions for the other three states &lt;code&gt;start&lt;/code&gt;, &lt;code&gt;q1&lt;/code&gt; and &lt;code&gt;q3&lt;/code&gt;. You can find the complete FSM modeled at &lt;a href="https://github.com/arpitbbhayani/fsm/blob/master/regex-1.ipynb"&gt;arpitbbhayani/fsm/regex-1&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Driver function
&lt;/h2&gt;

&lt;p&gt;The motive of this problem statement is to define a function called &lt;code&gt;grep_regex&lt;/code&gt; which tests a given &lt;code&gt;text&lt;/code&gt; against the regex &lt;code&gt;ab*c&lt;/code&gt;. The function will internally create an instance of &lt;code&gt;FSM&lt;/code&gt; and will pass the stream of characters to it. Once all the characters are exhausted, we invoke &lt;code&gt;does_match&lt;/code&gt; function on the FSM which suggests if the given &lt;code&gt;text&lt;/code&gt; matches the regex &lt;code&gt;ab*c&lt;/code&gt; or not.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;grep_regex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;evaluator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FSM&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;evaluator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;evaluator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;does_match&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;grep_regex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"abc"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="bp"&gt;True&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;grep_regex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"aba"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="bp"&gt;False&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;The entire execution is purely running sequential - and that's because of Coroutines. All states seem to run in parallel but they that are all executing in one thread concurrently. The coroutine of the current state is executing while all others are suspended on their corresponding &lt;code&gt;yield&lt;/code&gt; statements. When a new input is sent to the coroutine it is unblocked completes its execution, changes the current state of FSM and pauses itself on its &lt;code&gt;yield&lt;/code&gt; statement again.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  More FSMs
&lt;/h1&gt;

&lt;p&gt;We have seen how intuitive it is to build Regular expression FSMs using Python Coroutines, but if our hypothesis is true things should equally intuitive when we are implementing FSMs for other use cases and here we take a look at two examples and see how a state is implemented in each&lt;/p&gt;

&lt;h2&gt;
  
  
  Divisibility by 3
&lt;/h2&gt;

&lt;p&gt;Here we build an FSM that tells if a given stream of digits of a number is divisible by 3 or not. The state machine is as shown below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--f8wsRunP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/79641628-564ae000-81b6-11ea-9c84-147cae3a30a6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--f8wsRunP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/79641628-564ae000-81b6-11ea-9c84-147cae3a30a6.png" alt="div3"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can implement the state &lt;code&gt;q1&lt;/code&gt; as a coroutine as&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_create_q1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;digit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt;  &lt;span class="n"&gt;digit&lt;/span&gt; &lt;span class="ow"&gt;in&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; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current_state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;q1&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt;  &lt;span class="n"&gt;digit&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current_state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;q2&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt;  &lt;span class="n"&gt;digit&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current_state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;q0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We can see the similarity between the coroutine implementation and the transition function for a state. The entire implementation of this FSM can be found at &lt;a href="https://github.com/arpitbbhayani/fsm/blob/master/divisibility-by-3.ipynb"&gt;arpitbbhayani/fsm/divisibility-by-3&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  SQL Query Validator
&lt;/h2&gt;

&lt;p&gt;Here we build an FSM for a SQL Query Validator, which for a given a SQL query tells if it is a valid SQL query or not. The FSM for the validator that covers all the SQL queries will be massive, hence we just deal with the subset of it where we support the following SQL queries&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT * from TABLE_NAME;
SELECT column, [...columns] from TABLE_NAME;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fBxNhd5R--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/79635523-1c1a1800-818f-11ea-8afe-fe8065b55791.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fBxNhd5R--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/79635523-1c1a1800-818f-11ea-8afe-fe8065b55791.png" alt="fsm for sql query validator"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can implement the state &lt;code&gt;explicit_cols&lt;/code&gt; as a coroutine as&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_create_explicit_cols&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;'from'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current_state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_clause&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;','&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current_state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;more_cols&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Again the coroutine through which the state is implemented is very similar to the transition function of the state keeping things intuitive. The entire implementation of this FSM can be found at &lt;a href="https://github.com/arpitbbhayani/fsm/blob/master/sql-query-validator.ipynb"&gt;arpitbbhayani/fsm/sql-query-validator&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Even though this may not be the most efficient way to implement and build FSM but it is the most intuitive way indeed. The edges and state transitions, translate well into &lt;code&gt;if&lt;/code&gt; and &lt;code&gt;elif&lt;/code&gt; statements or the decision functions, while each state is being modeled as an independent coroutine and we still do things in a sequential manner. The entire execution is like a relay race where the baton of execution is being passed from one coroutine to another.&lt;/p&gt;

&lt;h1&gt;
  
  
  References and Readings
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Finite-state_machine"&gt;Finite State Machines - Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://brilliant.org/wiki/finite-state-machines/"&gt;Finite State Machines - Brilliant.org&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://web.cs.ucdavis.edu/~rogaway/classes/120/spring13/eric-applications.pdf"&gt;FSM Applications&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://realpython.com/lessons/what-are-python-coroutines/"&gt;What Are Python Coroutines?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://realpython.com/introduction-to-python-generators/"&gt;How to Use Generators and yield in Python&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Other articles you might like:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/bayesian-average"&gt;Solving an age-old problem using Bayesian Average&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/better-programmer"&gt;Eight rituals to be a better programmer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/rule-30"&gt;Pseudorandom numbers using Cellular Automata - Rule 30&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/function-overloading"&gt;Overload Functions in Python&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arpitbhayani.me/blogs/isolation-forest"&gt;Isolation Forest algorithm for anomaly detection&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;This article was originally published on my &lt;a href="https://arpitbhayani.me/blogs/fsm"&gt;blog - Building Finite State Machines with Python Coroutines&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you liked what you read, subscribe to my newsletter and get the post delivered directly to your inbox and give me a shout-out &lt;a href="https://twitter.com/arpit_bhayani"&gt;@arpit_bhayani&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://arpit.substack.com"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WpJKYG2m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4745789/79068776-07e59f00-7ce7-11ea-8eff-3918556a3682.png" alt="Subscribe to Arpit's newsletter"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>fsm</category>
    </item>
  </channel>
</rss>
