<?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: Manthan Gupta</title>
    <description>The latest articles on DEV Community by Manthan Gupta (@manthanguptaa).</description>
    <link>https://dev.to/manthanguptaa</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%2F293696%2F1f041385-ec6d-4193-a38d-9bee833464cf.jpg</url>
      <title>DEV Community: Manthan Gupta</title>
      <link>https://dev.to/manthanguptaa</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/manthanguptaa"/>
    <language>en</language>
    <item>
      <title>Introducing CricLang 🏏: A programming language for cricket enthusiasts</title>
      <dc:creator>Manthan Gupta</dc:creator>
      <pubDate>Sun, 17 Mar 2024 12:14:43 +0000</pubDate>
      <link>https://dev.to/manthanguptaa/introducing-criclang-a-programming-language-for-cricket-enthusiasts-1pc8</link>
      <guid>https://dev.to/manthanguptaa/introducing-criclang-a-programming-language-for-cricket-enthusiasts-1pc8</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/manthanguptaa/CricLang"&gt;CricLang&lt;/a&gt; is a fun programming language created for cricket enthusiasts. If you look at the initial commit on the repository, it will show it as June 9, 2023, but the idea of building my programming language has been lingering at the back of my head since my college days. Finally, after procrastinating on building CricLang, I started working on it on Feb 17, 2024, and it is now ready for public beta release.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the name CricLang?
&lt;/h2&gt;

&lt;p&gt;CricLang is an amalgamation of 'Cricket' and 'GoLang' as it is built on top of Go. It represents my love for cricket, software engineering, and the idea that code should be as simple and readable as the game. It is an evolving programming language and isn't perfect by any means.&lt;/p&gt;

&lt;h2&gt;
  
  
  Documentation
&lt;/h2&gt;

&lt;p&gt;CricLang is a dynamically typed language written in Go&lt;/p&gt;

&lt;h3&gt;
  
  
  Data Types
&lt;/h3&gt;

&lt;p&gt;CricLang currently supports 4 types of data types &lt;code&gt;int&lt;/code&gt;, &lt;code&gt;string&lt;/code&gt;, &lt;code&gt;boolean&lt;/code&gt;, and &lt;code&gt;array&lt;/code&gt; as of now. Boolean values are denoted by &lt;code&gt;notout&lt;/code&gt; and &lt;code&gt;out&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-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="mi"&gt;1&lt;/span&gt;                   &lt;span class="c1"&gt;# int
&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;                 &lt;span class="c1"&gt;# int
&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello World!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;      &lt;span class="c1"&gt;# string
&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;notout&lt;/span&gt;              &lt;span class="c1"&gt;# boolean true
&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;                 &lt;span class="c1"&gt;# boolean false
&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello World!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# array
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Declaring Variables
&lt;/h3&gt;

&lt;p&gt;Variables are declared using the reserved keyword &lt;code&gt;player&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-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;player&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;                       &lt;span class="c1"&gt;# integer variable
&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;player&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello World!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;          &lt;span class="c1"&gt;# string variable
&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;player&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;notout&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;                  &lt;span class="c1"&gt;# boolean variable
&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;player&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="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello World!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;  &lt;span class="c1"&gt;# array of variables
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Conditionals
&lt;/h3&gt;

&lt;p&gt;CricLang supports &lt;code&gt;if-else&lt;/code&gt; statements. If condition is declared using the &lt;code&gt;appeal&lt;/code&gt; reserved keyword and else is declared using the &lt;code&gt;appealrejected&lt;/code&gt; reserved keyword.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-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="nf"&gt;appeal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;if condition&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;appealrejected&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;else condition&lt;/span&gt;&lt;span class="sh"&gt;"&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="nf"&gt;appeal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;notout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;&lt;span class="sh"&gt;"&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="nf"&gt;appeal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="n"&gt;notout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;if condition&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;appealrejected&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;else condition&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Return Statements
&lt;/h3&gt;

&lt;p&gt;Return statements are declared using the keyword &lt;code&gt;signaldecision&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-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;signaldecision&lt;/span&gt; &lt;span class="mi"&gt;10&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="nf"&gt;appeal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&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="n"&gt;signaldecision&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;if condition&lt;/span&gt;&lt;span class="sh"&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;appealrejected&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;signaldecision&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;else condition&lt;/span&gt;&lt;span class="sh"&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;h3&gt;
  
  
  Functions
&lt;/h3&gt;

&lt;p&gt;Functions can be declared using the reserved keyword &lt;code&gt;field&lt;/code&gt;. Functions are also binded to variables in CricLang.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-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;player&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;5&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;player&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;25&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;player&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;field&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;y&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt; &lt;span class="nf"&gt;appeal&lt;/span&gt;&lt;span class="p"&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;x&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt; &lt;span class="n"&gt;signaldecision&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;yes&lt;/span&gt;&lt;span class="sh"&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;appealrejected&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;signaldecision&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;no&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;};&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="nf"&gt;z&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;y&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;            &lt;span class="c1"&gt;# output: yes
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Operators
&lt;/h3&gt;

&lt;p&gt;CricLang supports arithmetic operators (&lt;code&gt;+&lt;/code&gt;, &lt;code&gt;-&lt;/code&gt;, &lt;code&gt;*&lt;/code&gt;, &lt;code&gt;/&lt;/code&gt;), logical operator (&lt;code&gt;!&lt;/code&gt;), and comparison operators (&lt;code&gt;==&lt;/code&gt;, &lt;code&gt;&amp;lt;&lt;/code&gt;, &lt;code&gt;&amp;gt;&lt;/code&gt;, &lt;code&gt;!=&lt;/code&gt;) out of the box.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-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="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;                       &lt;span class="c1"&gt;# output: 2
&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;World!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;    &lt;span class="c1"&gt;# output: "Hello World!"
&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;                       &lt;span class="c1"&gt;# output: 0
&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;                      &lt;span class="c1"&gt;# output: 25
&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;                       &lt;span class="c1"&gt;# output : 1
&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;notout&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;               &lt;span class="c1"&gt;# output: false
&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;                        &lt;span class="c1"&gt;# output: true
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Built-in Functions
&lt;/h3&gt;

&lt;p&gt;CricLang is incomplete without its built-in functions which are meme references. Only the OG cricket fans can spot the references to the error messages. Here is a list of all the built-in functions&lt;/p&gt;

&lt;h3&gt;
  
  
  Thala
&lt;/h3&gt;

