<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://suvratapte.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://suvratapte.com/" rel="alternate" type="text/html" /><updated>2025-08-07T14:35:36+00:00</updated><id>https://suvratapte.com/feed.xml</id><title type="html">Ponderings of a Curious Mind</title><subtitle>This is a tech blog by Suvrat Apte. About Emacs, Clojure and other interesting things.</subtitle><author><name>Suvrat Apte</name></author><entry><title type="html">Our new album - Raga Bihag - is out!</title><link href="https://suvratapte.com/raga-bihag-released/" rel="alternate" type="text/html" title="Our new album - Raga Bihag - is out!" /><published>2025-03-28T09:45:40+00:00</published><updated>2025-03-28T09:45:40+00:00</updated><id>https://suvratapte.com/raga-bihag-released</id><content type="html" xml:base="https://suvratapte.com/raga-bihag-released/"><![CDATA[<p>Here is another album with the incredible - Stian Grimstad!</p>

<p>We have recorded 3 short and sweet tracks in Raga Bihag - Alaap, Vilmabit Teentaal and Drut Teentaal.</p>

<iframe data-testid="embed-iframe" style="border-radius:12px" src="https://open.spotify.com/embed/album/4uA2lJXx5wGPTC5HZ6O08H?utm_source=generator" width="100%" height="352" frameborder="0" allowfullscreen="" allow="autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture" loading="lazy"></iframe>

<p><br /></p>

<p>Hope you like it! :)</p>]]></content><author><name>Suvrat Apte</name></author><category term="music," /><category term="indian-classical-music," /><category term="sitar," /><category term="tabla," /><category term="bihag" /><summary type="html"><![CDATA[Here is another album with the incredible - Stian Grimstad! We have recorded 3 short and sweet tracks in Raga Bihag - Alaap, Vilmabit Teentaal and Drut Teentaal. Hope you like it! :)]]></summary></entry><entry><title type="html">Our new album - Raga Hemavati - is out!</title><link href="https://suvratapte.com/raga-hemavati-released/" rel="alternate" type="text/html" title="Our new album - Raga Hemavati - is out!" /><published>2025-02-21T09:45:40+00:00</published><updated>2025-02-21T09:45:40+00:00</updated><id>https://suvratapte.com/raga-hemavati-released</id><content type="html" xml:base="https://suvratapte.com/raga-hemavati-released/"><![CDATA[<p>I recently recorded a new album with my dear friend Stian Grimstad.</p>

<p>We have recorded 3 short and sweet tracks in the rare Raga Hemavati - Alaap, Vilmabit Teentaal and Drut Teentaal.</p>

<iframe data-testid="embed-iframe" style="border-radius:12px" src="https://open.spotify.com/embed/album/57TRyUfJ6y5gawESzWgjxF?utm_source=generator" width="100%" height="352" frameborder="0" allowfullscreen="" allow="autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture" loading="lazy"></iframe>

<p><br /></p>

<p>Hope you like it! :)</p>]]></content><author><name>Suvrat Apte</name></author><category term="music," /><category term="indian-classical-music," /><category term="sitar," /><category term="tabla," /><category term="hemavati" /><summary type="html"><![CDATA[I recently recorded a new album with my dear friend Stian Grimstad. We have recorded 3 short and sweet tracks in the rare Raga Hemavati - Alaap, Vilmabit Teentaal and Drut Teentaal. Hope you like it! :)]]></summary></entry><entry><title type="html">Simulating Prisoner’s Dilemma</title><link href="https://suvratapte.com/simulating-prisoners-dilemma/" rel="alternate" type="text/html" title="Simulating Prisoner’s Dilemma" /><published>2024-06-01T06:45:40+00:00</published><updated>2024-06-01T06:45:40+00:00</updated><id>https://suvratapte.com/simulating-prisoners-dilemma</id><content type="html" xml:base="https://suvratapte.com/simulating-prisoners-dilemma/"><![CDATA[<p>A recent <a href="https://www.youtube.com/watch?v=mScpHTIi-kM">Veritasium
video</a> sparked my
interest in Game Theory, and I decided to try to implement some of the
experiments in it.</p>

<p>When I was talking about this with a friend of mine, she incessantly
pushed me to write an <a href="/resources/ganit-sahakaryache.pdf">
article about it in Marathi in a magazine</a>. This is a post
accompanying the article. I will only discuss the implementation in
this post. I would highly recommend watching the <a href="https://www.youtube.com/watch?v=mScpHTIi-kM">Veritasium
video</a> before reading
further. <a href="https://en.wikipedia.org/wiki/Derek_Muller">Derek</a> has done
a phenomenal job in this one.</p>

<p>The word “game” in game theory makes it seem that it is related to
(possibly silly) computer or board games. But that is not true. In
game theory, we create models which attempt to replicate real life
situations in terms of rules and some scoring system to measure the
outcomes. A “game” also has rules and a scoring system, hence the name.</p>

<p>Prisoner’s Dilemma is one of the famous games in game theory. You can read about
it <a href="https://en.wikipedia.org/wiki/Prisoner%27s_dilemma">here</a>.</p>

<p>We are going to implement an inverted version of this game. The rules
of our game are as follows:</p>

<p>There are two players who can either cooperate with each other or
defect. If both cooperate, they each get 3 points. If one cooperates
and the other defects, the defector gets 5 points while the cooperator
gets 0. If both defect, they each get 1 point.</p>

<table>
  <thead>
    <tr>
      <th> </th>
      <th>Player 1 cooperates</th>
      <th>Player 1 defects</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Player 2 cooperates</strong></td>
      <td>P1 - <strong>3</strong> <br /> P2 - <strong>3</strong></td>
      <td>P1 - <strong>5</strong> <br /> P2 - <strong>0</strong></td>
    </tr>
    <tr>
      <td><strong>Player 2 deffects</strong></td>
      <td>P1 - <strong>0</strong> <br /> P2 - <strong>5</strong></td>
      <td>P1 - <strong>1</strong> <br /> P2 - <strong>1</strong></td>
    </tr>
  </tbody>
</table>

<p>My plan is to implement a two player version first and then implement a
multi-player version (which will be a new post).</p>

<!---excerpt-break-->

<h2 id="implementation">Implementation</h2>

<p>This game will be played between two players over many
rounds. Therefore, we need to store the moves that each player makes
in all the rounds, as well as their scores. Let’s define the state of
the game:</p>

<figure class="highlight"><pre><code class="language-clojure" data-lang="clojure"><span class="p">(</span><span class="k">def</span><span class="w"> </span><span class="n">initial-state</span><span class="w">
  </span><span class="p">{</span><span class="no">:first-player-moves</span><span class="w"> </span><span class="p">[]</span><span class="w">
   </span><span class="no">:second-player-moves</span><span class="w"> </span><span class="p">[]</span><span class="w">
   </span><span class="no">:score</span><span class="w"> </span><span class="p">{</span><span class="no">:first-player</span><span class="w"> </span><span class="mi">0</span><span class="w">
           </span><span class="no">:second-player</span><span class="w"> </span><span class="mi">0</span><span class="p">}})</span></code></pre></figure>

<p>Now let’s see how the players can make a move. For this, we need a
function for each player which will return whether the player wants to
cooperate or defect in the current round. Let’s represent cooperation
with <code class="language-plaintext highlighter-rouge">:co</code> and defection with <code class="language-plaintext highlighter-rouge">:de</code>.</p>

<p>For the players to decide their next moves, we need to provide them with the
history of their previous moves. So that they can devise a strategy which takes
into account the previous moves made by them and their opponent.</p>

<figure class="highlight"><pre><code class="language-clojure" data-lang="clojure"><span class="p">(</span><span class="k">defn-</span><span class="w"> </span><span class="n">tit-for-tat</span><span class="w">
  </span><span class="p">[</span><span class="n">player-moves</span><span class="w"> </span><span class="n">opponent-moves</span><span class="p">]</span><span class="w">
  </span><span class="p">(</span><span class="nb">or</span><span class="w"> </span><span class="p">(</span><span class="nb">last</span><span class="w"> </span><span class="n">opponent-moves</span><span class="p">)</span><span class="w"> </span><span class="no">:co</span><span class="p">))</span><span class="w">

</span><span class="p">(</span><span class="k">defn-</span><span class="w"> </span><span class="n">devil</span><span class="w">
  </span><span class="p">[</span><span class="n">_player-moves</span><span class="w"> </span><span class="n">_opponent-moves</span><span class="p">]</span><span class="w">
  </span><span class="no">:de</span><span class="p">)</span></code></pre></figure>

<p>The <code class="language-plaintext highlighter-rouge">tit-for-tat</code> strategy replicates the other player’s previous
move. If it is the first round, it cooperates. The <code class="language-plaintext highlighter-rouge">devil</code> strategy
always defects.</p>

<p>Now that we know how to write strategy functions to determine moves,
let’s compute the scores based on the moves made by both the players.
Here, we will implement the scoring system as described by the table
above.</p>

<figure class="highlight"><pre><code class="language-clojure" data-lang="clojure"><span class="p">(</span><span class="k">defn-</span><span class="w"> </span><span class="n">compute-score</span><span class="w">
  </span><span class="s">"Returns the score in this format:
   [&lt;first-player-score&gt; &lt;second-player-score&gt;]"</span><span class="w">
  </span><span class="p">[</span><span class="n">first-player-move</span><span class="w"> </span><span class="n">second-player-move</span><span class="p">]</span><span class="w">
  </span><span class="p">(</span><span class="k">cond</span><span class="w">
      </span><span class="c1">;; Both cooperate</span><span class="w">
      </span><span class="p">(</span><span class="nb">and</span><span class="w"> </span><span class="p">(</span><span class="nb">=</span><span class="w"> </span><span class="no">:co</span><span class="w"> </span><span class="n">first-player-move</span><span class="p">)</span><span class="w">
           </span><span class="p">(</span><span class="nb">=</span><span class="w"> </span><span class="no">:co</span><span class="w"> </span><span class="n">second-player-move</span><span class="p">))</span><span class="w">
      </span><span class="p">[</span><span class="mi">3</span><span class="w"> </span><span class="mi">3</span><span class="p">]</span><span class="w">

      </span><span class="c1">;; Both defect</span><span class="w">
      </span><span class="p">(</span><span class="nb">and</span><span class="w"> </span><span class="p">(</span><span class="nb">=</span><span class="w"> </span><span class="no">:de</span><span class="w"> </span><span class="n">first-player-move</span><span class="p">)</span><span class="w">
           </span><span class="p">(</span><span class="nb">=</span><span class="w"> </span><span class="no">:de</span><span class="w"> </span><span class="n">second-player-move</span><span class="p">))</span><span class="w">
      </span><span class="p">[</span><span class="mi">1</span><span class="w"> </span><span class="mi">1</span><span class="p">]</span><span class="w">

      </span><span class="c1">;; One cooperates, other defects</span><span class="w">
      </span><span class="p">(</span><span class="nb">and</span><span class="w"> </span><span class="p">(</span><span class="nb">=</span><span class="w"> </span><span class="no">:co</span><span class="w"> </span><span class="n">first-player-move</span><span class="p">)</span><span class="w">
           </span><span class="p">(</span><span class="nb">=</span><span class="w"> </span><span class="no">:de</span><span class="w"> </span><span class="n">second-player-move</span><span class="p">))</span><span class="w">
      </span><span class="p">[</span><span class="mi">0</span><span class="w"> </span><span class="mi">5</span><span class="p">]</span><span class="w">

      </span><span class="p">(</span><span class="nb">and</span><span class="w"> </span><span class="p">(</span><span class="nb">=</span><span class="w"> </span><span class="no">:de</span><span class="w"> </span><span class="n">first-player-move</span><span class="p">)</span><span class="w">
           </span><span class="p">(</span><span class="nb">=</span><span class="w"> </span><span class="no">:co</span><span class="w"> </span><span class="n">second-player-move</span><span class="p">))</span><span class="w">
      </span><span class="p">[</span><span class="mi">5</span><span class="w"> </span><span class="mi">0</span><span class="p">]))</span></code></pre></figure>

<p>The <code class="language-plaintext highlighter-rouge">compute-score</code> function, as the name suggests, calculates the
score based on the moves of the first and second players.</p>

<p>Now to play this game over and over again for many rounds, we have to
update the state of the game after each round to keep the track of the
moves history and the total score. Let’s do that:</p>