&lt;p&gt;Thala is inspired by the meme "Thala for a reason". It takes a string or an array as input and returns the length of the string or array but with a twist.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-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="nf"&gt;thala&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;                             &lt;span class="c1"&gt;# 0 params
&lt;/span&gt;&lt;span class="n"&gt;MISFIELD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;girlfriend&lt;/span&gt; &lt;span class="n"&gt;se&lt;/span&gt; &lt;span class="n"&gt;raat&lt;/span&gt; &lt;span class="n"&gt;mei&lt;/span&gt; &lt;span class="n"&gt;baat&lt;/span&gt; &lt;span class="n"&gt;kar&lt;/span&gt; &lt;span class="n"&gt;lena&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pehle&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="n"&gt;ki&lt;/span&gt; &lt;span class="n"&gt;jagah&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="n"&gt;argument&lt;/span&gt; &lt;span class="n"&gt;daal&lt;/span&gt; &lt;span class="n"&gt;de&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;thala&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;# wrong type of param
&lt;/span&gt;&lt;span class="n"&gt;MISFIELD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;girlfriend&lt;/span&gt; &lt;span class="n"&gt;se&lt;/span&gt; &lt;span class="n"&gt;raat&lt;/span&gt; &lt;span class="n"&gt;mei&lt;/span&gt; &lt;span class="n"&gt;baat&lt;/span&gt; &lt;span class="n"&gt;kar&lt;/span&gt; &lt;span class="n"&gt;lena&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pehle&lt;/span&gt; &lt;span class="n"&gt;sahi&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="n"&gt;ka&lt;/span&gt; &lt;span class="n"&gt;argument&lt;/span&gt; &lt;span class="n"&gt;toh&lt;/span&gt; &lt;span class="n"&gt;daal&lt;/span&gt; &lt;span class="n"&gt;de&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;thala&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello World&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                &lt;span class="c1"&gt;# string as a parameter
&lt;/span&gt;&lt;span class="n"&gt;Captain&lt;/span&gt; &lt;span class="n"&gt;Cool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;thala&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Is this sixteen?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;            &lt;span class="c1"&gt;# string a parameter
&lt;/span&gt;&lt;span class="n"&gt;Thala&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Gambhir
&lt;/h3&gt;

&lt;p&gt;Gambhir is inspired by the famous meme where he says some 3rd option when given two options. It takes two parameters and returns something random.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-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="nf"&gt;gambhir&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;                   &lt;span class="c1"&gt;# no arguments passed
&lt;/span&gt;&lt;span class="n"&gt;MISFIELD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Gautam&lt;/span&gt; &lt;span class="n"&gt;Gambhir&lt;/span&gt; &lt;span class="n"&gt;Stares&lt;/span&gt; &lt;span class="n"&gt;Angrily&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;got&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;want&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="n"&gt;arguments&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;gambhir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;virat&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sachin&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# 2 arguments passed
&lt;/span&gt;&lt;span class="n"&gt;Interviewer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;virat&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;sachin&lt;/span&gt;
&lt;span class="n"&gt;Gautam&lt;/span&gt; &lt;span class="n"&gt;Gambhir&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;baingan&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Kohli
&lt;/h3&gt;

&lt;p&gt;Kohli is inspired by one of his famous stump mic recordings. It takes [0, n] arguments and returns a fatal error with an error message.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-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="nf"&gt;kohli&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;                     &lt;span class="c1"&gt;# no arguments passed
&lt;/span&gt;&lt;span class="n"&gt;shaam&lt;/span&gt; &lt;span class="n"&gt;tak&lt;/span&gt; &lt;span class="n"&gt;khelenge&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;inki&lt;/span&gt; &lt;span class="n"&gt;G&lt;/span&gt; &lt;span class="n"&gt;phatt&lt;/span&gt; &lt;span class="n"&gt;jaayegi&lt;/span&gt; &lt;span class="n"&gt;lekin&lt;/span&gt; &lt;span class="n"&gt;abhi&lt;/span&gt; &lt;span class="n"&gt;tera&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt; &lt;span class="n"&gt;phatt&lt;/span&gt; &lt;span class="n"&gt;gaya&lt;/span&gt;
&lt;span class="nb"&gt;exit&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;kohli&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;wrong data type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;     &lt;span class="c1"&gt;# with an error message
&lt;/span&gt;&lt;span class="n"&gt;shaam&lt;/span&gt; &lt;span class="n"&gt;tak&lt;/span&gt; &lt;span class="n"&gt;khelenge&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;inki&lt;/span&gt; &lt;span class="n"&gt;G&lt;/span&gt; &lt;span class="n"&gt;phatt&lt;/span&gt; &lt;span class="n"&gt;jaayegi&lt;/span&gt; &lt;span class="n"&gt;lekin&lt;/span&gt; &lt;span class="n"&gt;abhi&lt;/span&gt; &lt;span class="n"&gt;tera&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt; &lt;span class="n"&gt;phatt&lt;/span&gt; &lt;span class="n"&gt;gaya&lt;/span&gt; &lt;span class="n"&gt;wrong&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;
&lt;span class="nb"&gt;exit&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Rohit
&lt;/h3&gt;

&lt;p&gt;Rohit is inspired by one of his after-match interviews in 2019. It takes one string argument and returns the output.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-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="nf"&gt;rohit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;             &lt;span class="c1"&gt;# no arguments passed
&lt;/span&gt;&lt;span class="n"&gt;MISFIELD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;mera&lt;/span&gt; &lt;span class="n"&gt;gale&lt;/span&gt; &lt;span class="n"&gt;ka&lt;/span&gt; &lt;span class="n"&gt;vaat&lt;/span&gt; &lt;span class="n"&gt;lag&lt;/span&gt; &lt;span class="n"&gt;gaya&lt;/span&gt; &lt;span class="n"&gt;chilla&lt;/span&gt; &lt;span class="n"&gt;chilla&lt;/span&gt; &lt;span class="n"&gt;ke&lt;/span&gt; &lt;span class="n"&gt;ki&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="n"&gt;argument&lt;/span&gt; &lt;span class="n"&gt;chahiye&lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt; &lt;span class="n"&gt;tunne&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="n"&gt;de&lt;/span&gt; &lt;span class="n"&gt;diye&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;rohit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;           &lt;span class="c1"&gt;# argument with wrong data type
&lt;/span&gt;&lt;span class="n"&gt;MISFIELD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;mera&lt;/span&gt; &lt;span class="n"&gt;gale&lt;/span&gt; &lt;span class="n"&gt;ka&lt;/span&gt; &lt;span class="n"&gt;vaat&lt;/span&gt; &lt;span class="n"&gt;lag&lt;/span&gt; &lt;span class="n"&gt;gaya&lt;/span&gt; &lt;span class="n"&gt;chilla&lt;/span&gt; &lt;span class="n"&gt;chilla&lt;/span&gt; &lt;span class="n"&gt;ke&lt;/span&gt; &lt;span class="n"&gt;ki&lt;/span&gt; &lt;span class="n"&gt;sahi&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="n"&gt;ka&lt;/span&gt; &lt;span class="n"&gt;argument&lt;/span&gt; &lt;span class="n"&gt;daal&lt;/span&gt; &lt;span class="n"&gt;de&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;rohit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Manthan&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="c1"&gt;# 1 string argument
&lt;/span&gt;&lt;span class="n"&gt;Reporter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Manthan&lt;/span&gt; &lt;span class="n"&gt;ke&lt;/span&gt; &lt;span class="n"&gt;birthday&lt;/span&gt; &lt;span class="n"&gt;ke&lt;/span&gt; &lt;span class="n"&gt;baare&lt;/span&gt; &lt;span class="n"&gt;mei&lt;/span&gt; &lt;span class="n"&gt;kuch&lt;/span&gt; &lt;span class="n"&gt;boliye&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="n"&gt;Rohit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Abhi&lt;/span&gt; &lt;span class="n"&gt;birthday&lt;/span&gt; &lt;span class="n"&gt;mei&lt;/span&gt; &lt;span class="n"&gt;kya&lt;/span&gt; &lt;span class="n"&gt;bola&lt;/span&gt; &lt;span class="n"&gt;jata&lt;/span&gt; &lt;span class="n"&gt;hai&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt; &lt;span class="n"&gt;Happy&lt;/span&gt; &lt;span class="n"&gt;Birthday&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt; &lt;span class="n"&gt;Yahi&lt;/span&gt; &lt;span class="n"&gt;bola&lt;/span&gt; &lt;span class="n"&gt;jata&lt;/span&gt; &lt;span class="n"&gt;hai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I will keep adding more fun built-in functions to CricLang and improve it overall. If you think you have some great ideas for adding a built-in function or improving CricLang, don't shy away from sending a PR.&lt;/p&gt;

&lt;h2&gt;
  
  
  Parting Words
&lt;/h2&gt;

&lt;p&gt;CricLang is my attempt at building a programming language, and it's by no means a complete language. It has its share of flaws, and they will be improved upon over the period of time. If you love CricLang, then don't forget to share it on &lt;a href="https://twitter.com/manthanguptaa"&gt;Twitter&lt;/a&gt;, &lt;a href="https://www.linkedin.com/in/manthanguptaa/"&gt;LinkedIn&lt;/a&gt;, and &lt;a href="https://peerlist.io/manthangupta"&gt;Peerlist&lt;/a&gt;. Drop a star to CricLang on &lt;a href="https://github.com/manthanguptaa/CricLang"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Note for Folks who are Hiring
&lt;/h2&gt;

&lt;p&gt;If you are hiring for software engineers, then I am actively looking out. I am looking for companies that are working either in the field of distributed systems, databases, cloud computing, audio/ video infrastructure, OTT platforms, fintech, or AI. If your team is pushing boundaries and working on something truly unique, I'd love to hear from you too. Reach out to me on &lt;a href="mailto:guptaamanthan01@gmail.com"&gt;guptaamanthan01@gmail.com&lt;/a&gt; or &lt;a href="https://twitter.com/manthanguptaa"&gt;Twitter&lt;/a&gt; or &lt;a href="https://www.linkedin.com/in/manthanguptaa/"&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                        Made with love for 🏏 in 🇮🇳
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>programming</category>
      <category>go</category>
      <category>opensource</category>
      <category>news</category>
    </item>
    <item>
      <title>Replication in Distributed Systems - Part 3</title>
      <dc:creator>Manthan Gupta</dc:creator>
      <pubDate>Tue, 13 Feb 2024 15:37:08 +0000</pubDate>
      <link>https://dev.to/manthanguptaa/replication-in-distributed-systems-part-3-3d4m</link>
      <guid>https://dev.to/manthanguptaa/replication-in-distributed-systems-part-3-3d4m</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fshfuxhyk23dqn7xsnsjv.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fshfuxhyk23dqn7xsnsjv.gif" alt="spider-man" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Welcome to the third and final part of my series on replication in distributed systems. If you have missed the first two parts of the series, I would advise you to read them first, as this comes off as a storyline. Click &lt;a href="https://manthanguptaa.in/posts/replication_in_distributed_systems_part_1/"&gt;here&lt;/a&gt; and &lt;a href="https://manthanguptaa.in/posts/replication_in_distributed_systems_part_2/"&gt;here&lt;/a&gt; for the previous blogs. In this blog, we will discuss... well, let's dive right in without formalities!&lt;/p&gt;

&lt;h2&gt;
  
  
  Leaderless Replication
&lt;/h2&gt;

&lt;p&gt;In a leaderless implementation, the client directly sends the writes to several replicas and waits for the majority of them to acknowledge, compared to a setup with one or more leaders where a leader exists to coordinate the writes.&lt;/p&gt;

&lt;h3&gt;
  
  
  What happens when a node goes down?
&lt;/h3&gt;

&lt;p&gt;In a leader-based configuration with one leader and two replicas, we need to perform &lt;em&gt;failover&lt;/em&gt; if we want to continue to process writes. But in a leaderless configuration, failover doesn't exist. So when the unavailable node comes back online, it has missing writes, meaning it has &lt;em&gt;stale&lt;/em&gt; data.&lt;/p&gt;

&lt;p&gt;This problem can easily be solved by sending the read request from the client to not just one replica but to several nodes in parallel. The client may receive different versions of the data that may be up-to-date or stale. Version numbers are used to determine which value is newer.&lt;/p&gt;

&lt;p&gt;When the unavailable node comes back online, it has stale data. There are two mechanisms to catch up on the writes&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Read Repair&lt;/strong&gt; - When a client makes a read request from several nodes in parallel, it can detect the node/s having stale data. The client sees the node which has stale data and writes back the newer value. This approach works well for values frequently read.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Anti-Entropy&lt;/strong&gt; - A background process runs constantly to look for differences in the data between the replicas. This approach doesn't copy writes in the same order they are written to the up-to-date replica&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Quorums Consistency
&lt;/h2&gt;

&lt;p&gt;Quorums aren't necessarily the majority -- the only thing that matters is that the sets of the nodes used by the read and write operations overlap in at least one node. If there are &lt;em&gt;n&lt;/em&gt; replicas, every write must be confirmed by &lt;em&gt;w&lt;/em&gt; nodes to be considered successful, and we must query at least &lt;em&gt;r&lt;/em&gt; nodes for each read. As long as &lt;strong&gt;w + r &amp;gt; n&lt;/strong&gt;, we expect to get up-to-date values.&lt;/p&gt;

&lt;p&gt;Reads and writes that obey these r and w values are called &lt;em&gt;quorum reads and writes&lt;/em&gt;. The quorum condition &lt;strong&gt;w + r &amp;gt; n&lt;/strong&gt; allows the system to tolerate unavailable nodes&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;if w &amp;lt; n, we can still process writes if a node is unavailable&lt;/li&gt;
&lt;li&gt;if r &amp;lt; n, we can still process reads if a node is unavailable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But even with quorum consistency, there are edge cases where stale values returned&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If a &lt;em&gt;sloppy quorum&lt;/em&gt; is used, the w writes can end up on different nodes than the r reads, so there is no longer a guaranteed overlap between the r and w nodes.&lt;/li&gt;
&lt;li&gt;If two writes occur concurrently, it's not clear which one happened first. The only safe solution is to merge the concurrent writes. If a winner is picked based on the timestamp (LWW - last write wins), writes can be lost due to clock skew.&lt;/li&gt;
&lt;li&gt;If a write happens concurrently with a read, the write may be reflected on only some of the replicas. It's undetermined whether the reads return the old or new value.&lt;/li&gt;
&lt;li&gt;If the write succeeds on fewer than w nodes and fails on the remaining ones, it is not rolled back on the replicas where it succeeded. It means that if a write is reported as failed, subsequent reads may or may not return the value from that write.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Sloppy Quorums &amp;amp; Hinted Handoff
&lt;/h3&gt;