<figure class="highlight"><pre><code class="language-clojure" data-lang="clojure"><span class="p">(</span><span class="k">defn-</span><span class="w"> </span><span class="n">simulate-game</span><span class="w">
  </span><span class="p">[</span><span class="n">rounds-number</span><span class="w"> </span><span class="n">first-player-stragey</span><span class="w"> </span><span class="n">second-player-stragey</span><span class="p">]</span><span class="w">
  </span><span class="p">(</span><span class="nb">loop</span><span class="w"> </span><span class="p">[</span><span class="n">state</span><span class="w"> </span><span class="n">initial-state</span><span class="w">
         </span><span class="n">n</span><span class="w"> </span><span class="n">rounds-number</span><span class="p">]</span><span class="w">
    </span><span class="p">(</span><span class="k">let</span><span class="w"> </span><span class="p">[</span><span class="n">first-player-moves</span><span class="w"> </span><span class="p">(</span><span class="no">:first-player-moves</span><span class="w"> </span><span class="n">state</span><span class="p">)</span><span class="w">
          </span><span class="n">second-player-moves</span><span class="w"> </span><span class="p">(</span><span class="no">:second-player-moves</span><span class="w"> </span><span class="n">state</span><span class="p">)</span><span class="w">

          </span><span class="n">first-player-move</span><span class="w"> </span><span class="p">(</span><span class="nf">first-player-stragey</span><span class="w"> </span><span class="n">first-player-moves</span><span class="w">
                                                  </span><span class="n">second-player-moves</span><span class="p">)</span><span class="w">
          </span><span class="n">second-player-move</span><span class="w"> </span><span class="p">(</span><span class="nf">second-player-stragey</span><span class="w"> </span><span class="n">second-player-moves</span><span class="w">
                                                    </span><span class="n">first-player-moves</span><span class="p">)</span><span class="w">

          </span><span class="p">[</span><span class="n">first-player-score</span><span class="w"> </span><span class="n">second-player-score</span><span class="p">]</span><span class="w">
          </span><span class="p">(</span><span class="nf">compute-score</span><span class="w"> </span><span class="n">first-player-move</span><span class="w">
                         </span><span class="n">second-player-move</span><span class="p">)</span><span class="w">

          </span><span class="n">new-state</span><span class="w"> </span><span class="p">(</span><span class="nb">-&gt;</span><span class="w"> </span><span class="n">state</span><span class="w">
                        </span><span class="p">(</span><span class="nf">update</span><span class="w"> </span><span class="no">:first-player-moves</span><span class="w"> </span><span class="nb">conj</span><span class="w"> </span><span class="n">first-player-move</span><span class="p">)</span><span class="w">
                        </span><span class="p">(</span><span class="nf">update</span><span class="w"> </span><span class="no">:second-player-moves</span><span class="w"> </span><span class="nb">conj</span><span class="w"> </span><span class="n">second-player-move</span><span class="p">)</span><span class="w">
                        </span><span class="p">(</span><span class="nf">update-in</span><span class="w"> </span><span class="p">[</span><span class="no">:score</span><span class="w"> </span><span class="no">:first-player</span><span class="p">]</span><span class="w"> </span><span class="nb">+</span><span class="w"> </span><span class="n">first-player-score</span><span class="p">)</span><span class="w">
                        </span><span class="p">(</span><span class="nf">update-in</span><span class="w"> </span><span class="p">[</span><span class="no">:score</span><span class="w"> </span><span class="no">:second-player</span><span class="p">]</span><span class="w"> </span><span class="nb">+</span><span class="w"> </span><span class="n">second-player-score</span><span class="p">))</span><span class="w">

          </span><span class="n">n</span><span class="w"> </span><span class="p">(</span><span class="nb">dec</span><span class="w"> </span><span class="n">n</span><span class="p">)]</span><span class="w">
      </span><span class="p">(</span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nb">pos?</span><span class="w"> </span><span class="n">n</span><span class="p">)</span><span class="w">
        </span><span class="p">(</span><span class="nf">recur</span><span class="w"> </span><span class="n">new-state</span><span class="w"> </span><span class="n">n</span><span class="p">)</span><span class="w">
        </span><span class="n">new-state</span><span class="p">))))</span></code></pre></figure>

<p>This is the complete implementation of the two-player version of this
game. Now we can simulate the game between two strategies:</p>

<figure class="highlight"><pre><code class="language-clojure" data-lang="clojure"><span class="p">(</span><span class="nf">simulate-game</span><span class="w"> </span><span class="mi">100</span><span class="w"> </span><span class="n">devil</span><span class="w"> </span><span class="n">tit-for-tat</span><span class="p">)</span><span class="w">

</span><span class="c1">;; Or if you just want to see the score</span><span class="w">

</span><span class="p">(</span><span class="nb">-&gt;</span><span class="w"> </span><span class="mi">2000</span><span class="w">
    </span><span class="p">(</span><span class="nf">simulate-game</span><span class="w"> </span><span class="n">tit-for-tat</span><span class="w"> </span><span class="n">devil</span><span class="p">)</span><span class="w">
    </span><span class="no">:score</span><span class="p">)</span></code></pre></figure>

<p>I have written some more strategies
<a href="https://github.com/suvratapte/game-theory/blob/main/src/game_theory/single_player.clj">here</a>.</p>

<p>Play around and find out which is the best strategy! :-)</p>

<p>I have also written a multi player version <a href="https://github.com/suvratapte/game-theory/blob/main/src/game_theory/multi_player.clj">here</a>.
I will soon write a post about it.</p>

<p>Feel free to make a PR if you think anything in the code needs to be
improved.</p>

<p>Happy learning! :-)</p>]]></content><author><name>Suvrat Apte</name></author><category term="clojure," /><category term="game-theory" /><summary type="html"><![CDATA[A recent Veritasium video sparked my interest in Game Theory, and I decided to try to implement some of the experiments in it. When I was talking about this with a friend of mine, she incessantly pushed me to write an article about it in Marathi in a magazine. This is a post accompanying the article. I will only discuss the implementation in this post. I would highly recommend watching the Veritasium video before reading further. Derek has done a phenomenal job in this one. The word “game” in game theory makes it seem that it is related to (possibly silly) computer or board games. But that is not true. In game theory, we create models which attempt to replicate real life situations in terms of rules and some scoring system to measure the outcomes. A “game” also has rules and a scoring system, hence the name. Prisoner’s Dilemma is one of the famous games in game theory. You can read about it here. We are going to implement an inverted version of this game. The rules of our game are as follows: There are two players who can either cooperate with each other or defect. If both cooperate, they each get 3 points. If one cooperates and the other defects, the defector gets 5 points while the cooperator gets 0. If both defect, they each get 1 point.   Player 1 cooperates Player 1 defects Player 2 cooperates P1 - 3 P2 - 3 P1 - 5 P2 - 0 Player 2 deffects P1 - 0 P2 - 5 P1 - 1 P2 - 1 My plan is to implement a two player version first and then implement a multi-player version (which will be a new post).]]></summary></entry><entry><title type="html">Our new album - Anandpriya - is out!</title><link href="https://suvratapte.com/anandpriya-released/" rel="alternate" type="text/html" title="Our new album - Anandpriya - is out!" /><published>2023-08-25T09:45:40+00:00</published><updated>2023-08-25T09:45:40+00:00</updated><id>https://suvratapte.com/anandpriya-released</id><content type="html" xml:base="https://suvratapte.com/anandpriya-released/"><![CDATA[<p>KG Westman and I recorded this exciting new album a few weeks back and now it is out!</p>

<p>It contains a long presentation of raga Anandpriya (created by KG Westman) - Alaap, Jod, Jhala, Gat in Vilambit Teentaal and Gat in Drut Ektaal.</p>

<p>It also contains a shorter presentation of raga Kirwai - Alaap, Jod, Jhala and a Gat in Rupak.</p>

<iframe data-testid="embed-iframe" style="border-radius:12px" src="https://open.spotify.com/embed/album/40ZSGldzvLw0oL1EP3pvTv?utm_source=generator" width="100%" height="352" frameborder="0" allowfullscreen="" allow="autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture" loading="lazy"></iframe>

<p><br /></p>

<p>Hope you like it! :)</p>]]></content><author><name>Suvrat Apte</name></author><category term="music," /><category term="indian-classical-music," /><category term="sitar," /><category term="tabla," /><category term="kirwani," /><category term="anandpriya" /><summary type="html"><![CDATA[KG Westman and I recorded this exciting new album a few weeks back and now it is out! It contains a long presentation of raga Anandpriya (created by KG Westman) - Alaap, Jod, Jhala, Gat in Vilambit Teentaal and Gat in Drut Ektaal. It also contains a shorter presentation of raga Kirwai - Alaap, Jod, Jhala and a Gat in Rupak. Hope you like it! :)]]></summary></entry><entry><title type="html">Raag Mishra-Charukeshi in Luxembourg</title><link href="https://suvratapte.com/naghma-luxembourg/" rel="alternate" type="text/html" title="Raag Mishra-Charukeshi in Luxembourg" /><published>2023-04-09T07:14:40+00:00</published><updated>2023-04-09T07:14:40+00:00</updated><id>https://suvratapte.com/naghma-luxembourg</id><content type="html" xml:base="https://suvratapte.com/naghma-luxembourg/"><![CDATA[<p>This is from one of the recordings we did in Luxembourg after the Indian classical music workshop KG Westman and I conducted.
<br /> The base composition is composed by KG Westman.
<br /></p>

<iframe width="672" height="378" src="https://www.youtube.com/embed/PP6yRMjiDUc" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen=""></iframe>

<p><br /> KG Westman - Sitar
<br /> Mohammed Abuzekry - Oud
<br /> Ahmed Radwan - Violin
<br /> Achal Murthy - Bass</p>

<p>Gratitude to <a href="https://www.facebook.com/adham.alsayyad" target="_blank">Adham Al-Sayyad</a> and to the <a href="https://www.facebook.com/belong.esch22" target="_blank">Belong</a> team for organizing the workshop and the recording.</p>]]></content><author><name>Suvrat Apte</name></author><category term="music," /><category term="indian-classical-music," /><category term="sitar," /><category term="tabla" /><summary type="html"><![CDATA[This is from one of the recordings we did in Luxembourg after the Indian classical music workshop KG Westman and I conducted. The base composition is composed by KG Westman. KG Westman - Sitar Mohammed Abuzekry - Oud Ahmed Radwan - Violin Achal Murthy - Bass Gratitude to Adham Al-Sayyad and to the Belong team for organizing the workshop and the recording.]]></summary></entry><entry><title type="html">Our new album - Zafaran - is out!</title><link href="https://suvratapte.com/zafaran-released/" rel="alternate" type="text/html" title="Our new album - Zafaran - is out!" /><published>2022-06-21T09:45:40+00:00</published><updated>2022-06-21T09:45:40+00:00</updated><id>https://suvratapte.com/zafaran-released</id><content type="html" xml:base="https://suvratapte.com/zafaran-released/"><![CDATA[<p>We recently recorded a music album which is a mix of Indian, Swedish and Egyptian music. The songs are composed by KG Westman. I got to collaborate with two incredible musicians from Egypt - Adham Al Sayyad and Ahmed Radwan. Here’s the album:</p>

<iframe style="border-radius:12px" src="https://open.spotify.com/embed/album/5lNYtd8IocZE2AbRsmM0s6?utm_source=generator&amp;theme=0" width="100%" height="380" frameborder="0" allowfullscreen="" allow="autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture"></iframe>

<p><br /></p>

<p>My favourites are Piloo, Kaaphal Hill and Hårgalåten!</p>

<p>Hope you like it! :)</p>]]></content><author><name>Suvrat Apte</name></author><category term="music," /><category term="indian-classical-music," /><category term="sitar," /><category term="tabla," /><category term="aud," /><category term="kawala" /><summary type="html"><![CDATA[We recently recorded a music album which is a mix of Indian, Swedish and Egyptian music. The songs are composed by KG Westman. I got to collaborate with two incredible musicians from Egypt - Adham Al Sayyad and Ahmed Radwan. Here’s the album: My favourites are Piloo, Kaaphal Hill and Hårgalåten! Hope you like it! :)]]></summary></entry><entry><title type="html">Sitar performance by KG Westman</title><link href="https://suvratapte.com/performance-with-kg-westman/" rel="alternate" type="text/html" title="Sitar performance by KG Westman" /><published>2022-01-21T05:40:40+00:00</published><updated>2022-01-21T05:40:40+00:00</updated><id>https://suvratapte.com/performance-with-kg-westman</id><content type="html" xml:base="https://suvratapte.com/performance-with-kg-westman/"><![CDATA[<p>I recently moved to Stockholm and met one of the most amazing sitar players in Europe - KG Westman.
I got an opportunity to accompany him at a concert.</p>

<p>He played raga Anandpriya. It is his own creation.
Here’s the video of the performance:</p>

<iframe width="672" height="378" src="https://www.youtube.com/embed/w20odMWGdTE" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>

<p><br />
<!---excerpt-break--></p>

<p>This concert was organized by <a href="https://www.facebook.com/watch/dhaibatmusic/" target="_blank">Dhaibat music</a>.</p>

<p>Hope you enjoy the performance! :)</p>

<p>You can read more about KG on his <a href="http://www.kgwestman.com/" target="_blank">website</a>.</p>]]></content><author><name>Suvrat Apte</name></author><category term="music," /><category term="indian-classical-music," /><category term="sitar," /><category term="tabla" /><summary type="html"><![CDATA[I recently moved to Stockholm and met one of the most amazing sitar players in Europe - KG Westman. I got an opportunity to accompany him at a concert. He played raga Anandpriya. It is his own creation. Here’s the video of the performance:]]></summary></entry><entry><title type="html">Org Capure Talk - Emacs Meetup</title><link href="https://suvratapte.com/org-capture-talk/" rel="alternate" type="text/html" title="Org Capure Talk - Emacs Meetup" /><published>2021-04-02T07:43:40+00:00</published><updated>2021-04-02T07:43:40+00:00</updated><id>https://suvratapte.com/org-capture-talk</id><content type="html" xml:base="https://suvratapte.com/org-capture-talk/"><![CDATA[<p>This is a talk that I had given at an Emacs meetup hosted by Helpshift.</p>

<iframe width="672" height="378" src="https://www.youtube.com/embed/tFt6plDQm58" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>

<p><br />
<!---excerpt-break--></p>

<p>Here is the code that was shown in this talk:</p>

<figure class="highlight"><pre><code class="language-elisp" data-lang="elisp"><span class="c1">;; This is the demo file that was used for this meetup: https://www.meetup.com/the-peg/events/270312246/</span>

<span class="c1">;;; Code:</span>

<span class="c1">;; ──────────────────────────── Org mode vars - Default values ──────────────────────────</span>

<span class="p">(</span><span class="k">setq</span> <span class="nv">org-directory</span> <span class="s">"~/org"</span><span class="p">)</span>
<span class="p">(</span><span class="k">setq</span> <span class="nv">org-capture-templates</span> <span class="no">nil</span><span class="p">)</span>


<span class="c1">;; ─────────────────────────────────── Basic templates ──────────────────────────────────</span>

<span class="p">(</span><span class="k">setq</span> <span class="nv">suv-org-personal-todo-file</span> <span class="p">(</span><span class="nv">concat</span> <span class="nv">org-directory</span> <span class="s">"/todo.org"</span><span class="p">))</span>

<span class="c1">;; `org-capture-templates` should be a list of template specifications:</span>
<span class="c1">;; Each specification (&lt;key&gt; &lt;short description&gt; &lt;type&gt; &lt;target&gt; &lt;template&gt; &lt;properties&gt;)</span>

<span class="p">(</span><span class="k">setq</span> <span class="nv">org-capture-templates</span>
      <span class="o">'</span><span class="p">((</span><span class="s">"t"</span>
         <span class="s">"Personal todo"</span>
         <span class="nv">entry</span>
         <span class="p">(</span><span class="nv">file</span> <span class="nv">suv-org-personal-todo-file</span><span class="p">)</span>
         <span class="s">"* TODO %^{Description}"</span><span class="p">)))</span>

<span class="c1">;; Settting cursor position.</span>
<span class="p">(</span><span class="k">setq</span> <span class="nv">org-capture-templates</span>
      <span class="o">'</span><span class="p">((</span><span class="s">"t"</span> <span class="s">"Personal todo"</span> <span class="nv">entry</span> <span class="p">(</span><span class="nv">file</span> <span class="nv">suv-org-personal-todo-file</span><span class="p">)</span>
         <span class="s">"* TODO %^{Description}\n  %?"</span><span class="p">)))</span>

<span class="c1">;; Adding date in logbook.</span>
<span class="p">(</span><span class="k">setq</span> <span class="nv">org-capture-templates</span>
      <span class="o">'</span><span class="p">((</span><span class="s">"t"</span> <span class="s">"Personal todo"</span> <span class="nv">entry</span> <span class="p">(</span><span class="nv">file</span> <span class="nv">suv-org-personal-todo-file</span><span class="p">)</span>
         <span class="s">"* TODO %^{Description}\n  :LOGBOOK:\n  - Added: %U\n  :END:\n  %?"</span><span class="p">)))</span>


<span class="c1">;; ──────────────────────────────── Advanced configuration ────────────────────────────────</span>

<span class="c1">;; Add tags.</span>
<span class="p">(</span><span class="k">setq</span> <span class="nv">org-capture-templates</span>
      <span class="o">'</span><span class="p">((</span><span class="s">"t"</span> <span class="s">"Personal todo"</span> <span class="nv">entry</span> <span class="p">(</span><span class="nv">file</span> <span class="nv">suv-org-personal-todo-file</span><span class="p">)</span>
         <span class="s">"* TODO %^{Description} %^g\n  :LOGBOOK:\n - Added: %U\n  :END:\n  %?"</span><span class="p">)))</span>

<span class="c1">;; Add template for meeting notes.</span>
<span class="p">(</span><span class="k">setq</span> <span class="nv">suv-org-meeting-notes-file</span> <span class="p">(</span><span class="nv">concat</span> <span class="nv">org-directory</span> <span class="s">"/meeting-notes.org"</span><span class="p">))</span>

<span class="p">(</span><span class="k">setq</span> <span class="nv">org-capture-templates</span>
      <span class="o">'</span><span class="p">((</span><span class="s">"t"</span> <span class="s">"Personal todo"</span> <span class="nv">entry</span> <span class="p">(</span><span class="nv">file</span> <span class="nv">suv-org-personal-todo-file</span><span class="p">)</span>
         <span class="s">"* TODO %^{Description} %^g\n  :LOGBOOK:\n - Added: %U\n  :END:\n  %?"</span><span class="p">)</span>

        <span class="p">(</span><span class="s">"m"</span> <span class="s">"Meeting notes"</span> <span class="nv">entry</span> <span class="p">(</span><span class="nv">file</span> <span class="nv">suv-org-meeting-notes-file</span><span class="p">)</span>
         <span class="s">"* %^{Agenda}\n  - Attendees: %^{Attendees}, Suvrat
  - Date: %U\n  - Notes:\n    + %?\n  - Action items [/]\n    + [ ] "</span><span class="p">)))</span>

<span class="c1">;; Prepend</span>
<span class="p">(</span><span class="k">setq</span> <span class="nv">org-capture-templates</span>
      <span class="o">'</span><span class="p">((</span><span class="s">"t"</span> <span class="s">"Personal todo"</span> <span class="nv">entry</span> <span class="p">(</span><span class="nv">file</span> <span class="nv">suv-org-personal-todo-file</span><span class="p">)</span>
         <span class="s">"* TODO %^{Description} %^g\n  :LOGBOOK:\n - Added: %U\n  :END:\n  %?"</span><span class="p">)</span>

        <span class="p">(</span><span class="s">"m"</span> <span class="s">"Meeting notes"</span> <span class="nv">entry</span> <span class="p">(</span><span class="nv">file</span> <span class="nv">suv-org-meeting-notes-file</span><span class="p">)</span>
         <span class="s">"* %^{Agenda}\n  - Attendees: %^{Attendees}, Suvrat
  - Date: %U\n  - Notes:\n    + %?\n  - Action items [/]\n    + [ ] "</span>
         <span class="ss">:prepend</span> <span class="no">t</span><span class="p">)))</span>

<span class="c1">;; Clock-in and clock-resume</span>
<span class="p">(</span><span class="k">setq</span> <span class="nv">org-capture-templates</span>
      <span class="o">'</span><span class="p">((</span><span class="s">"t"</span> <span class="s">"Personal todo"</span> <span class="nv">entry</span> <span class="p">(</span><span class="nv">file</span> <span class="nv">suv-org-personal-todo-file</span><span class="p">)</span>
         <span class="s">"* TODO %^{Description} %^g\n  :LOGBOOK:\n - Added: %U\n  :END:\n  %?"</span><span class="p">)</span>

        <span class="p">(</span><span class="s">"m"</span> <span class="s">"Meeting notes"</span> <span class="nv">entry</span> <span class="p">(</span><span class="nv">file</span> <span class="nv">suv-org-meeting-notes-file</span><span class="p">)</span>
         <span class="s">"* %^{Agenda}\n  - Attendees: %^{Attendees}, Suvrat
  - Date: %U\n  - Notes:\n    + %?\n  - Action items [/]\n    + [ ] "</span>
         <span class="ss">:prepend</span> <span class="no">t</span>
         <span class="ss">:clock-in</span> <span class="no">t</span>
         <span class="ss">:clock-resume</span> <span class="no">t</span><span class="p">)))</span>

<span class="c1">;; Movies</span>
<span class="p">(</span><span class="k">setq</span> <span class="nv">suv-org-movies-file</span> <span class="p">(</span><span class="nv">concat</span> <span class="nv">org-directory</span> <span class="s">"/movies.org"</span><span class="p">))</span>

<span class="c1">;; Immediate-finish</span>
<span class="p">(</span><span class="k">setq</span> <span class="nv">org-capture-templates</span>
      <span class="o">'</span><span class="p">((</span><span class="s">"t"</span> <span class="s">"Personal todo"</span> <span class="nv">entry</span> <span class="p">(</span><span class="nv">file</span> <span class="nv">suv-org-personal-todo-file</span><span class="p">)</span>
         <span class="s">"* TODO %^{Description} %^g\n  :LOGBOOK:\n - Added: %U\n  :END:\n  %?"</span><span class="p">)</span>

        <span class="p">(</span><span class="s">"m"</span> <span class="s">"Meeting notes"</span> <span class="nv">entry</span> <span class="p">(</span><span class="nv">file</span> <span class="nv">suv-org-meeting-notes-file</span><span class="p">)</span>
         <span class="s">"* %^{Agenda}\n  - Attendees: %^{Attendees}, Suvrat
  - Date: %U\n  - Notes:\n    + %?\n  - Action items [/]\n    + [ ] "</span>
         <span class="ss">:prepend</span> <span class="no">t</span><span class="p">)</span>

        <span class="p">(</span><span class="s">"M"</span> <span class="s">"Movie"</span> <span class="nv">entry</span> <span class="p">(</span><span class="nv">file</span> <span class="nv">suv-org-movies-file</span><span class="p">)</span>
         <span class="s">"* TODO %^{Description}"</span>
         <span class="ss">:immediate-finish</span> <span class="no">t</span><span class="p">)))</span>

<span class="c1">;; Work</span>
<span class="p">(</span><span class="k">setq</span> <span class="nv">suv-org-work-file</span> <span class="p">(</span><span class="nv">concat</span> <span class="nv">org-directory</span> <span class="s">"/work.org"</span><span class="p">))</span>