&lt;p&gt;In large clusters with significantly large n nodes, the client can likely connect to some database nodes during the network interruption, just not the nodes that needed to assemble a quorum for a particular write or read. Is it better to return errors to all requests when we can't reach a quorum, or should we accept the writes anyway and write them to some nodes that are reachable, but aren't among the n nodes on which the value lives?&lt;/p&gt;

&lt;p&gt;This is called &lt;em&gt;sloppy quorums&lt;/em&gt;. Writes and reads still require w and r successful responses, but those may include nodes that aren't among the designated n "home" nodes for a value. Once the network interruption is fixed, any writes that one node temporarily accepted on behalf of another node are sent to the appropriate "home" nodes. It is called &lt;em&gt;hinted handoff&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Sloppy quorums are particularly useful for increasing write availability. As long as any w nodes are available, the database can accept the writes. However, this means that even when w + r &amp;gt; n, you cannot be sure to read the latest value for a key because the latest value may have been temporarily written to some nodes outside of n.&lt;/p&gt;

&lt;h2&gt;
  
  
  Last Write Wins (LWW)
&lt;/h2&gt;

&lt;p&gt;Leaderless replication is designed to tolerate conflicting concurrent writes. One approach to achieving eventual convergence is to declare that each replica needs only to store the most "recent" value and allow "older" values to be overwritten. We can attach a timestamp to each write, pick the biggest timestamp as the most "recent" value, and discard any writes with an earlier timestamp. This conflict resolution algorithm is called &lt;em&gt;last write wins&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;LWW achieves the goal of eventual convergence but at the cost of durability. If there are several concurrent writes to the same key, even if they were all reported to be successful by the quorum to the client, only one of the writes will be able to survive, and the others will be silently discarded. It may cause LWW to drop writes that aren't concurrent. Caching is one use case where lost writes are acceptable, and LWW is a good choice. But if losing data isn't acceptable, then LWW is a poor choice for conflict resolution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Defining Concurrency &amp;amp; "Happens-Before" Relationship
&lt;/h2&gt;

&lt;p&gt;An operation A happens before another operation B if B knows about A, B depends on A, or B builds upon A. The key to defining concurrency is to know whether one operation happens before another operation. In concurrency, the timestamp doesn't matter. We call two operations concurrent if they are unaware of each other, regardless of the physical time at which they occurred.&lt;/p&gt;

&lt;h3&gt;
  
  
  Capturing the Happens-Before Relationship
&lt;/h3&gt;

&lt;p&gt;The server can determine whether two operations are concurrent by looking at the version numbers. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The server maintains the version number for every key and increments the version number every time that key is written. The server stores the new version along with the value written. &lt;/li&gt;
&lt;li&gt;When a client reads a key, the server returns all the values that haven't been overwritten with the latest version number. A client must read the key before writing. &lt;/li&gt;
&lt;li&gt;When a client writes a key, it must include the version number from the prior read and must merge all the values it received in the prior read.&lt;/li&gt;
&lt;li&gt;When the server receives a write with a particular version number, it can overwrite all values with that version number or below, but it must keep all values with a higher version number.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Version Vectors
&lt;/h2&gt;

&lt;p&gt;Using a single version number to capture dependencies between operations isn't sufficient when multiple replicas are accepting writes concurrently. Instead, we need to use a version number per replica per key. Each replica increments its own version number when processing a write and keeps track of the version numbers it has seen from each of the other replicas. This information indicates which values to overwrite and which values to keep as siblings (concurrent values are called siblings). The collection of version numbers from all replicas is called &lt;em&gt;version vector&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;Version vectors are sent from the database replicas to clients when values are read and need to be sent back to the database when a value is subsequently written. It helps the database to distinguish between overwrites and concurrent writes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Parting Words
&lt;/h2&gt;

&lt;p&gt;The third part and final part of the blog series introduced quorum consistency for leaderless replication, the LWW concurrency model, and version vectors. This rounds up my blog series on replication in distributed systems.&lt;/p&gt;

&lt;p&gt;If you liked the blog, don't forget to share it and follow me on &lt;a href="https://twitter.com/manthanguptaa"&gt;Twitter&lt;/a&gt;, &lt;a href="https://www.linkedin.com/in/manthangupta109/"&gt;LinkedIn&lt;/a&gt;, &lt;a href="https://peerlist.io/manthangupta"&gt;Peerlist&lt;/a&gt;, and other social platforms, and tag me. You may also write to me at &lt;a href="mailto:guptaamanthan01@gmail.com"&gt;guptaamanthan01@gmail.com&lt;/a&gt; to share your thoughts about the blog.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Designing Data-Intensive Applications: The Big Ideas Behind Reliable, Scalable, and Maintainable Systems by Martin Kleppmann&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>distributedsystems</category>
      <category>systemdesign</category>
      <category>database</category>
      <category>programming</category>
    </item>
    <item>
      <title>Replication in Distributed Systems - Part 2</title>
      <dc:creator>Manthan Gupta</dc:creator>
      <pubDate>Thu, 01 Feb 2024 13:36:17 +0000</pubDate>
      <link>https://dev.to/manthanguptaa/replication-in-distributed-systems-part-2-3e3n</link>
      <guid>https://dev.to/manthanguptaa/replication-in-distributed-systems-part-2-3e3n</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fprz3s4psia5znhjtxvf8.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fprz3s4psia5znhjtxvf8.gif" alt="spider-man" width="498" height="354"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the &lt;a href="https://manthanguptaa.in/posts/replication_in_distributed_systems_part_1/"&gt;first part&lt;/a&gt; of the series, we laid the foundation of replication in distributed systems. We will take this forward in the 2nd part, where we introduce the different consistency guarantees, multi-leader configuration and its comparison with single-leader configuration, conflict resolution, and more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reading your own writes
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqk0d4pkaon0rbwukeg3e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqk0d4pkaon0rbwukeg3e.png" alt="read-your-writes" width="800" height="339"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Many applications allow the user to submit some data and then view what they have submitted, for example, comment in a discussion, buy a stock, etc. The submitted data is sent to the leader and read by the follower, but if we have asynchronous replication, it is a problem. The new data may have not reached the replica. It seems like the data is lost.&lt;/p&gt;

&lt;p&gt;In this situation, we need &lt;em&gt;read-after-write consistency&lt;/em&gt;, also known as &lt;em&gt;read-your-writes consistency&lt;/em&gt;. It guarantees that if the user reloads the page, they will always see the updates that they have submitted. It doesn't hold for other user's updates, and it will take some time to reflect them.&lt;/p&gt;

&lt;p&gt;But how do we implement it? The initial thought process should be to read from the leader the data that the user may have modified. For example, user info can only be edited by the user itself, so a simple rule is that the user profile is read from the leader and any other user's profile from a follower. But if most things are editable by the user, then the benefit of read scaling will be negated. In this case, track the time of the last update and serve the reads from the leader after a minute of the last update. &lt;/p&gt;