<span class="c1">;; Auto complete for variables and using the variables</span>
<span class="p">(</span><span class="k">setq</span> <span class="nv">org-capture-templates</span>
      <span class="o">'</span><span class="p">((</span><span class="s">"t"</span> <span class="s">"Personal todo"</span> <span class="nv">entry</span> <span class="p">(</span><span class="nv">file</span> <span class="nv">suv-org-personal-todo-file</span><span class="p">)</span>
         <span class="s">"* TODO %^{Description} %^g\n  :LOGBOOK:\n - Added: %U\n  :END:\n  %?"</span><span class="p">)</span>

        <span class="p">(</span><span class="s">"m"</span> <span class="s">"Meeting notes"</span> <span class="nv">entry</span> <span class="p">(</span><span class="nv">file</span> <span class="nv">suv-org-meeting-notes-file</span><span class="p">)</span>
         <span class="s">"* %^{Agenda}\n  - Attendees: %^{Attendees}, Suvrat
  - Date: %U\n  - Notes:\n    + %?\n  - Action items [/]\n    + [ ] "</span>
         <span class="ss">:prepend</span> <span class="no">t</span><span class="p">)</span>

        <span class="p">(</span><span class="s">"M"</span> <span class="s">"Movie"</span> <span class="nv">entry</span> <span class="p">(</span><span class="nv">file</span> <span class="nv">suv-org-movies-file</span><span class="p">)</span>
         <span class="s">"* TODO %^{Description}"</span>
         <span class="ss">:immediate-finish</span> <span class="no">t</span><span class="p">)</span>

        <span class="p">(</span><span class="s">"w"</span> <span class="s">"Work task"</span> <span class="nv">entry</span> <span class="p">(</span><span class="nv">file</span> <span class="nv">suv-org-work-file</span><span class="p">)</span>
         <span class="s">"* TODO %^{Type|TODO|DEP|BUG}-%^{Ticket number} - %^{Description}
  :PROPERTIES:
  :LINK:     https://helpshift.atlassian.net/browse/%\\1-%\\2
  :END:
  :LOGBOOK:\n  - Added - %U\n  :END:\n  "</span><span class="p">)))</span>


<span class="c1">;; ────────────────────────────── Writing code in templates ─────────────────────────────</span>

<span class="p">(</span><span class="k">setq</span> <span class="nv">suv-org-reading-list-file</span> <span class="p">(</span><span class="nv">concat</span> <span class="nv">org-directory</span> <span class="s">"/reading-list.org"</span><span class="p">))</span>

<span class="c1">;; Get from kill ring</span>
<span class="p">(</span><span class="k">setq</span> <span class="nv">org-capture-templates</span>
      <span class="o">'</span><span class="p">((</span><span class="s">"t"</span> <span class="s">"Personal todo"</span> <span class="nv">entry</span> <span class="p">(</span><span class="nv">file</span> <span class="nv">suv-org-personal-todo-file</span><span class="p">)</span>
         <span class="s">"* TODO %^{Description} %^g\n  :LOGBOOK:\n - Added: %U\n  :END:\n  %?"</span><span class="p">)</span>

        <span class="p">(</span><span class="s">"m"</span> <span class="s">"Meeting notes"</span> <span class="nv">entry</span> <span class="p">(</span><span class="nv">file</span> <span class="nv">suv-org-meeting-notes-file</span><span class="p">)</span>
         <span class="s">"* %^{Agenda}\n  - Attendees: %^{Attendees}, Suvrat
  - Date: %U\n  - Notes:\n    + %?\n  - Action items [/]\n    + [ ] "</span>
         <span class="ss">:prepend</span> <span class="no">t</span><span class="p">)</span>

        <span class="p">(</span><span class="s">"M"</span> <span class="s">"Movie"</span> <span class="nv">entry</span> <span class="p">(</span><span class="nv">file</span> <span class="nv">suv-org-movies-file</span><span class="p">)</span>
         <span class="s">"* TODO %^{Description}"</span>
         <span class="ss">:immediate-finish</span> <span class="no">t</span><span class="p">)</span>

        <span class="p">(</span><span class="s">"w"</span> <span class="s">"Work task"</span> <span class="nv">entry</span> <span class="p">(</span><span class="nv">file</span> <span class="nv">suv-org-work-file</span><span class="p">)</span>
         <span class="s">"* TODO %^{Type|TODO|DEP|BUG}-%^{Ticket number} - %^{Description}
  :PROPERTIES:
  :LINK:     https://helpshift.atlassian.net/browse/%\\1-%\\2
  :END:
  :LOGBOOK:\n  - Added - %U\n  :END:\n  "</span><span class="p">)</span>

        <span class="p">(</span><span class="s">"r"</span> <span class="s">"Reading list item"</span> <span class="nv">entry</span> <span class="p">(</span><span class="nv">file</span> <span class="nv">suv-org-reading-list-file</span><span class="p">)</span>
         <span class="s">"* TODO %^{Description}\n  :LOGBOOK:\n - Added: %U\n  :END:
  %(current-kill 0)\n  %?"</span><span class="p">)))</span>

<span class="c1">;; Show how you can know all of this from inside of Emacs. (`C-h v`)</span>

<span class="c1">;; Use `%c` instead of `%(current-kill 0)`</span>

<span class="c1">;;; org-capture-demo.el ends here</span></code></pre></figure>

<h2 id="conclusion">Conclusion</h2>

<p>Org capture is a great way of capturing information in a structured way with
minimal distraction from your workflow!</p>]]></content><author><name>Suvrat Apte</name></author><category term="emacs," /><category term="org-mode," /><category term="org-capture," /><category term="productivity" /><summary type="html"><![CDATA[This is a talk that I had given at an Emacs meetup hosted by Helpshift.]]></summary></entry><entry><title type="html">Consistent Hashing with Clojure</title><link href="https://suvratapte.com/consistent-hashing-with-clojure/" rel="alternate" type="text/html" title="Consistent Hashing with Clojure" /><published>2020-12-31T09:59:40+00:00</published><updated>2020-12-31T09:59:40+00:00</updated><id>https://suvratapte.com/consistent-hashing-with-clojure</id><content type="html" xml:base="https://suvratapte.com/consistent-hashing-with-clojure/"><![CDATA[<p>In this post, I have tried explaining what <em>Consistent Hashing</em> is, when it is
needed and how to implement it in Clojure. Consistent hashing has many use
cases. I have chosen the use case of distributed caching for this post.</p>

<h2 id="caching">Caching</h2>

<p>Almost all applications today use some kind of caching. Caches help reduce the number of
requests served by your database and improve latency. Initially, your application would
have one cache node sitting over your database. On read paths, it will be checked if data
is available on the cache node, if not, you would go to the database and populate the data
on your cache node. On write paths, you would first update the database and then your
cache. Or let the cached item expire with some TTL according to your consistency
requirements. With this setup, you are using your cache node as a superfast index to look
up hot items and absorb traffic that would have otherwise gone to your database.</p>

<p>But as your application usage grows, your cache node is also going to get
overwhelmed and soon enough, you will need multiple cache nodes. When you have
multiple nodes, you will need to decide how you are going to divide data between
those nodes.</p>

<h2 id="distributed-caching">Distributed Caching</h2>

<p>One very simple strategy to divide data between cache nodes is to take an
integer hash of the cache key and then take the mod by the number of cache
nodes.</p>

<!---excerpt-break-->

<p>For example, if the hash of the cache key came out to be 86696499 and if we have
4 servers, then <code class="language-plaintext highlighter-rouge">(86696499 mod 4) = 3</code>; so the data should be in the node with
index 3 (0 based indexes).</p>

<p>This is very simple to implement. For simplicity, we will use email addresses of
users as cache keys.</p>

<figure class="highlight"><pre><code class="language-clojure" data-lang="clojure"><span class="p">(</span><span class="nf">require</span><span class="w"> </span><span class="o">'</span><span class="p">[</span><span class="n">clojure.pprint</span><span class="w"> </span><span class="no">:as</span><span class="w"> </span><span class="n">pp</span><span class="p">])</span><span class="w">

</span><span class="p">(</span><span class="k">def</span><span class="w"> </span><span class="n">emails</span><span class="w"> </span><span class="p">[</span><span class="s">"Bob@example.com"</span><span class="w"> </span><span class="s">"Carry@example.com"</span><span class="w"> </span><span class="s">"Daisy@example.com"</span><span class="w">
             </span><span class="s">"George@example.com"</span><span class="w"> </span><span class="s">"Heidi@example.com"</span><span class="w"> </span><span class="s">"Mark@example.com"</span><span class="w">
             </span><span class="s">"Steve@example.com"</span><span class="w"> </span><span class="s">"Zack@example.com"</span><span class="p">])</span><span class="w">

</span><span class="p">(</span><span class="k">defn</span><span class="w"> </span><span class="n">get-node</span><span class="w">
  </span><span class="s">"Returns which node shall be used for the given `object` when `n`
  cache nodes are there."</span><span class="w">
  </span><span class="p">[</span><span class="n">n</span><span class="w"> </span><span class="n">object</span><span class="p">]</span><span class="w">
  </span><span class="p">(</span><span class="nb">-&gt;</span><span class="w"> </span><span class="n">object</span><span class="w"> </span><span class="n">hash</span><span class="w"> </span><span class="p">(</span><span class="nf">mod</span><span class="w"> </span><span class="n">n</span><span class="p">)))</span><span class="w">

</span><span class="p">(</span><span class="k">defn</span><span class="w"> </span><span class="n">get-distribution</span><span class="w">
  </span><span class="s">"Returns distribution of `objects` over `n` nodes."</span><span class="w">
  </span><span class="p">[</span><span class="n">n</span><span class="w"> </span><span class="n">objects</span><span class="p">]</span><span class="w">
  </span><span class="p">(</span><span class="nb">reduce</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="p">[</span><span class="n">acc</span><span class="w"> </span><span class="n">object</span><span class="p">]</span><span class="w">
            </span><span class="p">(</span><span class="k">let</span><span class="w"> </span><span class="p">[</span><span class="nb">node</span><span class="w"> </span><span class="p">(</span><span class="nf">get-node</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="n">object</span><span class="p">)]</span><span class="w">
              </span><span class="p">(</span><span class="nf">update</span><span class="w"> </span><span class="n">acc</span><span class="w">
                      </span><span class="p">(</span><span class="nb">str</span><span class="w"> </span><span class="s">"node-"</span><span class="w"> </span><span class="nb">node</span><span class="p">)</span><span class="w">
                      </span><span class="p">(</span><span class="nf">fnil</span><span class="w"> </span><span class="nb">conj</span><span class="w"> </span><span class="p">[])</span><span class="w">
                      </span><span class="n">object</span><span class="p">)))</span><span class="w">
          </span><span class="p">{}</span><span class="w">
          </span><span class="n">objects</span><span class="p">))</span><span class="w">

</span><span class="c1">;; For printing maps in sorted order of keys</span><span class="w">
</span><span class="p">(</span><span class="nf">-&gt;&gt;</span><span class="w"> </span><span class="n">emails</span><span class="w"> </span><span class="p">(</span><span class="nf">get-distribution</span><span class="w"> </span><span class="mi">4</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="nb">into</span><span class="w"> </span><span class="p">(</span><span class="nb">sorted-map</span><span class="p">))</span><span class="w"> </span><span class="n">pp/pprint</span><span class="p">)</span></code></pre></figure>

<p>Let’s go through the code above.</p>

<p><code class="language-plaintext highlighter-rouge">emails</code> is just a collection of emails.</p>

<p><code class="language-plaintext highlighter-rouge">get-node</code> tells us which object should go on which node. This was the logic
that we discussed previously. We are first taking a hash and then taking <code class="language-plaintext highlighter-rouge">mod n</code>
of that hash.</p>

<p><code class="language-plaintext highlighter-rouge">get-distribution</code> just runs <code class="language-plaintext highlighter-rouge">get-node</code> on <code class="language-plaintext highlighter-rouge">emails</code> and returns a map which has
node names as keys and corresponding values as list of keys which would reside
on those nodes.</p>

<p>The last line prints how <code class="language-plaintext highlighter-rouge">emails</code> will be divided on cache nodes if we had 4
cache nodes. It prints the following map:</p>

<figure class="highlight"><pre><code class="language-clojure" data-lang="clojure"><span class="p">{</span><span class="s">"node-0"</span><span class="w"> </span><span class="p">[</span><span class="s">"Bob@example.com"</span><span class="w"> </span><span class="s">"Steve@example.com"</span><span class="w"> </span><span class="s">"Zack@example.com"</span><span class="p">]</span><span class="n">,</span><span class="w">
 </span><span class="s">"node-1"</span><span class="w"> </span><span class="p">[</span><span class="s">"Carry@example.com"</span><span class="w"> </span><span class="s">"Daisy@example.com"</span><span class="w"> </span><span class="s">"George@example.com"</span><span class="p">]</span><span class="n">,</span><span class="w">
 </span><span class="s">"node-2"</span><span class="w"> </span><span class="p">[</span><span class="s">"Mark@example.com"</span><span class="p">]</span><span class="n">,</span><span class="w">
 </span><span class="s">"node-3"</span><span class="w"> </span><span class="p">[</span><span class="s">"Heidi@example.com"</span><span class="p">]}</span></code></pre></figure>

<p>Okay so this seems to be working well!  Now every time we have to fetch some
data, we will just check on which node that data is expected and then we will
try to fetch it from that node. So far so good!</p>

<p>So why do we need consistent hashing if mod n hashing is working well?</p>

<p>In today’s distributed infrastructure, the total number of cache nodes can
easily change. There could be multiple reasons such as, needing a few extra
nodes when more traffic is expected, or a node going down due to some error.</p>

<p>We can simulate the above 2 situations.</p>

<p>Let’s say we add another cache node in our cluster. We can simulate this by running:</p>

<figure class="highlight"><pre><code class="language-clojure" data-lang="clojure"><span class="p">(</span><span class="nf">-&gt;&gt;</span><span class="w"> </span><span class="n">emails</span><span class="w"> </span><span class="p">(</span><span class="nf">get-distribution</span><span class="w"> </span><span class="mi">5</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="nb">into</span><span class="w"> </span><span class="p">(</span><span class="nb">sorted-map</span><span class="p">))</span><span class="w"> </span><span class="n">pp/pprint</span><span class="p">)</span></code></pre></figure>

<p>We will get the following:</p>

<figure class="highlight"><pre><code class="language-clojure" data-lang="clojure"><span class="p">{</span><span class="s">"node-0"</span><span class="w"> </span><span class="p">[</span><span class="s">"Bob@example.com"</span><span class="p">]</span><span class="n">,</span><span class="w">
 </span><span class="s">"node-1"</span><span class="w"> </span><span class="p">[</span><span class="s">"Daisy@example.com"</span><span class="p">]</span><span class="n">,</span><span class="w">
 </span><span class="s">"node-2"</span><span class="w"> </span><span class="p">[</span><span class="s">"Steve@example.com"</span><span class="p">]</span><span class="n">,</span><span class="w">
 </span><span class="s">"node-3"</span><span class="w"> </span><span class="p">[</span><span class="s">"Carry@example.com"</span><span class="w"> </span><span class="s">"George@example.com"</span><span class="w"> </span><span class="s">"Mark@example.com"</span><span class="p">]</span><span class="n">,</span><span class="w">
 </span><span class="s">"node-4"</span><span class="w"> </span><span class="p">[</span><span class="s">"Heidi@example.com"</span><span class="w"> </span><span class="s">"Zack@example.com"</span><span class="p">]}</span></code></pre></figure>

<p>If we compare the distribution of keys for 4 nodes vs 5 nodes, we can see that
literally 6 out of 8 keys have different nodes now.</p>

<p>The same will happen if a node goes down. Let’s simulate this by running:</p>

<figure class="highlight"><pre><code class="language-clojure" data-lang="clojure"><span class="p">(</span><span class="nf">-&gt;&gt;</span><span class="w"> </span><span class="n">emails</span><span class="w"> </span><span class="p">(</span><span class="nf">get-distribution</span><span class="w"> </span><span class="mi">3</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="nb">into</span><span class="w"> </span><span class="p">(</span><span class="nb">sorted-map</span><span class="p">))</span><span class="w"> </span><span class="n">pp/pprint</span><span class="p">)</span></code></pre></figure>

<p>This produces:</p>

<figure class="highlight"><pre><code class="language-clojure" data-lang="clojure"><span class="p">{</span><span class="s">"node-0"</span><span class="w"> </span><span class="p">[</span><span class="s">"Zack@example.com"</span><span class="p">]</span><span class="n">,</span><span class="w">
 </span><span class="s">"node-1"</span><span class="w"> </span><span class="p">[</span><span class="s">"Bob@example.com"</span><span class="w"> </span><span class="s">"Daisy@example.com"</span><span class="w"> </span><span class="s">"George@example.com"</span><span class="p">]</span><span class="n">,</span><span class="w">
 </span><span class="s">"node-2"</span><span class="w"> </span><span class="p">[</span><span class="s">"Carry@example.com"</span><span class="w"> </span><span class="s">"Heidi@example.com"</span><span class="w"> </span><span class="s">"Mark@example.com"</span><span class="w"> </span><span class="s">"Steve@example.com"</span><span class="p">]}</span></code></pre></figure>

<p>In this case as well, 5 out of 8 keys now have a different node.</p>

<p>Both of these cases create a really bad situation for our databases. Our data is going to
be residing on 4 nodes initially. Once we add or remove nodes, almost all of the keys are
going to get relocated. This is going to result in a flurry of cache misses and all the
missed requests will go to our databases, creating a hotspot.</p>

<p>This is clearly undesirable and in extreme situations, this could even take our
entire system down.</p>

<p>Let’s understand why this is happening. We need to remember that our logic to
select nodes (<code class="language-plaintext highlighter-rouge">get-node</code>) for data includes <em>number of nodes</em> as a parameter. So
when our <em>number of nodes</em> changes, clearly the output of <code class="language-plaintext highlighter-rouge">get-node</code> is most
likely to change.</p>

<p>We need to find a strategy which will not directly depend on the <em>number of
nodes</em> that we have.</p>

<h2 id="consistent-hashing">Consistent Hashing</h2>

<p>Consistent hashing is a simple method of hashing which does not depend on the
number of nodes we have. In consistent hashing, we imagine our nodes to be
placed on a ring. The ring is made up of the range of our hash function. For
example, if our hash function produced hashes over the entire range of integers,
then the ring would go from the minimum integer to the maximum integer.</p>

<p>We will generate hashes for nodes using some unique property of nodes, say IP
addresses. These hashes will be the locations of our nodes on the ring.</p>

<p align="center">
<img src="/resources/consistent-hashing-ring.png" style="height: 55%; width: 55%;" />
</p>

<p>To insert or retrieve data, we will hash the caching key and use the node which
is closest to the caching key hash in the clockwise direction. (Clockwise is
just a convention we are using for this post. Anti-clockwise will also work.)</p>

<p align="center">
<img src="/resources/consistent-hashing-ring-key-hash.png" style="margin-left:19%; height: 75%; width: 75%;" />
</p>

<p>What benefit has this given us?</p>

<p>Well, so far it does not look like this is useful. In fact, we are doing more
work to find out which data goes to which node. We will now consider the 2 cases
that we discussed for mod n hashing.</p>

<p>Let’s say we add a 5<sup>th</sup> node to our ring.</p>

<p>If the 5<sup>th</sup> node got placed between the 1<sup>st</sup> and the
2<sup>nd</sup> node, think about which keys will get relocated. Only the keys
between 1<sup>st</sup> and 5<sup>th</sup> node will be relocated to the
5<sup>th</sup> node. All the keys on the rest of the ring will remain where they
were.</p>

<p align="center">
<img src="/resources/consistent-hashing-node-added.png" style="height: 60%; width: 60%;" />
</p>

<p>Similarly, if one of our nodes, say the 4<sup>th</sup> node, goes down; then
only the keys between the 3<sup>rd</sup> and 4<sup>th</sup> will get relocated.</p>

<p align="center">
<img src="/resources/consistent-hashing-node-removed.png" style="margin-right: 5%; height: 65%; width: 65%;" />
</p>

<p>When nodes are added or removed, only <code class="language-plaintext highlighter-rouge">count(keys) / count(nodes)</code> number of
keys will be relocated. This will reduce the number of cache misses by a huge
amount and save our databases from hotspots!
<br /><em>(There is a small caveat here which is discussed later.)</em></p>

<h2 id="implementation-in-clojure">Implementation in Clojure</h2>

<p>We will write a simple API for consistent hashing. This will include functions
to manage the ring: <code class="language-plaintext highlighter-rouge">create-ring</code>, <code class="language-plaintext highlighter-rouge">add-node</code>, <code class="language-plaintext highlighter-rouge">remove-node</code>. And like before,
we will have a <code class="language-plaintext highlighter-rouge">get-node</code> function.</p>

<p>Let’s look at <code class="language-plaintext highlighter-rouge">create-ring</code> first.</p>

<figure class="highlight"><pre><code class="language-clojure" data-lang="clojure"><span class="p">(</span><span class="k">defn</span><span class="w"> </span><span class="n">create-ring</span><span class="w">
  </span><span class="s">"Creates a ring for `nodes`.

  `nodes` should be a coll of property of nodes which should be used
  for placing the nodes on the ring.
  Returns a ring data structure. It is a map which looks like this:

  {:node-hashes &lt;a list containing hashes of `nodes` (order is preserved) &gt;

   :hash-&gt;node &lt;a map which is a look up table which gives node descriptor
                given a hash to a hash&gt; }

  The return value of this function should be preserved by the caller as it is
  required as input to other functions in this API.
  "</span><span class="w">
  </span><span class="p">[</span><span class="n">nodes</span><span class="p">]</span><span class="w">
  </span><span class="p">(</span><span class="k">let</span><span class="w"> </span><span class="p">[</span><span class="n">nodes</span><span class="w"> </span><span class="p">(</span><span class="nb">set</span><span class="w"> </span><span class="n">nodes</span><span class="p">)</span><span class="w">
        </span><span class="n">node-hashes</span><span class="w"> </span><span class="p">(</span><span class="nf">-&gt;&gt;</span><span class="w"> </span><span class="n">nodes</span><span class="w">
                         </span><span class="p">(</span><span class="nb">map</span><span class="w"> </span><span class="n">hash</span><span class="p">)</span><span class="w">
                         </span><span class="nb">sort</span><span class="p">)</span><span class="w">
        </span><span class="n">hash-&gt;node</span><span class="w"> </span><span class="p">(</span><span class="nb">reduce</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="p">[</span><span class="n">acc</span><span class="w"> </span><span class="nb">node</span><span class="p">]</span><span class="w">
                             </span><span class="p">(</span><span class="nb">assoc</span><span class="w"> </span><span class="n">acc</span><span class="w">
                                    </span><span class="p">(</span><span class="nf">hash</span><span class="w"> </span><span class="nb">node</span><span class="p">)</span><span class="w">
                                    </span><span class="nb">node</span><span class="p">))</span><span class="w">
                           </span><span class="p">{}</span><span class="w">
                           </span><span class="n">nodes</span><span class="p">)]</span><span class="w">
    </span><span class="p">{</span><span class="no">:node-hashes</span><span class="w"> </span><span class="n">node-hashes</span><span class="w">
     </span><span class="no">:hash-&gt;node</span><span class="w"> </span><span class="n">hash-&gt;node</span><span class="p">}))</span></code></pre></figure>

<p>We are taking the <code class="language-plaintext highlighter-rouge">set</code> of nodes to make sure there are no duplicate
entries. Then we get the hash values for all the nodes and sort them in
ascending order. This sorted list will be used to find the closest node in the
ring. We also create a lookup table <code class="language-plaintext highlighter-rouge">hash-&gt;node</code> which gives us the node
corresponding to a given hash. Finally, we return both of these so that they can
be passed to other functions in our API.</p>

<p>Let’s see how <code class="language-plaintext highlighter-rouge">add-node</code> and <code class="language-plaintext highlighter-rouge">remove-node</code> work.</p>

<figure class="highlight"><pre><code class="language-clojure" data-lang="clojure"><span class="p">(</span><span class="k">defn</span><span class="w"> </span><span class="n">add-node</span><span class="w">
  </span><span class="s">"Adds `node` to existing `ring`.

  `ring` is expected to be a ring data structure (see doc string of
  `create-ring`.)

  `node` is expected to be a node descriptor (see doc string of `create-ring`).

  Returns a ring data structure (see doc string of `create-ring`).
  "</span><span class="w">
  </span><span class="p">[</span><span class="n">ring</span><span class="w"> </span><span class="nb">node</span><span class="p">]</span><span class="w">
  </span><span class="p">(</span><span class="k">let</span><span class="w"> </span><span class="p">[</span><span class="n">current-nodes</span><span class="w"> </span><span class="p">(</span><span class="nb">-&gt;</span><span class="w"> </span><span class="n">ring</span><span class="w"> </span><span class="no">:hash-&gt;node</span><span class="w"> </span><span class="nb">vals</span><span class="p">)]</span><span class="w">
    </span><span class="p">(</span><span class="nb">-&gt;</span><span class="w"> </span><span class="n">current-nodes</span><span class="w">
        </span><span class="p">(</span><span class="nb">conj</span><span class="w"> </span><span class="nb">node</span><span class="p">)</span><span class="w">
        </span><span class="n">create-ring</span><span class="p">)))</span><span class="w">