&lt;p&gt;Another complication arises if the user is using multiple devices to access the service. Let's say the user comments under an Instagram photo and checks the comment from another device. In this case, we need &lt;em&gt;cross-device read-after-write consistency&lt;/em&gt;. Approaches that require remembering the timestamp of the last update need to be centralized. Another issue is that the request might not be routed to the same data center for multiple devices, so there might be read inconsistencies. If your approach requires reading from the leader, we may first need to route requests from all of a user's devices to the same data center.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monotonic Reads
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fciy9y06mheqbgr0f205l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fciy9y06mheqbgr0f205l.png" alt="monotonic-reads" width="800" height="438"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If the user makes multiple reads from different replicas as the user refreshes the web page, each request is served from a random server. The user sees time moving backward because the data hasn't persisted on all the replicas.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Monotonic reads&lt;/em&gt; is a guarantee that this kind of anomaly doesn't happen. It's a lesser consistency than strong consistency but a stronger guarantee than eventual consistency. One way of achieving this is by serving all the reads for a user from the same replica chosen by the hash of the userID.&lt;/p&gt;

&lt;h2&gt;
  
  
  Consistent Prefix Reads
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnk4kho9ln72n9ena7b4b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnk4kho9ln72n9ena7b4b.png" alt="consistent-prefix-reads" width="800" height="574"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's suppose you are in a WhatsApp group of 3 people, and all 3 of you are exchanging messages. Now you see the sequence of messages not making any sense. Your friend is replying to messages that haven't arrived, and it feels like he can see the future. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Consistent prefix reads&lt;/em&gt; guarantees that if a sequence of writes happens in a particular order, anyone reading those writes will see them appear in the same order. One solution to this problem is to make sure that any writes that are causally related to each other are stored in the same partition.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multi-Leader Replication
&lt;/h2&gt;

&lt;p&gt;Leader based replication has one major downside, it has only one leader. If we aren't able to connect to the leader for any reason, we can't write to the database. The obvious answer to this problem is to have more than one node that accepts writes. This is called &lt;em&gt;multi-leader&lt;/em&gt; configuration, also known as &lt;em&gt;master-master&lt;/em&gt; or &lt;em&gt;active/active replication&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Single-Leader v/s Multi-Leader Configuration in Multi-Data Center Deployment
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Performance
&lt;/h4&gt;

&lt;p&gt;In a single-leader configuration, all writes go to the data center with the leader, which adds significant latency to writes, compared to a multi-leader configuration where every write is processed in the local data center and is replicated asynchronously to the other data center. The inter-data center network delay is hidden from the user, which means the perceived performance may be better.&lt;/p&gt;

&lt;h4&gt;
  
  
  Tolerance of Data Center Outages
&lt;/h4&gt;

&lt;p&gt;In a single-leader configuration, if the data center with the leader fails, failover can promote a follower to the leader in another data center. In a multi-leader configuration, it continues to operate independently of the others, and replication catches up when the failed data center comes back online.&lt;/p&gt;

&lt;h4&gt;
  
  
  Tolerance of Network Problems
&lt;/h4&gt;

&lt;p&gt;A single-leader configuration is very sensitive to problems in this inter-data center link because writes are made asynchronously over this link. A multi-leader configuration with asynchronous configuration can tolerate network problems better as it doesn't prevent it from processing writes.&lt;/p&gt;

&lt;p&gt;A big downside of multi-leader configuration is that the same data can be modified in 2 different places, causing &lt;em&gt;write conflicts&lt;/em&gt;. Auto-incrementing keys, triggers, and integrity constraints can be problematic.&lt;/p&gt;

&lt;h3&gt;
  
  
  Handling Write-Conflicts
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Synchronous v/s Asynchronous Conflict Detection
&lt;/h4&gt;

&lt;p&gt;In a single-leader database, the 2nd writer is either blocked or queued, waiting for the first write to complete or aborted, forcing the user to retry the write. In a multi-leader setup, both the writes are accepted, and the conflict is only detected asynchronously at some later point in time. We could've made the conflict detection synchronous in a multi-leader setup i.e. wait for the first write to be replicated to all the replicas before telling the user the write was successful. But this would make us lose on the benefit of multi-leader replication to allow each replica to accept writes independently. Use single-leader replication if you want synchronous conflict detection.&lt;/p&gt;

&lt;h4&gt;
  
  
  Converging Towards a Consistent State
&lt;/h4&gt;

&lt;p&gt;A single-leader database applies the writes in sequential order, meaning that if there are multiple updates to the same field, the last write determines the final value of the field. In multi-leader configuration, there is no defined ordering of writes, so it's not clear what the final value of the field will be. &lt;/p&gt;

&lt;p&gt;Various ways of achieving &lt;em&gt;convergent conflict resolution&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Give each write a unique ID, pick the write with the highest ID as the winner, and throw all the other writes. If a timestamp is used, the technique is called &lt;em&gt;last write wins (LWW)&lt;/em&gt;. But this is prone to data loss.&lt;/li&gt;
&lt;li&gt;Give each replica a unique ID, and let the writes that originated at a higher-numbered replica always take precedence over writes that originated at a lower-numbered replica. But this is also prone to data loss.&lt;/li&gt;
&lt;li&gt;Record the conflict in an explicit data structure that preserves all information, and write application code that resolves the conflict.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Custom Conflict Resolution Logic
&lt;/h4&gt;

&lt;p&gt;Most multi-leader replication tools let us write conflict resolution logic using application code that may execute on read or on write.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;on write&lt;/em&gt; - As soon as the system detects a conflict in the log of replicated changes, it calls the conflict handler.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;on read&lt;/em&gt; - When a conflict is detected, all the conflicting writes are stored. The next time data is read, multiple versions of the data are sent back to the application. The application may prompt the user to manually resolve the conflict.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Conflict resolution usually applies on a row or document level and not to a complete transaction.&lt;/p&gt;

&lt;h4&gt;
  
  
  Automatic Conflict Resolution
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Conflict-free replicated datatypes (CRDTs)&lt;/em&gt; are a family of data structures for sets, maps, ordered lists, counters, etc that can be concurrently edited by multiple users and which automatically sensibly resolve conflicts. It uses 2-way merge function&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Mergeable persistent data structure&lt;/em&gt; tracks history explicitly, similarly to the git version control, and uses a 3-way merge function&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Operational transformation&lt;/em&gt; is the conflict resolution algorithm behind collaborative editing applications such as Google Docs. It is designed particularly for concurrent editing of an ordered list of items.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Parting Words
&lt;/h2&gt;

&lt;p&gt;The second part of the blog series introduced the different consistency guarantees other than strong consistency and eventual consistency. It also gave an in-depth introduction to multi-leader configuration, where we compared it to single-leader configuration.&lt;/p&gt;

&lt;p&gt;If you liked the blog, don't forget to share it and follow me on &lt;a href="https://twitter.com/manthanguptaa"&gt;Twitter&lt;/a&gt;, &lt;a href="https://www.linkedin.com/in/manthangupta109/"&gt;LinkedIn&lt;/a&gt;, &lt;a href="https://peerlist.io/manthangupta"&gt;Peerlist&lt;/a&gt;, and other social platforms, and tag me. You may also write to me at &lt;a href="mailto:guptaamanthan01@gmail.com"&gt;guptaamanthan01@gmail.com&lt;/a&gt; to share your thoughts about the blog.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Designing Data-Intensive Applications: The Big Ideas Behind Reliable, Scalable, and Maintainable Systems by Martin Kleppmann&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>distributedsystems</category>
      <category>database</category>
      <category>systemdesign</category>
      <category>programming</category>
    </item>
    <item>
      <title>Replication in Distributed Systems - Part 1</title>
      <dc:creator>Manthan Gupta</dc:creator>
      <pubDate>Mon, 29 Jan 2024 16:27:47 +0000</pubDate>
      <link>https://dev.to/manthanguptaa/replication-in-distributed-systems-part-1-5a13</link>
      <guid>https://dev.to/manthanguptaa/replication-in-distributed-systems-part-1-5a13</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ue4jd1q79bnrnmfm62f.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ue4jd1q79bnrnmfm62f.gif" alt="Spider-man gif" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Welcome, fellow nerds, to the 1st part of a blog series on replication. We will be discussing why we even need to distribute a database across multiple machines, what are leaders and followers, how to handle the failure of leaders and followers, etc. It will set it up nicely for our future blog in this series.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why distribute a database across multiple machines?
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt; - If your data volume, read load, or write load grows larger than what a single machine can handle, you can spread the load across multiple machines&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High availability&lt;/strong&gt; - If your application needs to continue to serve even if one or more machines goes down, you can use multiple machines to give you redundancy/ fault tolerance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Latency&lt;/strong&gt; - If you have users over the globe, you will want to have servers at various locations worldwide so that each user is served from a data center that is geographically closer to them.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There are 2 common ways to distribute data across multiple machines (or nodes)&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Replication&lt;/strong&gt; - Keeping a copy of the same data on several different nodes, potentially in different locations. Replication provides redundancy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Partition&lt;/strong&gt; - Splitting the database into smaller subsets called &lt;em&gt;partitions&lt;/em&gt; so that different partitions can be assigned to different nodes (also known as &lt;em&gt;sharding&lt;/em&gt;)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2omuu3g60kwdf3al6lk6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2omuu3g60kwdf3al6lk6.png" alt="Replication &amp;amp; Partition" width="800" height="471"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Leaders &amp;amp; Followers
&lt;/h2&gt;

&lt;p&gt;Every node that has a copy of the database is called a &lt;em&gt;replica&lt;/em&gt;. Every write needs to be processed by every replica; otherwise, the replicas would no longer have the same data. One of the replicas is designated as the &lt;em&gt;leader&lt;/em&gt;. When a client wants to write to the database, they must send their request to the leader that first writes the new data to its local storage. &lt;/p&gt;

&lt;p&gt;The replicas other than the leader are known as &lt;em&gt;followers&lt;/em&gt;. Whenever the leader writes new data to its local storage, it also sends the data change to all of its followers as part of the replication log or change stream in the same order they were processed by the leader. All the followers are read-only, while only the leader accepts the writes. So, when the client wants to read from the database, the followers or the leader can serve the read request.&lt;/p&gt;

&lt;h2&gt;
  
  
  Async vs Sync Replication
&lt;/h2&gt;

&lt;p&gt;In synchronous replication, the leader waits until the follower confirms that it received the write before reporting the success to the user and before making the write visible to other clients. In asynchronous replication, the leader sends the message and doesn't wait for the acknowledgment from the follower.&lt;/p&gt;

&lt;p&gt;The advantage of synchronous replication is that the follower is guaranteed to have an up-to-date copy of the data that is consistent with the leader. If the leader suddenly fails, we can be sure the follower has the data available. The disadvantage is that if the follower doesn't respond, for some reason, it has crashed, network fault, etc. The write cannot be processed. The leader will have to block all the writes and wait for the acknowledgment from the follower whenever it is available again.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fya0qiuwm8wir559q0los.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fya0qiuwm8wir559q0los.png" alt="Sync v/s Async Replication" width="800" height="348"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is definitely impractical to have all the followers as synchronous. Any one node outage would cause the whole system to grind to a halt. If we have a synchronous replication setting enabled on a database, it usually means that one of the followers is synchronous, and the others are asynchronous. If the synchronous follower becomes unavailable or slow, one of the asynchronous followers is promoted to synchronous. It guarantees we have an up-to-date copy of the data on at least two nodes: the leader and one synchronous follower.&lt;/p&gt;

&lt;p&gt;In asynchronous replication, if the leader fails and isn't recoverable, any writes that haven't yet been replicated to the followers are lost. It means the writes aren't guaranteed to be durable, even if it has been confirmed to the client. However, the advantage of a fully asynchronous configuration is that the leader can continue processing writes even if all the followers have fallen behind. Weak durability may sound like a bad trade-off, but asynchronous replication is widely used, especially if there are many followers or if they are geographically distributed.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to add new Followers?
&lt;/h2&gt;

&lt;p&gt;Let's say we want to add a new replica because we want to scale or replace a failed node. Simply copying data files from one node to another is not sufficient. Clients are constantly writing to the database, and the data is always in flux, so a standard file copy would see different parts of the database at different points in time. We can lock the database, making it unavailable for any writes, but that would go against our goal of high availability. &lt;/p&gt;

&lt;p&gt;Here is how it's done&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Take a consistent snapshot of the leader's database at some point in time. If possible, without taking a lock on the database&lt;/li&gt;
&lt;li&gt;Copy the snapshot to the new follower node&lt;/li&gt;
&lt;li&gt;The follower connects to the leader and requests all the data changes that have happened since the snapshot was taken&lt;/li&gt;
&lt;li&gt;When the followers have processed the backlog of data changes since the snapshot, we say it has caught up. It can now continue to process data changes from the leader as they happen&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Handling Node Outages
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Follower Failure
&lt;/h3&gt;

&lt;p&gt;Each follower stores a log of the data changes it has received from the leader on its local disk. If a follower crashes and restarts or the network between the leader and the follower is temporarily interrupted. The follower can recover from its log: it knows the last transaction that was processed before the fault occurred. Thus, the follower can connect to the leader and request all the data changes that occurred when the follower was disconnected. &lt;/p&gt;

&lt;h3&gt;
  
  
  Leader Failure
&lt;/h3&gt;

&lt;p&gt;What if the leader himself goes down? TLDR; One of the followers is promoted to be the leader. Clients are reconfigured to send all the writes to the new leader, and the followers need to start consuming data from the new leader. This process is called &lt;em&gt;failover&lt;/em&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There is no foolproof way of detecting what has gone wrong, so most systems use a timeout. Nodes frequently bounce messages back and forth between each other, and if a node doesn't respond for some time - say 30 seconds, it is assumed to be dead. (This doesn't apply if the leader is taken down for planned maintenance)&lt;/li&gt;
&lt;li&gt;Choosing a new leader is done through an election where the leader is chosen by a majority of the remaining replicas, or a new replica could be appointed by the previous leader. The best candidate is usually the replica with the most up-to-date data changes from the previous leader.&lt;/li&gt;
&lt;li&gt;Clients are now reconfigured to send their write requests to the new leader. If the old leader comes back, it might still believe it is the leader, not realizing that the other replicas have forced it to step down. The system has to ensure that the older leader becomes a follower and recognizes the new leader.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The time between when the leader is down and the next leader is getting elected. Writes are blocked or queued in the leaderless period. Consistent reads are served by the replicas if synchronous replication is enabled else there is the possibility that stale and inconsistent data is served because of eventual consistency.&lt;/p&gt;