</span><span class="p">(</span><span class="k">defn</span><span class="w"> </span><span class="n">remove-node</span><span class="w">
  </span><span class="s">"Removes `node` from existing `ring`.

  `ring` is expected to be a ring data structure (see doc string of
  `create-ring`.)

  `node` is expected to be a node descriptor (see doc string of `create-ring`).

  Returns a ring data structure (see doc string of `create-ring`).
  "</span><span class="w">
  </span><span class="p">[</span><span class="n">ring</span><span class="w"> </span><span class="nb">node</span><span class="p">]</span><span class="w">
  </span><span class="p">(</span><span class="k">let</span><span class="w"> </span><span class="p">[</span><span class="n">current-nodes</span><span class="w"> </span><span class="p">(</span><span class="nb">-&gt;</span><span class="w"> </span><span class="n">ring</span><span class="w"> </span><span class="no">:hash-&gt;node</span><span class="w"> </span><span class="nb">vals</span><span class="p">)]</span><span class="w">
    </span><span class="p">(</span><span class="nf">-&gt;&gt;</span><span class="w"> </span><span class="n">current-nodes</span><span class="w">
         </span><span class="p">(</span><span class="nb">remove</span><span class="w"> </span><span class="o">#</span><span class="p">(</span><span class="nb">=</span><span class="w"> </span><span class="n">%</span><span class="w"> </span><span class="nb">node</span><span class="p">))</span><span class="w">
         </span><span class="n">create-ring</span><span class="p">)))</span></code></pre></figure>

<p>As you can see, these are very simple functions which just get <code class="language-plaintext highlighter-rouge">current-nodes</code> from the
<code class="language-plaintext highlighter-rouge">ring</code> and then add or remove a node and call <code class="language-plaintext highlighter-rouge">create-ring</code> again. This works
because our hash function is repeatable. So creating the ring again generates the same
hash values for existing nodes.</p>

<p>Let’s look at the last function in our API, <code class="language-plaintext highlighter-rouge">get-node</code>.</p>

<figure class="highlight"><pre><code class="language-clojure" data-lang="clojure"><span class="p">(</span><span class="k">defn</span><span class="w"> </span><span class="n">get-node</span><span class="w">
  </span><span class="s">"Returns node to be used for cache-key `k`."</span><span class="w">
  </span><span class="p">[</span><span class="n">ring</span><span class="w"> </span><span class="n">k</span><span class="p">]</span><span class="w">
  </span><span class="p">(</span><span class="k">let</span><span class="w"> </span><span class="p">[</span><span class="n">node-hashes</span><span class="w"> </span><span class="p">(</span><span class="no">:node-hashes</span><span class="w"> </span><span class="n">ring</span><span class="p">)</span><span class="w">
        </span><span class="n">key-hash</span><span class="w"> </span><span class="p">(</span><span class="nf">hash</span><span class="w"> </span><span class="n">k</span><span class="p">)</span><span class="w">
        </span><span class="n">closest-hash</span><span class="w"> </span><span class="p">(</span><span class="nb">or</span><span class="w"> </span><span class="p">(</span><span class="nf">-&gt;&gt;</span><span class="w"> </span><span class="n">node-hashes</span><span class="w">
                              </span><span class="p">(</span><span class="nb">drop-while</span><span class="w"> </span><span class="o">#</span><span class="p">(</span><span class="nb">&lt;</span><span class="w"> </span><span class="n">%</span><span class="w"> </span><span class="n">key-hash</span><span class="p">))</span><span class="w">
                              </span><span class="nb">first</span><span class="p">)</span><span class="w">
                         </span><span class="p">(</span><span class="nb">first</span><span class="w"> </span><span class="n">node-hashes</span><span class="p">))]</span><span class="w">
    </span><span class="p">(</span><span class="nb">get</span><span class="w"> </span><span class="p">(</span><span class="no">:hash-&gt;node</span><span class="w"> </span><span class="n">ring</span><span class="p">)</span><span class="w"> </span><span class="n">closest-hash</span><span class="p">)))</span></code></pre></figure>

<p>The main logic in this function is to find the closest node to the cache-key, in
clockwise direction.</p>

<figure class="highlight"><pre><code class="language-clojure" data-lang="clojure"><span class="p">(</span><span class="nb">or</span><span class="w"> </span><span class="p">(</span><span class="nf">-&gt;&gt;</span><span class="w"> </span><span class="n">node-hashes</span><span class="w">
         </span><span class="p">(</span><span class="nb">drop-while</span><span class="w"> </span><span class="o">#</span><span class="p">(</span><span class="nb">&lt;</span><span class="w"> </span><span class="n">%</span><span class="w"> </span><span class="n">key-hash</span><span class="p">))</span><span class="w">
         </span><span class="nb">first</span><span class="p">)</span><span class="w">
    </span><span class="p">(</span><span class="nb">first</span><span class="w"> </span><span class="n">node-hashes</span><span class="p">))</span></code></pre></figure>

<p><code class="language-plaintext highlighter-rouge">node-hashes</code> is the sorted list of hashes of our nodes. We are dropping the
nodes which have hashes lesser than the hash of the cache-key. We will stop
dropping once we find a value greater than <code class="language-plaintext highlighter-rouge">key-hash</code>. This value will be the
hash of the closest node in clockwise direction. If <code class="language-plaintext highlighter-rouge">key-hash</code> is greater then
all the values in <code class="language-plaintext highlighter-rouge">node-hashes</code>, we wrap around and select <code class="language-plaintext highlighter-rouge">(first
node-hashes)</code>. For simplicity, I have used sequential search for finding the
closest hash. Binary search could be used for making this more effecient.</p>

<p>Now our API for consistent hashing is complete and ready for use!</p>

<p>Let’s use it for the same example scenarios that we used for mod n hashing.</p>

<figure class="highlight"><pre><code class="language-clojure" data-lang="clojure"><span class="p">(</span><span class="nf">require</span><span class="w"> </span><span class="o">'</span><span class="p">[</span><span class="n">clojure.pprint</span><span class="w"> </span><span class="no">:as</span><span class="w"> </span><span class="n">pp</span><span class="p">])</span><span class="w">

</span><span class="p">(</span><span class="k">def</span><span class="w"> </span><span class="n">emails</span><span class="w"> </span><span class="p">[</span><span class="s">"Bob@example.com"</span><span class="w"> </span><span class="s">"Carry@example.com"</span><span class="w"> </span><span class="s">"Daisy@example.com"</span><span class="w">
             </span><span class="s">"George@example.com"</span><span class="w"> </span><span class="s">"Heidi@example.com"</span><span class="w"> </span><span class="s">"Mark@example.com"</span><span class="w">
             </span><span class="s">"Steve@example.com"</span><span class="w"> </span><span class="s">"Zack@example.com"</span><span class="p">])</span><span class="w">

</span><span class="p">(</span><span class="k">def</span><span class="w"> </span><span class="n">nodes</span><span class="w"> </span><span class="p">[</span><span class="s">"node-0"</span><span class="w"> </span><span class="s">"node-1"</span><span class="w"> </span><span class="s">"node-2"</span><span class="w"> </span><span class="s">"node-3"</span><span class="p">])</span><span class="w">

</span><span class="p">(</span><span class="k">defn</span><span class="w"> </span><span class="n">get-distribution</span><span class="w">
  </span><span class="p">[</span><span class="n">nodes</span><span class="w"> </span><span class="n">objects</span><span class="p">]</span><span class="w">
  </span><span class="p">(</span><span class="k">let</span><span class="w"> </span><span class="p">[</span><span class="n">ring</span><span class="w"> </span><span class="p">(</span><span class="nf">create-ring</span><span class="w"> </span><span class="n">nodes</span><span class="p">)]</span><span class="w">
    </span><span class="p">(</span><span class="nb">reduce</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="p">[</span><span class="n">acc</span><span class="w"> </span><span class="n">object</span><span class="p">]</span><span class="w">
              </span><span class="p">(</span><span class="k">let</span><span class="w"> </span><span class="p">[</span><span class="nb">node</span><span class="w"> </span><span class="p">(</span><span class="nf">get-node</span><span class="w"> </span><span class="n">ring</span><span class="w"> </span><span class="n">object</span><span class="p">)]</span><span class="w">
                </span><span class="p">(</span><span class="nf">update</span><span class="w"> </span><span class="n">acc</span><span class="w">
                        </span><span class="nb">node</span><span class="w">
                        </span><span class="p">(</span><span class="nf">fnil</span><span class="w"> </span><span class="nb">conj</span><span class="w"> </span><span class="p">[])</span><span class="w">
                        </span><span class="n">object</span><span class="p">)))</span><span class="w">
            </span><span class="p">{}</span><span class="w">
            </span><span class="n">objects</span><span class="p">)))</span><span class="w">

</span><span class="c1">;; For printing maps in sorted order of keys</span><span class="w">
</span><span class="p">(</span><span class="nf">-&gt;&gt;</span><span class="w"> </span><span class="n">emails</span><span class="w"> </span><span class="p">(</span><span class="nf">get-distribution</span><span class="w"> </span><span class="n">nodes</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="nb">into</span><span class="w"> </span><span class="p">(</span><span class="nb">sorted-map</span><span class="p">))</span><span class="w"> </span><span class="n">pp/pprint</span><span class="p">)</span></code></pre></figure>

<p>Result with 4 nodes:</p>

<figure class="highlight"><pre><code class="language-clojure" data-lang="clojure"><span class="p">{</span><span class="s">"node-0"</span><span class="w"> </span><span class="p">[</span><span class="s">"Daisy@example.com"</span><span class="w"> </span><span class="s">"George@example.com"</span><span class="p">]</span><span class="n">,</span><span class="w">
 </span><span class="s">"node-1"</span><span class="w"> </span><span class="p">[</span><span class="s">"Mark@example.com"</span><span class="w"> </span><span class="s">"Zack@example.com"</span><span class="p">]</span><span class="n">,</span><span class="w">
 </span><span class="s">"node-2"</span><span class="w"> </span><span class="p">[</span><span class="s">"Bob@example.com"</span><span class="w"> </span><span class="s">"Heidi@example.com"</span><span class="p">]</span><span class="n">,</span><span class="w">
 </span><span class="s">"node-3"</span><span class="w"> </span><span class="p">[</span><span class="s">"Carry@example.com"</span><span class="w"> </span><span class="s">"Steve@example.com"</span><span class="p">]}</span></code></pre></figure>

<p>With a node added:</p>

<figure class="highlight"><pre><code class="language-clojure" data-lang="clojure"><span class="p">(</span><span class="nf">-&gt;&gt;</span><span class="w"> </span><span class="n">emails</span><span class="w"> </span><span class="p">(</span><span class="nf">get-distribution</span><span class="w"> </span><span class="p">(</span><span class="nb">conj</span><span class="w"> </span><span class="n">nodes</span><span class="w"> </span><span class="s">"node-4"</span><span class="p">))</span><span class="w"> </span><span class="p">(</span><span class="nb">into</span><span class="w"> </span><span class="p">(</span><span class="nb">sorted-map</span><span class="p">))</span><span class="w"> </span><span class="n">pp/pprint</span><span class="p">)</span><span class="w">

</span><span class="p">{</span><span class="s">"node-0"</span><span class="w"> </span><span class="p">[</span><span class="s">"Daisy@example.com"</span><span class="w"> </span><span class="s">"George@example.com"</span><span class="p">]</span><span class="n">,</span><span class="w">
 </span><span class="s">"node-1"</span><span class="w"> </span><span class="p">[</span><span class="s">"Mark@example.com"</span><span class="w"> </span><span class="s">"Zack@example.com"</span><span class="p">]</span><span class="n">,</span><span class="w">
 </span><span class="s">"node-2"</span><span class="w"> </span><span class="p">[</span><span class="s">"Heidi@example.com"</span><span class="p">]</span><span class="n">,</span><span class="w">
 </span><span class="s">"node-3"</span><span class="w"> </span><span class="p">[</span><span class="s">"Carry@example.com"</span><span class="w"> </span><span class="s">"Steve@example.com"</span><span class="p">]</span><span class="n">,</span><span class="w">
 </span><span class="s">"node-4"</span><span class="w"> </span><span class="p">[</span><span class="s">"Bob@example.com"</span><span class="p">]}</span></code></pre></figure>

<p>Only 1 out of 8 keys got relocated!</p>

<p>With <code class="language-plaintext highlighter-rouge">node-3</code> removed:</p>

<figure class="highlight"><pre><code class="language-clojure" data-lang="clojure"><span class="p">(</span><span class="nf">-&gt;&gt;</span><span class="w"> </span><span class="n">emails</span><span class="w"> </span><span class="p">(</span><span class="nf">get-distribution</span><span class="w"> </span><span class="p">(</span><span class="nf">drop-last</span><span class="w"> </span><span class="n">nodes</span><span class="p">))</span><span class="w"> </span><span class="p">(</span><span class="nb">into</span><span class="w"> </span><span class="p">(</span><span class="nb">sorted-map</span><span class="p">))</span><span class="w"> </span><span class="n">pp/pprint</span><span class="p">)</span><span class="w">

</span><span class="p">{</span><span class="s">"node-0"</span><span class="w"> </span><span class="p">[</span><span class="s">"Daisy@example.com"</span><span class="w"> </span><span class="s">"George@example.com"</span><span class="p">]</span><span class="n">,</span><span class="w">
 </span><span class="s">"node-1"</span><span class="w"> </span><span class="p">[</span><span class="s">"Mark@example.com"</span><span class="w"> </span><span class="s">"Zack@example.com"</span><span class="p">]</span><span class="n">,</span><span class="w">
 </span><span class="s">"node-2"</span><span class="w"> </span><span class="p">[</span><span class="s">"Bob@example.com"</span><span class="w"> </span><span class="s">"Carry@example.com"</span><span class="w"> </span><span class="s">"Heidi@example.com"</span><span class="w"> </span><span class="s">"Steve@example.com"</span><span class="p">]}</span></code></pre></figure>

<p>Only 2 out of 8 keys got relocated. We can see that <code class="language-plaintext highlighter-rouge">node-3</code> keys are now with
<code class="language-plaintext highlighter-rouge">node-2</code>. Keys with <code class="language-plaintext highlighter-rouge">node-0</code> and <code class="language-plaintext highlighter-rouge">node-1</code> have not changed at all.</p>

<h2 id="caveats">Caveats</h2>

<p>Our implementation above is not something that can be used in production. The
problem is that when we have only a few nodes, we could land up in a situation
like this:</p>

<p align="center">
<img src="/resources/consistent-hashing-caveat.png" style="height: 55%; width: 55%;" />
</p>

<p>In the above situation, most of the keys will go to <code class="language-plaintext highlighter-rouge">Node 1</code>.</p>

<p>The solution is simple. Instead of having just one hash per node, we could have
multiple hashes which map to the same node. This will ensure more randomness and
a better distribution of keys. It will look like this:</p>

<p align="center">
<img src="/resources/consistent-hashing-caveat-solution.png" style="height: 68%; width: 68%;" />
</p>

<h2 id="conclusion">Conclusion</h2>

<ul>
  <li>
    <p>Consistent hashing is a simple and great caching strategy to make sure your
databases are protected from hotspot in a distributed environment.</p>
  </li>
  <li>
    <p>Consistent hashing is able to achieve this by getting rid of <code class="language-plaintext highlighter-rouge">number of nodes</code>
as a parameter to hashing.</p>
  </li>
  <li>
    <p>When nodes are added or removed, only <code class="language-plaintext highlighter-rouge">count(keys) / count(nodes)</code> number of
keys will be relocated.</p>
  </li>
  <li>
    <p>Many in-memory datastores today use consistent hashing.</p>
  </li>
</ul>]]></content><author><name>Suvrat Apte</name></author><category term="consistent-hashing," /><category term="distributed-caches," /><category term="clojure" /><summary type="html"><![CDATA[In this post, I have tried explaining what Consistent Hashing is, when it is needed and how to implement it in Clojure. Consistent hashing has many use cases. I have chosen the use case of distributed caching for this post. Caching Almost all applications today use some kind of caching. Caches help reduce the number of requests served by your database and improve latency. Initially, your application would have one cache node sitting over your database. On read paths, it will be checked if data is available on the cache node, if not, you would go to the database and populate the data on your cache node. On write paths, you would first update the database and then your cache. Or let the cached item expire with some TTL according to your consistency requirements. With this setup, you are using your cache node as a superfast index to look up hot items and absorb traffic that would have otherwise gone to your database. But as your application usage grows, your cache node is also going to get overwhelmed and soon enough, you will need multiple cache nodes. When you have multiple nodes, you will need to decide how you are going to divide data between those nodes. Distributed Caching One very simple strategy to divide data between cache nodes is to take an integer hash of the cache key and then take the mod by the number of cache nodes.]]></summary></entry><entry><title type="html">nREPL Middleware</title><link href="https://suvratapte.com/nREPL-middleware/" rel="alternate" type="text/html" title="nREPL Middleware" /><published>2020-08-20T17:31:40+00:00</published><updated>2020-08-20T17:31:40+00:00</updated><id>https://suvratapte.com/nREPL-middleware</id><content type="html" xml:base="https://suvratapte.com/nREPL-middleware/"><![CDATA[<p>In this post, I have tried to cover what <a href="https://nrepl.org/" target="_blank">nREPL</a> is, what <em>nREPL Middleware</em> are and why we need them. We will
also look at the middleware provided by <a href="https://github.com/clojure-emacs/cider-nrepl" target="_blank"><code class="language-plaintext highlighter-rouge">cider-nrepl</code></a> and in the end, we will write our own custom middleware.</p>

<p>If you write Clojure, you are most probably using nREPL as that is the most popular REPL
out there. But it is not the only REPL out there.</p>

<h2 id="the-clojure-repl">The Clojure REPL</h2>

<p>Clojure itself has its own REPL. To start the default Clojure REPL, just run the <code class="language-plaintext highlighter-rouge">clojure</code> on
your terminal. You will see a REPL prompt. This is the default Clojure REPL.
<br />Try <code class="language-plaintext highlighter-rouge">(println "Hello, world!")</code> and you will see it works just like any other REPL.</p>

<p>But there are a few problems with this REPL. It does not support some basic features like
autocompletion or line editing (visiting previously typed text with up arrow)</p>

<blockquote>
  <p>Line editing will work if you use the <code class="language-plaintext highlighter-rouge">clj</code> command, but it is just a wrapper over
<code class="language-plaintext highlighter-rouge">clojure</code> with <code class="language-plaintext highlighter-rouge">rlwrap</code>.</p>
</blockquote>

<p>If you read <code class="language-plaintext highlighter-rouge">man clojure</code>, you will also notice that there is no easy way to start this
REPL on a socket. So if you are using this REPL, you cannot connect to it from remote machines.</p>

<p>So the default REPL clearly cannot be used as your daily development REPL. That is where
the need for other types of REPLs comes in.</p>

<h2 id="nrepl">nREPL</h2>

<p>Network REPL (nREPL) is a huge improvement over the default Clojure REPL. nREPL has a
client server design. As the name suggests, an nREPL server can be started on a socket so
that remote clients can connect to it. It also gives you support for autocompletion,
symbol lookups and many more things.</p>

<!---excerpt-break-->

<p>If you use Emacs, you can see the communication between the client and the server by
executing the following Elisp code:</p>

<figure class="highlight"><pre><code class="language-elisp" data-lang="elisp"><span class="p">(</span><span class="k">setq</span> <span class="nv">nrepl-log-messages</span> <span class="no">t</span><span class="p">)</span></code></pre></figure>

<blockquote>
  <p>If you don’t know how to run the above code, just press <code class="language-plaintext highlighter-rouge">M-:</code> (which runs
<code class="language-plaintext highlighter-rouge">eval-expression</code>) in any buffer, paste the above code in the input minibuffer and press
<code class="language-plaintext highlighter-rouge">RET</code>.</p>
</blockquote>

<p>This will tell the nREPL client in Emacs to log the messages passed between the client and
the server. Now run <code class="language-plaintext highlighter-rouge">(println "Hello, world!")</code> in the REPL and then switch to the buffer
with this name:</p>

<p><code class="language-plaintext highlighter-rouge">*nrepl-messages &lt;projectname&gt;:&lt;host&gt;:&lt;port&gt;*</code></p>

<p>This buffer lists all the messages sent by the client and the replies sent by the
server.  <br />When we executed <code class="language-plaintext highlighter-rouge">(println "Hello, world!")</code>, the
client sent this message:</p>

<figure class="highlight"><pre><code class="language-clojure" data-lang="clojure"><span class="p">(</span><span class="nf">--&gt;</span><span class="w">
  </span><span class="n">id</span><span class="w">                                 </span><span class="s">"9"</span><span class="w">
  </span><span class="n">op</span><span class="w">                                 </span><span class="s">"eval"</span><span class="w">
  </span><span class="n">session</span><span class="w">                            </span><span class="s">"ed9decc8-200a-4a80-aec7-025050a8ff4b"</span><span class="w">
  </span><span class="n">time-stamp</span><span class="w">                         </span><span class="s">"2020-07-31 20:09:42.624467000"</span><span class="w">
  </span><span class="n">code</span><span class="w">                               </span><span class="s">"(println \"Hello, world!\")"</span><span class="w">
  </span><span class="n">column</span><span class="w">                             </span><span class="mi">1</span><span class="w">
  </span><span class="n">file</span><span class="w">                               </span><span class="s">"*cider-repl workspace/cider-nrepl:localhost:57021(clj)*"</span><span class="w">
  </span><span class="n">line</span><span class="w">                               </span><span class="mi">2</span><span class="w">
  </span><span class="n">nrepl.middleware.print/buffer-size</span><span class="w"> </span><span class="mi">4096</span><span class="w">
  </span><span class="n">nrepl.middleware.print/options</span><span class="w">     </span><span class="p">(</span><span class="nf">dict</span><span class="w"> </span><span class="n">...</span><span class="p">)</span><span class="w">
  </span><span class="n">nrepl.middleware.print/print</span><span class="w">       </span><span class="s">"cider.nrepl.pprint/pprint"</span><span class="w">
  </span><span class="n">nrepl.middleware.print/quota</span><span class="w">       </span><span class="mi">1048576</span><span class="w">
  </span><span class="n">nrepl.middleware.print/stream?</span><span class="w">     </span><span class="s">"1"</span><span class="w">
  </span><span class="n">ns</span><span class="w">                                 </span><span class="s">"user"</span><span class="w">
</span><span class="p">)</span></code></pre></figure>

<blockquote>
  <p>Messages starting with <code class="language-plaintext highlighter-rouge">--&gt;</code> are requests from client. And those starting with
<code class="language-plaintext highlighter-rouge">&lt;--</code> are replies from server. <br />
The messages buffer will contain some other messages as well. But we will focus on the
messages that I’ve mentioned here.</p>
</blockquote>

<p>So what does this tell us?</p>

<p>The most important field in any message sent by the client is the <code class="language-plaintext highlighter-rouge">op</code> field. This field
tells the server what operation is to be performed. Depending on the <code class="language-plaintext highlighter-rouge">op</code>, there will be
other fields that that particular <code class="language-plaintext highlighter-rouge">op</code> depends on.</p>

<p>In the above message, the <code class="language-plaintext highlighter-rouge">op</code> is <code class="language-plaintext highlighter-rouge">eval</code>. From <code class="language-plaintext highlighter-rouge">eval</code>, the server understands that it has
to evaluate some code. It expects the client to send the code to be evaluated in <code class="language-plaintext highlighter-rouge">code</code>
field. You can see that the <code class="language-plaintext highlighter-rouge">code</code> field contains the code which we had run: <code class="language-plaintext highlighter-rouge">"(println \"Hello, world!\")"</code>.</p>

<p>The <code class="language-plaintext highlighter-rouge">session</code> field represents the ID of the current session. Every client has a separate
session ID with the server so that the server can identify multiple clients
separately. The <code class="language-plaintext highlighter-rouge">id</code> field is the ID of the request. Every request has a separate ID. The
server uses the same <code class="language-plaintext highlighter-rouge">id</code> in its replies so that clients can map requests and replies. So
to look at the replies from server, let’s use the <code class="language-plaintext highlighter-rouge">id</code> field (at your end, <code class="language-plaintext highlighter-rouge">id</code> will most
probably be a different number). Here are the replies from the server:</p>

<figure class="highlight"><pre><code class="language-clojure" data-lang="clojure"><span class="p">(</span><span class="nf">&lt;--</span><span class="w">
  </span><span class="n">id</span><span class="w">         </span><span class="s">"9"</span><span class="w">
  </span><span class="n">session</span><span class="w">    </span><span class="s">"ed9decc8-200a-4a80-aec7-025050a8ff4b"</span><span class="w">
  </span><span class="n">time-stamp</span><span class="w"> </span><span class="s">"2020-07-31 20:09:43.156831000"</span><span class="w">
  </span><span class="n">out</span><span class="w">        </span><span class="s">"Hello, world!"</span><span class="w">
</span><span class="p">)</span><span class="w">
</span><span class="p">(</span><span class="nf">&lt;--</span><span class="w">
  </span><span class="n">id</span><span class="w">         </span><span class="s">"9"</span><span class="w">
  </span><span class="n">session</span><span class="w">    </span><span class="s">"ed9decc8-200a-4a80-aec7-025050a8ff4b"</span><span class="w">
  </span><span class="n">time-stamp</span><span class="w"> </span><span class="s">"2020-07-31 20:09:43.184731000"</span><span class="w">
  </span><span class="n">value</span><span class="w">      </span><span class="s">"nil"</span><span class="w">
</span><span class="p">)</span></code></pre></figure>

<blockquote>
  <p>There will be another 3 messages with the same <code class="language-plaintext highlighter-rouge">id</code>, but those are not important for
this discussion.</p>
</blockquote>

<p>The first message tells the client that <code class="language-plaintext highlighter-rouge">"Hello, world!"</code> is printed on <code class="language-plaintext highlighter-rouge">out</code>
(<code class="language-plaintext highlighter-rouge">stdout</code>). The second message tells that the return value of the executed expression was
<code class="language-plaintext highlighter-rouge">nil</code> (<code class="language-plaintext highlighter-rouge">println</code> returns <code class="language-plaintext highlighter-rouge">nil</code>).</p>

<p>This feature of being able to look at client server communication comes in handy at times.</p>

<p>Now that we have looked at basics of client server communication, we can jump to the
biggest feature that nREPL provides - support for custom <em>middleware</em>.</p>

<h2 id="nrepl-middleware">nREPL Middleware</h2>

<p>nREPL Middleware gives you the ability to add your own middleware to support your own
operations. What this essentially means is that you can write code (which will run on the
server side) which can read requests from clients and then send appropriate responses.</p>

<p>So for example, if you wanted nREPL to show you <a href="https://clojuredocs.org/" target="_blank">ClojureDocs</a>, you could write your own operation, say <code class="language-plaintext highlighter-rouge">clojure-docs</code>,
which would take a <code class="language-plaintext highlighter-rouge">symbol</code> to be searched, as input (in the client message) and return
the doc in the server reply.</p>

<p>This is exactly how <a href="https://github.com/clojure-emacs/cider-nrepl" target="_blank"><code class="language-plaintext highlighter-rouge">cider-nrepl</code></a> adds a whole lot of functionality to
nREPL. <code class="language-plaintext highlighter-rouge">cider-nrepl</code> is a collection of middleware.</p>

<h3 id="cider-nrepl">CIDER nREPL</h3>

<p>If you are using <code class="language-plaintext highlighter-rouge">cider</code> in Emacs, you are already using the <code class="language-plaintext highlighter-rouge">cider-nrepl</code> middleware.
Let’s dig deeper into an operation provided by <code class="language-plaintext highlighter-rouge">cider-nrepl</code> - <em>autocomplete</em>.</p>

<p>If you type <code class="language-plaintext highlighter-rouge">print</code>, you will see autocompletions similar to this:</p>

<p align="center">
<img src="/resources/nREPL--autocompletion.jpg" />
</p>

<p>Let’s look at the messages for this. To get completions for <code class="language-plaintext highlighter-rouge">print</code>, the client sends this message:</p>

<figure class="highlight"><pre><code class="language-clojure" data-lang="clojure"><span class="p">(</span><span class="nf">--&gt;</span><span class="w">
  </span><span class="n">id</span><span class="w">                        </span><span class="s">"58"</span><span class="w">
  </span><span class="n">op</span><span class="w">                        </span><span class="s">"complete"</span><span class="w">
  </span><span class="n">session</span><span class="w">                   </span><span class="s">"ed9decc8-200a-4a80-aec7-025050a8ff4b"</span><span class="w">
  </span><span class="n">time-stamp</span><span class="w">                </span><span class="s">"2020-07-31 22:31:59.822565000"</span><span class="w">
  </span><span class="n">context</span><span class="w">                   </span><span class="s">":same"</span><span class="w">
  </span><span class="n">enhanced-cljs-completion?</span><span class="w"> </span><span class="s">"t"</span><span class="w">
  </span><span class="n">ns</span><span class="w">                        </span><span class="s">"user"</span><span class="w">
  </span><span class="n">prefix</span><span class="w">                    </span><span class="s">"print"</span><span class="w">
</span><span class="p">)</span></code></pre></figure>

<p>The <code class="language-plaintext highlighter-rouge">op</code> is <code class="language-plaintext highlighter-rouge">complete</code>, and <code class="language-plaintext highlighter-rouge">op</code> specific keys are <code class="language-plaintext highlighter-rouge">prefix</code> and <code class="language-plaintext highlighter-rouge">ns</code>. <code class="language-plaintext highlighter-rouge">prefix</code> is the text
to be completed and <code class="language-plaintext highlighter-rouge">ns</code> is the current namespace in the REPL. This is important because
completions are depedent on the current namespace.</p>

<p>Here is the message from the server:</p>

<figure class="highlight"><pre><code class="language-clojure" data-lang="clojure"><span class="p">(</span><span class="nf">&lt;--</span><span class="w">
  </span><span class="n">id</span><span class="w">          </span><span class="s">"58"</span><span class="w">
  </span><span class="n">session</span><span class="w">     </span><span class="s">"ed9decc8-200a-4a80-aec7-025050a8ff4b"</span><span class="w">
  </span><span class="n">time-stamp</span><span class="w">  </span><span class="s">"2020-07-31 22:31:59.826961000"</span><span class="w">
  </span><span class="n">completions</span><span class="w"> </span><span class="p">((</span><span class="nf">dict</span><span class="w"> </span><span class="s">"candidate"</span><span class="w"> </span><span class="s">"print"</span><span class="w"> </span><span class="s">"ns"</span><span class="w"> </span><span class="s">"clojure.core"</span><span class="w"> </span><span class="s">"type"</span><span class="w"> </span><span class="s">"function"</span><span class="p">)</span><span class="w">
 </span><span class="p">(</span><span class="nf">dict</span><span class="w"> </span><span class="s">"candidate"</span><span class="w"> </span><span class="s">"printf"</span><span class="w"> </span><span class="s">"ns"</span><span class="w"> </span><span class="s">"clojure.core"</span><span class="w"> </span><span class="s">"type"</span><span class="w"> </span><span class="s">"function"</span><span class="p">)</span><span class="w">
 </span><span class="p">(</span><span class="nf">dict</span><span class="w"> </span><span class="s">"candidate"</span><span class="w"> </span><span class="s">"println"</span><span class="w"> </span><span class="s">"ns"</span><span class="w"> </span><span class="s">"clojure.core"</span><span class="w"> </span><span class="s">"type"</span><span class="w"> </span><span class="s">"function"</span><span class="p">)</span><span class="w">
 </span><span class="p">(</span><span class="nf">dict</span><span class="w"> </span><span class="s">"candidate"</span><span class="w"> </span><span class="s">"print-dup"</span><span class="w"> </span><span class="s">"ns"</span><span class="w"> </span><span class="s">"clojure.core"</span><span class="w"> </span><span class="s">"type"</span><span class="w"> </span><span class="s">"var"</span><span class="p">)</span><span class="w">
 </span><span class="p">(</span><span class="nf">dict</span><span class="w"> </span><span class="s">"candidate"</span><span class="w"> </span><span class="s">"print-str"</span><span class="w"> </span><span class="s">"ns"</span><span class="w"> </span><span class="s">"clojure.core"</span><span class="w"> </span><span class="s">"type"</span><span class="w"> </span><span class="s">"function"</span><span class="p">)</span><span class="w">
 </span><span class="p">(</span><span class="nf">dict</span><span class="w"> </span><span class="s">"candidate"</span><span class="w"> </span><span class="s">"print-ctor"</span><span class="w"> </span><span class="s">"ns"</span><span class="w"> </span><span class="s">"clojure.core"</span><span class="w"> </span><span class="s">"type"</span><span class="w"> </span><span class="s">"function"</span><span class="p">)</span><span class="w">
 </span><span class="p">(</span><span class="nf">dict</span><span class="w"> </span><span class="s">"candidate"</span><span class="w"> </span><span class="s">"println-str"</span><span class="w"> </span><span class="s">"ns"</span><span class="w"> </span><span class="s">"clojure.core"</span><span class="w"> </span><span class="s">"type"</span><span class="w"> </span><span class="s">"function"</span><span class="p">)</span><span class="w">
 </span><span class="p">(</span><span class="nf">dict</span><span class="w"> </span><span class="s">"candidate"</span><span class="w"> </span><span class="s">"print-method"</span><span class="w"> </span><span class="s">"ns"</span><span class="w"> </span><span class="s">"clojure.core"</span><span class="w"> </span><span class="s">"type"</span><span class="w"> </span><span class="s">"var"</span><span class="p">)</span><span class="w">
 </span><span class="p">(</span><span class="nf">dict</span><span class="w"> </span><span class="s">"candidate"</span><span class="w"> </span><span class="s">"print-simple"</span><span class="w"> </span><span class="s">"ns"</span><span class="w"> </span><span class="s">"clojure.core"</span><span class="w"> </span><span class="s">"type"</span><span class="w"> </span><span class="s">"function"</span><span class="p">))</span><span class="w">
  </span><span class="n">status</span><span class="w">      </span><span class="p">(</span><span class="s">"done"</span><span class="p">)</span><span class="w">
</span><span class="p">)</span></code></pre></figure>

<p>The server is providing detailed information about the completions in the <code class="language-plaintext highlighter-rouge">completions</code>
key. For every completion, it is telling what the completion text is, which namespace it
comes from and the type of completion candidate (<code class="language-plaintext highlighter-rouge">var</code> or <code class="language-plaintext highlighter-rouge">function</code>). Now if you look at the
screenshot above, you can see that <code class="language-plaintext highlighter-rouge">print-method</code> has a <code class="language-plaintext highlighter-rouge">&lt;v&gt;</code> at the end - signifying that
it is a <code class="language-plaintext highlighter-rouge">var</code>. This is based on the <code class="language-plaintext highlighter-rouge">type</code> information sent by the server.</p>

<p>These two messages give us a fair idea about how the operation must be implemented. If I
were to guess how the implementation of nREPL Middleware must be, I would guess it to be
something like the following:</p>

<p align="center">
<img src="/resources/nREPL--probable-architecture.png" style="height: 100%; width: 100%" />
</p>
<p align="center">
<!-- <i>Probable architecture</i> -->
</p>

<p>Depending on the operation, requests would be routed to respective handlers. And to add a
new handler, you would register the operation and the handler function with nREPL.</p>

<p>But that is not the case. There is one small point which is a bit counter intuitive. The
architecture is similar to how <a href="https://github.com/ring-clojure/ring/wiki/Concepts" target="_blank">Ring
middleware</a> works. It looks like this:</p>

<p align="center">
<img src="/resources/nREPL--nrepl-middleware-architecture.png" style="height: 70%; width: 70%;" />
</p>
<p align="center">
<!-- <i>Probable architecture</i> -->
</p>

<p>This type of architecture enables multiple handlers being able to take part in serving a
request. For example, a <code class="language-plaintext highlighter-rouge">complete</code> request from a client, will be handled by the session
middleware (to track the session) and also by the completion middleware (to provide
completions).</p>

<p>With that, we can now proceed to writing our own middleware.</p>

<h2 id="writing-your-own-middleware">Writing Your Own Middleware</h2>

<p>While writing Clojure, we sometimes need to examine macroexpanded code. So let’s write a
simple middleware which will give you macroexpanded code. The <code class="language-plaintext highlighter-rouge">op</code> will be
<code class="language-plaintext highlighter-rouge">macroexpansion</code> (not naming it <code class="language-plaintext highlighter-rouge">macroexpand</code> since <code class="language-plaintext highlighter-rouge">cider-nrepl</code> already has it). It will
take code to be expanded as input and it will send back macroexpanded code. To achieve
this, let’s create a new namespace and write the following code in it:</p>

<figure class="highlight"><pre><code class="language-clojure" data-lang="clojure"><span class="p">(</span><span class="nf">ns</span><span class="w"> </span><span class="n">nrepl-playground.macroexpansion</span><span class="w">         </span><span class="c1">;; Your ns name could be different</span><span class="w">
  </span><span class="p">(</span><span class="no">:require</span><span class="w"> </span><span class="p">[</span><span class="n">clojure.walk</span><span class="w"> </span><span class="no">:as</span><span class="w"> </span><span class="n">walk</span><span class="p">]</span><span class="w">
            </span><span class="c1">;; You'll need to add `nrepl` in your dependenciess</span><span class="w">
            </span><span class="p">[</span><span class="n">nrepl.middleware</span><span class="w"> </span><span class="no">:refer</span><span class="w"> </span><span class="p">[</span><span class="n">set-descriptor!</span><span class="p">]]</span><span class="w"> 
            </span><span class="p">[</span><span class="n">nrepl.misc</span><span class="w"> </span><span class="no">:refer</span><span class="w"> </span><span class="p">[</span><span class="n">response-for</span><span class="p">]]</span><span class="w">
            </span><span class="p">[</span><span class="n">nrepl.transport</span><span class="w"> </span><span class="no">:as</span><span class="w"> </span><span class="n">t</span><span class="p">]))</span><span class="w">

</span><span class="p">(</span><span class="k">defn-</span><span class="w"> </span><span class="n">handle-macroexpansion</span><span class="w">
  </span><span class="p">[{</span><span class="no">:keys</span><span class="w"> </span><span class="p">[</span><span class="n">transport</span><span class="w"> </span><span class="n">code</span><span class="p">]</span><span class="w"> </span><span class="no">:as</span><span class="w"> </span><span class="n">msg</span><span class="p">}]</span><span class="w">
  </span><span class="p">(</span><span class="k">let</span><span class="w"> </span><span class="p">[</span><span class="n">expanded-code</span><span class="w"> </span><span class="p">(</span><span class="nf">walk/macroexpand-all</span><span class="w"> </span><span class="p">(</span><span class="nf">read-string</span><span class="w"> </span><span class="n">code</span><span class="p">))]</span><span class="w">
    </span><span class="p">(</span><span class="nf">t/send</span><span class="w"> </span><span class="n">transport</span><span class="w"> </span><span class="p">(</span><span class="nf">response-for</span><span class="w"> </span><span class="n">msg</span><span class="w">
                                    </span><span class="no">:status</span><span class="w"> </span><span class="no">:done</span><span class="w">
                                    </span><span class="no">:expanded-code</span><span class="w"> </span><span class="p">(</span><span class="nb">str</span><span class="w"> </span><span class="n">expanded-code</span><span class="p">)))))</span><span class="w">

</span><span class="p">(</span><span class="k">defn</span><span class="w"> </span><span class="n">wrap-macroexpansion</span><span class="w">
  </span><span class="p">[</span><span class="n">handler</span><span class="p">]</span><span class="w">
  </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="p">[{</span><span class="no">:keys</span><span class="w"> </span><span class="p">[</span><span class="n">op</span><span class="p">]</span><span class="w"> </span><span class="no">:as</span><span class="w"> </span><span class="n">msg</span><span class="p">}]</span><span class="w">
    </span><span class="p">(</span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nb">=</span><span class="w"> </span><span class="s">"macroexpansion"</span><span class="w"> </span><span class="n">op</span><span class="p">)</span><span class="w">
      </span><span class="p">(</span><span class="nf">handle-macroexpansion</span><span class="w"> </span><span class="n">msg</span><span class="p">)</span><span class="w">
      </span><span class="p">(</span><span class="nf">handler</span><span class="w"> </span><span class="n">msg</span><span class="p">))))</span><span class="w">

</span><span class="p">(</span><span class="nf">set-descriptor!</span><span class="w"> </span><span class="o">#</span><span class="ss">'wrap-macroexpansion</span><span class="w">
                 </span><span class="p">{</span><span class="no">:requires</span><span class="w"> </span><span class="o">#</span><span class="p">{}</span><span class="w">
                  </span><span class="no">:expects</span><span class="w"> </span><span class="o">#</span><span class="p">{}</span><span class="w">
                  </span><span class="no">:handles</span><span class="w"> </span><span class="p">{</span><span class="s">"macroexpansion"</span><span class="w">
                            </span><span class="p">{</span><span class="no">:doc</span><span class="w"> </span><span class="s">"Get macroexpanded code"</span><span class="w">
                             </span><span class="no">:requires</span><span class="w"> </span><span class="p">{</span><span class="s">"code"</span><span class="w"> </span><span class="s">"code to be macroexpanded"</span><span class="p">}</span><span class="w">
                             </span><span class="no">:optional</span><span class="w"> </span><span class="p">{}</span><span class="w">
                             </span><span class="no">:returns</span><span class="w"> </span><span class="p">{</span><span class="s">"expanded-code"</span><span class="w"> </span><span class="s">"macroexpanded code"</span><span class="p">}}}})</span></code></pre></figure>