&lt;h4&gt;
  
  
  What could go wrong with Failover?
&lt;/h4&gt;

&lt;p&gt;If asynchronous replication is used, the new leader may not have received all the writes from the old leader before it failed. If the former leader rejoins the cluster after a new leader has been chosen, what should happen to the writes that the new leader hasn't received? The new leader may receive conflicting writes in the meantime. The most common solution is to discard the unreplicated changes of the old leader. But, discarding the writes is dangerous business as it violates the client's durability.&lt;/p&gt;

&lt;p&gt;In certain fault situations, two nodes might believe that they are the leader. This situation is called &lt;em&gt;split brain&lt;/em&gt;, and it is dangerous. If both the leaders accept writes, and there is no process for resolving conflicts, data is likely to be lost or corrupted. As a safety catch, some systems have mechanisms to shut down one node if two leaders are detected. &lt;/p&gt;

&lt;p&gt;And finally, what should be the ideal timeout before the leader is declared dead? A longer timeout means a longer time to recover in case where the leader fails. However, if the timeout is too short, there could be unnecessary failovers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation of Replication Logs
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Statement Based Replication
&lt;/h3&gt;

&lt;p&gt;The leader logs every write request that it executes and sends that statement log to its followers. For a relational database, every &lt;em&gt;INSERT, UPDATE, or DELETE&lt;/em&gt; statement is forwarded to followers, and each follower parses and executes that SQL statement as it has received from a client. But this approach could break down on statements that call a non-deterministic function such as &lt;em&gt;Now()&lt;/em&gt; or &lt;em&gt;RAND()&lt;/em&gt; that is likely to generate different values on each replica.&lt;/p&gt;

&lt;h3&gt;
  
  
  Write Ahead Log (WAL)
&lt;/h3&gt;

&lt;p&gt;This log is an append-only sequence of bytes containing all writes to the database. We can use the same log to build a replica on another node. The main disadvantage is that the log describes the data on a very low level, which makes it tightly coupled to the storage engine. If the database changes its storage format from one version to another, it is typically not possible to run different versions of the database software on the leader and the followers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Logical Log Replication (row-based)
&lt;/h3&gt;

&lt;p&gt;A logical log is decoupled from the storage engine and uses different log formats for the storage engine and replication. For a relational database, it is usually a sequence of records describing writes to database tables at the granularity of a row. As it is decoupled from a storage engine, it can be made backward compatible, allowing the leader and the follower to run different versions of the database software or even different storage engines.&lt;/p&gt;

&lt;h2&gt;
  
  
  Parting Words
&lt;/h2&gt;

&lt;p&gt;The first part of the blog series aimed at laying the foundation for future blogs in this series on replication in distributed systems. We still have a lot to discuss on this topic that we will do in the next one.&lt;/p&gt;

&lt;p&gt;If you liked the blog, don't forget to share it on &lt;a href="https://twitter.com/intent/tweet?text=I%20just%20read%20this%20blog%20%22Replication%20in%20Distributed%20Systems%20-%20Part%201%22%20by%20%40manthanguptaa%20and%20%3Cshare%20positive%20words%20with%20the%20world%3E.%0AHere%20is%20the%20link%20to%20this%20awesome%20blog%3A&amp;amp;url=https%3A%2F%2Fmanthanguptaa.in%2Fposts%2Freplication_in_distributed_systems_part_1%2F%20%20"&gt;Twitter&lt;/a&gt;, LinkedIn, Peerlist, and other social platforms and tag me. You may also write to me at &lt;a href="mailto:guptaamanthan01@gmail.com"&gt;guptaamanthan01@gmail.com&lt;/a&gt; to share your thoughts about the blog.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Designing Data-Intensive Applications: The Big Ideas Behind Reliable, Scalable, and Maintainable Systems by Martin Kleppmann&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>distributedsystems</category>
      <category>database</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>Data Structures That Power Your Databases</title>
      <dc:creator>Manthan Gupta</dc:creator>
      <pubDate>Mon, 29 Jan 2024 15:40:22 +0000</pubDate>
      <link>https://dev.to/manthanguptaa/data-structures-that-power-your-databases-54fc</link>
      <guid>https://dev.to/manthanguptaa/data-structures-that-power-your-databases-54fc</guid>
      <description>&lt;p&gt;Have you ever thought about why databases are so complex internally and why we can't use a text file to store the data? This blog post aims to go from the most basic database that writes data to text files to a more complex setting where we use LSM-tree and B-tree. We will understand why we need these data structures and more.&lt;/p&gt;

&lt;h2&gt;
  
  
  World's Simplest Key-Value Store
&lt;/h2&gt;

&lt;p&gt;What does the world's simplest key-value store look like? 2 bash function that writes data to a text file and gets data from the text file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;db_set&lt;span class="o"&gt;(){&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; database
&lt;span class="o"&gt;}&lt;/span&gt;

db_get&lt;span class="o"&gt;(){&lt;/span&gt;
    &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"^&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;,"&lt;/span&gt; database | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"s/^&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;,//"&lt;/span&gt; | &lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 1
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let me explain both the functions. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The db_set() function appends to the end of the file without any logic. That means if you update the value of a key, it will not overwrite the value but create a new key value at the end of the file. &lt;/li&gt;
&lt;li&gt;The db_get() function gets the last occurrence of the key.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What's the problem with this implementation?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Doesn't deal with concurrency control, reclaiming disk space, handling errors, and partially written records.&lt;/li&gt;
&lt;li&gt;db_get() function has terrible performance as it takes O(n) to lookup for a record.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To efficiently find the value of a key, we need a different data structure: &lt;strong&gt;an index&lt;/strong&gt;. The general idea behind indexes is to keep some additional metadata on the side, which acts as a signpost and helps you locate the data you want. But this comes with a tradeoff as it slows down writes but offers fast reads.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hash Indexes
&lt;/h2&gt;

&lt;p&gt;I am not planning to dive deep into the workings of a hash indexes in this particular blog. I plan on covering it in a future blog, but till then, you can refer to &lt;a href="https://samuel-sorial.hashnode.dev/understanding-hash-indexes"&gt;this blog&lt;/a&gt; to understand more about it.&lt;/p&gt;

&lt;p&gt;Let's again go back to our key-value store. The strategy to improve the lookup speed is to keep an in-memory hash map where every key is mapped to a byte offset in the file. Whenever a new key is appended to the file, the hash map is also updated to reflect the offset.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp121buajb11oyxe1ikq8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp121buajb11oyxe1ikq8.png" alt="Byte Offset" width="800" height="298"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  How do we avoid running out of disk space as we are only appending to the file?
&lt;/h3&gt;

&lt;p&gt;We break the files into smaller segments and perform &lt;strong&gt;compaction&lt;/strong&gt; on each segment. Compaction is throwing away the duplicate keys in the file and keeping only the most recent update for each key. We can perform compaction over multiple segments together at the same time. Segments are never modified, so the merged segment is written to a new file. It is done in the background while we serve read and write requests using the old segment files.&lt;/p&gt;

&lt;p&gt;But there are some things to take care of with the implementation and limitations of the hash table index:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hash table must fit in memory because, on disk, it is hard to get the same performance&lt;/li&gt;
&lt;li&gt;We can't do range queries efficiently&lt;/li&gt;
&lt;li&gt;If the database is restarted, the in-memory hash maps are lost. We rebuild the index by reading the entire segment file from beginning to end. It will take a lot of time. We can have a snapshot of each segment's hash map on disk to solve this issue&lt;/li&gt;
&lt;li&gt;Database may crash halfway through appending a record that can be resolved by including checksums&lt;/li&gt;
&lt;li&gt;Writes are appended to the file in a strictly sequential order. A common implementation is to have only 1 write thread and multiple read threads&lt;/li&gt;
&lt;li&gt;When merging segments, the &lt;strong&gt;tombstone&lt;/strong&gt; tells the merging process to discard any previous values for the deleted key&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  SSTables
&lt;/h2&gt;

&lt;p&gt;A simple change to our segment files can help us get rid of maintaining the hash index with all keys. We store the key-value pairs in a sorted-by-key order. We call this format &lt;strong&gt;SSTable&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What advantages do we gain over the hash index?
&lt;/h3&gt;

&lt;p&gt;Merging the segment files gets simple and efficient even if the files are larger than the available memory. The merge sort algorithm is used to create new merged segment files, also sorted by key. We now don't need to maintain an index of all keys in memory. We build a sparse index where we get the keys between which our key lies. It saves disk space and I/O bandwidth.&lt;/p&gt;

&lt;h4&gt;
  
  
  How is this SSTable constructed and maintained?
&lt;/h4&gt;

&lt;p&gt;When writes come in we add it to the in-memory tree &lt;strong&gt;memtable&lt;/strong&gt;. When it gets bigger than a threshold, we write all the data from the memtable to the SSTable file. The new SSTable file becomes the most recent segment of the database. While we write to SSTable, writes continue to new memtable instance.&lt;br&gt;
When read requests come in we first search for the key in memtable then in the most recent on-disk segment, then in the next older segment and so on. And from time to time we run compaction in the background. We can also keep a seperate log on disk to which every write is immediately appended for durability purposes.&lt;/p&gt;

&lt;h2&gt;
  
  
  LSM Tree
&lt;/h2&gt;

&lt;p&gt;Log-structure merge-tree or LSM tree is a clever algorithm based on the above principle of merging and compacting sorted files. LSM is append-only as we only append all the modfications to the SSTable.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4nqyu4hzrvglw8lcx1bd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4nqyu4hzrvglw8lcx1bd.png" alt="LSM Tree Algorithm" width="800" height="739"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The LSM tree algorithm can be slow when looking up keys that do not exist in the database. We first check the memtable and then all the segments. Storage engines use &lt;strong&gt;Bloom Filters&lt;/strong&gt; to optimize the algorithm. &lt;/p&gt;

&lt;p&gt;A bloom filter is a memory-efficient data structure for approximating the contents of a set. It can tell if a key exists in the database and thus save many unnecessary disk reads for keys that don't exist.&lt;/p&gt;

&lt;h2&gt;
  
  
  B Tree
&lt;/h2&gt;

&lt;p&gt;B Tree keeps key-value pairs sorted by keys like SSTable, which allows efficient key lookups and range queries. It breaks down the database into fixed-size blocks or pages, traditionally 4Kb in size, and reads or writes one page at a time. This design corresponds closely to the underlying hardware, as disks are also arranged in fixed-size blocks.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft1pi9yimk2z0fsx2jv7u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft1pi9yimk2z0fsx2jv7u.png" alt="B Tree" width="800" height="417"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An append-only file where we capture all B tree modifications before applying them to the pages of the tree itself. It is a &lt;strong&gt;write-ahead log&lt;/strong&gt; (WAL or redo log) that helps make the database crash-resilient. We use latches (lightweight locks) to protect our B tree when multiple threads try to access the B tree at the same time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which one is better? LSM Tree vs B Tree
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;B Tree writes every piece of data at least twice: once to the write-ahead log and once to the tree page itself (and sometimes again when the pages split). The log-structure index rewrites data multiple times due to the repeated compaction and merging of SSTable. It results in one write to the database and multitudinous writes to the disk over the course of the database's lifetime - known as &lt;strong&gt;write amplification&lt;/strong&gt;. It is a concern on SSDs as a limited number of overwrites can perform before wearing out.&lt;/li&gt;
&lt;li&gt;LSM trees can be compressed better, resulting in smaller files on disk than B trees.&lt;/li&gt;
&lt;li&gt;B tree storage engine leaves some disk space unused due to fragmentation when the page is split or the row cannot fit in an existing table. LSM trees aren't page oriented and periodically rewrite SSTables to remove fragmentation.&lt;/li&gt;
&lt;li&gt;The compaction process can sometimes interfere with the performance of ongoing reads and writes. At high throughput, the disk's finite bandwidth is shared between the initial write and the compaction threads running in the background. The bigger the database gets, the more disk bandwidth is required for compaction.&lt;/li&gt;
&lt;li&gt;In B trees, each key only exists in exactly one place in the index, whereas a log-structured storage engine may have multiple copies of the same key in different segments. It makes B trees attractive in databases that want to offer strong transactional semantics.&lt;/li&gt;
&lt;li&gt;LSM trees are typically able to sustain a higher write throughput than B trees. But B trees are thought to offer faster read throughput.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Parting Words
&lt;/h2&gt;

&lt;p&gt;There are definitely more data structures that power databases like skiplist, inverted index, R tree, suffix tree, etc. But this blog introduces to the more famous ones and to help understand the underlying working of them.&lt;/p&gt;

&lt;p&gt;If you liked the blog don't forget to share it on &lt;a href="https://twitter.com/intent/tweet?text=I%20just%20read%20this%20blog%20%22Data%20Structures%20That%20Power%20Your%20Databases%22%20by%20%40manthanguptaa%20and%20%3Cshare%20positive%20words%20with%20the%20world%3E.%0AHere%20is%20the%20link%20to%20this%20awesome%20blog%3A%20&amp;amp;url=https%3A%2F%2Fmanthanguptaa.in%2Fposts%2Fdata_structures_that_power_your_databases%2F"&gt;Twitter&lt;/a&gt;, LinkedIn, Peerlist, and other social platforms and tag me. You may also write to me on &lt;a href="mailto:guptaamanthan01@gmail.com"&gt;guptaamanthan01@gmail.com&lt;/a&gt; to share your thoughts about the blog.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Designing Data-Intensive Applications: The Big Ideas Behind Reliable, Scalable, and Maintainable Systems by Martin Kleppmann&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>distributedsystems</category>
      <category>database</category>
    </item>
  </channel>
</rss>