<p>Let’s look at what we are doing here. Our handler is <code class="language-plaintext highlighter-rouge">handle-macroexpansion</code>. Middleware
handler should be a function which accepts <code class="language-plaintext highlighter-rouge">msg</code> as its input. This will the message sent
by client. So we are extracting <code class="language-plaintext highlighter-rouge">code</code> from it. Then we are macroexpanding the code and
sending it back to the client.</p>

<p>The <code class="language-plaintext highlighter-rouge">wrap-macroexpansion</code> function is the middleware function. If the <code class="language-plaintext highlighter-rouge">op</code> is
<code class="language-plaintext highlighter-rouge">macroexpansion</code> we pass the message to our handler, otherwise we pass control to the next
handler.</p>

<p>The call to <code class="language-plaintext highlighter-rouge">set-descriptor!</code> tells nREPL to set this middleware. The second parameter is
the middleware descriptor - a map containing details about the middleware. <code class="language-plaintext highlighter-rouge">requires</code>
should be a set containing middleware vars or strings (ops) which need to be run <em>before</em>
your middleware. <code class="language-plaintext highlighter-rouge">excepts</code> should be a set containing middleware vars or strings (ops)
which need to be run <em>after</em> your middleware. This is how the order of middleware is
decided.</p>

<p>For example, if your middleware depends on other middleware, for example, if it depends on
the session middleware, you will put <code class="language-plaintext highlighter-rouge">requires</code> as <code class="language-plaintext highlighter-rouge">#{'session}</code>. If your middleware
expects <code class="language-plaintext highlighter-rouge">eval</code> middleware to be called after your middleware executes, you will write
<code class="language-plaintext highlighter-rouge">expects</code> as <code class="language-plaintext highlighter-rouge">#{"eval"}</code>.</p>

<p>Our middleware does not depend on any other middleware, nor does it expect any other
middleware to be executed later. So for us, both of these sets are empty.</p>

<p><code class="language-plaintext highlighter-rouge">handles</code> is used for documenting the middleware. This map should have operations (as
strings) it handles as its keys (<code class="language-plaintext highlighter-rouge">"macroexpansion"</code> in our case) and values should be maps
describing those operations:</p>

<figure class="highlight"><pre><code class="language-clojure" data-lang="clojure"><span class="p">{</span><span class="no">:doc</span><span class="w"> </span><span class="n">&lt;description</span><span class="w"> </span><span class="n">of</span><span class="w"> </span><span class="n">your</span><span class="w"> </span><span class="n">opearation&gt;</span><span class="w">
 </span><span class="no">:requires</span><span class="w"> </span><span class="n">&lt;map</span><span class="w"> </span><span class="n">of</span><span class="w"> </span><span class="n">required</span><span class="w"> </span><span class="n">things</span><span class="w"> </span><span class="n">it</span><span class="w"> </span><span class="n">expects</span><span class="w"> </span><span class="n">in</span><span class="w"> </span><span class="n">msg&gt;</span><span class="w">
 </span><span class="no">:optional</span><span class="w"> </span><span class="n">&lt;map</span><span class="w"> </span><span class="n">of</span><span class="w"> </span><span class="n">optional</span><span class="w"> </span><span class="n">things</span><span class="w"> </span><span class="n">it</span><span class="w"> </span><span class="n">expects</span><span class="w"> </span><span class="n">in</span><span class="w"> </span><span class="n">msg&gt;</span><span class="w">
 </span><span class="no">:returns</span><span class="w"> </span><span class="n">&lt;map</span><span class="w"> </span><span class="n">of</span><span class="w"> </span><span class="n">return</span><span class="w"> </span><span class="n">values</span><span class="w"> </span><span class="n">it</span><span class="w"> </span><span class="n">puts</span><span class="w"> </span><span class="n">in</span><span class="w"> </span><span class="n">msg&gt;</span><span class="p">}</span></code></pre></figure>

<p>But calling <code class="language-plaintext highlighter-rouge">set-descriptor!</code> is not enough. Middleware stack cannot be modified
dynamically once nREPL starts. So to tell Leiningen to add this middleware to nREPL
<em>before</em> starting the server, you will need to add this to your project file:</p>

<figure class="highlight"><pre><code class="language-clojure" data-lang="clojure"><span class="no">:repl-options</span><span class="w"> </span><span class="p">{</span><span class="no">:nrepl-middleware</span><span class="w"> 
               </span><span class="p">[</span><span class="n">nrepl-playground.macroexpansion/wrap-macroexpansion</span><span class="p">]}</span></code></pre></figure>

<p>You will need to restart your REPL for the middleware to take effect. There is a way to
enable dynamic middleware loading, but that is a topic for another blog post.</p>

<p>After you start the REPL, connect to it from Emacs. From the REPL buffer (or from any
other Clojure file buffer from the running project), press <code class="language-plaintext highlighter-rouge">M-:</code> (which runs
<code class="language-plaintext highlighter-rouge">eval-expression</code>) and in the prompt, type the following and press <code class="language-plaintext highlighter-rouge">RET</code>:</p>

<figure class="highlight"><pre><code class="language-elisp" data-lang="elisp"><span class="p">(</span><span class="nv">cider-nrepl-send-sync-request</span> <span class="o">`</span><span class="p">(</span><span class="s">"op"</span> <span class="s">"macroexpansion"</span>
                                 <span class="s">"code"</span> <span class="s">"(defn add [a b] (+ a b))"</span><span class="p">))</span></code></pre></figure>

<blockquote>
  <p><code class="language-plaintext highlighter-rouge">cider-nrepl-send-sync-request</code> is a function provided by <code class="language-plaintext highlighter-rouge">cider</code> - the Emacs client for
<code class="language-plaintext highlighter-rouge">cider-nrepl</code> - to send messages to the REPL server.</p>
</blockquote>

<p>You will see the reply message in the
minibuffer but it won’t be much readable in a single line. So switch to the messages
buffer and you should find messages similar to these:</p>

<figure class="highlight"><pre><code class="language-clojure" data-lang="clojure"><span class="p">(</span><span class="nf">--&gt;</span><span class="w">
  </span><span class="n">id</span><span class="w">         </span><span class="s">"124"</span><span class="w">
  </span><span class="n">op</span><span class="w">         </span><span class="s">"macroexpansion"</span><span class="w">
  </span><span class="n">session</span><span class="w">    </span><span class="s">"aedffa41-cbfa-4577-8450-864c8fb06349"</span><span class="w">
  </span><span class="n">time-stamp</span><span class="w"> </span><span class="s">"2020-08-20 22:03:28.467298000"</span><span class="w">
  </span><span class="n">code</span><span class="w">       </span><span class="s">"(defn add [a b] (+ a b))"</span><span class="w">
</span><span class="p">)</span><span class="w">
</span><span class="p">(</span><span class="nf">&lt;--</span><span class="w">
  </span><span class="n">id</span><span class="w">            </span><span class="s">"124"</span><span class="w">
  </span><span class="n">session</span><span class="w">       </span><span class="s">"aedffa41-cbfa-4577-8450-864c8fb06349"</span><span class="w">
  </span><span class="n">time-stamp</span><span class="w">    </span><span class="s">"2020-08-20 22:03:28.470777000"</span><span class="w">
  </span><span class="n">expanded-code</span><span class="w"> </span><span class="s">"(def add (fn* ([a b] (+ a b))))"</span><span class="w">
  </span><span class="n">status</span><span class="w">        </span><span class="p">(</span><span class="s">"done"</span><span class="p">)</span><span class="w">
</span><span class="p">)</span></code></pre></figure>

<p>You can see that <code class="language-plaintext highlighter-rouge">expanded-code</code> has the macroexpanded code for the code we had sent in
the request. Our middleware is working! :)</p>

<h2 id="conclusion">Conclusion</h2>

<p>In this post, we saw:</p>

<ul>
  <li>Why was there a need to have REPLs other than Clojure’s default REPL.</li>
  <li>How nREPL provides extensibility with support for custom middleware.</li>
  <li>How to look at client-server messaging with Emacs + <code class="language-plaintext highlighter-rouge">cider</code>.</li>
  <li>Architecture of nREPL Middleware.</li>
  <li>How to add a custom middleware.</li>
</ul>

<p>Now whenever you feel like some functionality is missing from your Clojure development
setup and if you feel adventurous, go ahead and implement it as a middleware! :)</p>]]></content><author><name>Suvrat Apte</name></author><category term="clojure," /><category term="cider-nrepl," /><category term="nrepl" /><summary type="html"><![CDATA[In this post, I have tried to cover what nREPL is, what nREPL Middleware are and why we need them. We will also look at the middleware provided by cider-nrepl and in the end, we will write our own custom middleware. If you write Clojure, you are most probably using nREPL as that is the most popular REPL out there. But it is not the only REPL out there. The Clojure REPL Clojure itself has its own REPL. To start the default Clojure REPL, just run the clojure on your terminal. You will see a REPL prompt. This is the default Clojure REPL. Try (println "Hello, world!") and you will see it works just like any other REPL. But there are a few problems with this REPL. It does not support some basic features like autocompletion or line editing (visiting previously typed text with up arrow) Line editing will work if you use the clj command, but it is just a wrapper over clojure with rlwrap. If you read man clojure, you will also notice that there is no easy way to start this REPL on a socket. So if you are using this REPL, you cannot connect to it from remote machines. So the default REPL clearly cannot be used as your daily development REPL. That is where the need for other types of REPLs comes in. nREPL Network REPL (nREPL) is a huge improvement over the default Clojure REPL. nREPL has a client server design. As the name suggests, an nREPL server can be started on a socket so that remote clients can connect to it. It also gives you support for autocompletion, symbol lookups and many more things.]]></summary></entry></feed>