<?xml version="1.0" encoding="UTF-8"?><rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title>Mrinal&#39;s Blog</title><link>https://mrinalxdev.github.io/mrinalxblogs/blogs/blog.html</link><atom:link href="http://rss.144-124-237-35.sslip.io/mrinalxdev/blog" rel="self" type="application/rss+xml"></atom:link><description>Technical blog by Mrinal covering Redis, Distributed Systems, Algorithms, and more. - Powered by AtomRSS</description><generator>AtomRSS</generator><webMaster>contact@atomgroup.dev (AtomRSS)</webMaster><language>en</language><lastBuildDate>Sat, 08 Aug 2026 05:07:40 GMT</lastBuildDate><ttl>5</ttl><item><title>Search Engines at scale : From a Beginners POV</title><description>&lt;hr class=&quot;mt-3&quot;&gt;

      &lt;h1 class=&quot;text-4xl mt-[57px] mb-3 font-serif&quot;&gt;
        Search Engines at scale from a Beginners POV
      &lt;/h1&gt;
      &lt;span class=&quot;text-sm text-gray-500&quot;&gt;6th April, 2026&lt;/span&gt;
      &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;
        Last time time we discussed on the basics of search engines and two ways
        on how does it indexes everything. In this blog I will try to share how
        these search engines work at scale and handles not thousands but
        millions or billions of documents.
      &lt;/p&gt;

      &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/search-engine-II/banner.png&quot; class=&quot;w-full max-w-[590px] h-auto mx-auto my-10&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

      &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;
        As search engine grows keeping the entire index on a single machine
        becomes nearly impossible. We eventually hit physical limits regarding
        RAM, storage space and processing power. Adding more resources to a
        single machine is known as vertical scaling which is somewhat costly and
        offers diminishing returns. The only viable path forward is horizontal
        scaling, which involves distributing the data across many separate
        computers. This is called &lt;span class=&quot;font-bold&quot;&gt;Sharding&lt;/span&gt;
      &lt;/p&gt;

      &lt;h1 class=&quot;text-4xl mt-[57px] mb-3 font-serif&quot;&gt;
        Partitioning data horizontally
      &lt;/h1&gt;

      &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;
        To distribute data more effectively we need to explain how to route
        specific documents to specific machines. Two main strategies exist for
        this allocation which are
        &lt;span class=&quot;font-bold&quot;&gt;range based partitioning&lt;/span&gt; which assigns
        documents to shards based on alphaetical or numerical ranges. For
        example documents starting with A through M go to shard 1 while N
        through Z go to shard 2. This approach makes range scans easy and
        effective but can lead to uneven distribution if certain letters are
        more common. Then comes
        &lt;span class=&quot;font-bold&quot;&gt;Hash Based partitioning&lt;/span&gt; this applies a
        mathematical formula to a unique identifier, such as the document ID to
        deteremine its destination. This ensures an even spread of data across
        all machines which optimizes storage usage but makes querying by range
        difficult.
      &lt;/p&gt;

      &lt;div class=&quot;my-10&quot;&gt;
        &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/search-engine-II/range.png&quot; class=&quot;w-[600px] mx-auto&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
        &lt;p class=&quot;text-gray-500 text-sm&quot;&gt;Example of range based partitioning&lt;/p&gt;
      &lt;/div&gt;

      &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;
        Now splitting data introduces the distributedd indexing problem. When we
        replicate data across nodes to secure the loss we must balance
        consistency and availability. If a user updates a document we must
        decide how strictly to enforce that update across all replicas before
        acknowledging success. Relying on consistency would mean that all users
        see the same data but may slow down the system or have some errors if a
        node goes down. While if we prioritize availability which will allow the
        systems to keep functioning during outages but it risks returning stale
        results.
      &lt;/p&gt;

      &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;
        To answer a user query the system must often ask multiple machines for
        their portion of the results and combine them. The difficulty is in
        executing this without the user waiting for the slowest machine in the
        cluster to respond. If one shard is lagging due to heavy load the entire
        search experience suffers.
      &lt;/p&gt;

      &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;
        The biggest problem here is the &lt;span class=&quot;font-bold&quot;&gt;straggler&lt;/span&gt; effect. If even one shard is
        slow (due to high load, hardware issues, or bad luck) the entire query
        has to wait for that slowest shard. The user doesn’t care which shard is
        slow they just want fast results.
      &lt;/p&gt;

      &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/search-engine-II/linking.png&quot; class=&quot;my-10 mx-auto w-[590px]&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

      &lt;h1 class=&quot;text-4xl mt-[57px] mb-3 font-serif&quot;&gt;Query Federation&lt;/h1&gt;

      &lt;p class=&quot;text-lg font-serif mt-4 mb-4&quot;&gt;To allow searching across multiple shards we use a pattern known as scatter gather or query federation. The query lifecycle begins when a coordinator node receives a user request and the node acts as the central conductor. It scatters the request to all relevant shards simultaneously. This parallel execution is important because it allows the system to use the combined processing powwer of of every machine in the cluster and each shard executes the search locally on its own subset of data. Once the shards find their matches they send their individual results back to the coordinator. The coordinator then gathers these partiall results to form a complete response for the user.&lt;/p&gt;

      &lt;p class=&quot;text-xl py-3 font-serif&quot;&gt;The Map-reduce&lt;/p&gt;

      &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;I am sure till now you have seen many people to read and implement map reduce research paper, inface I did the same :p. While scatter gather describes the flow of data the root computational model is often referred to as &lt;span class=&quot;font-bold&quot;&gt;Map-Reduce&lt;/span&gt;. In the context of a live search query this pattern splits the workload into two distict phases. The &lt;span class=&quot;font-bold&quot;&gt;Map phase&lt;/span&gt; occurs at the shard level when a shard receives a query it maps the search terms against its local index amd ot calculates a relevance score for every matching document and generates a list of candidate results. The shard then filters this list to keep only the most promising candidates which reduces the amount of data that must travel over the network.&lt;/p&gt;

      &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;&lt;span class=&quot;font-bold&quot;&gt;Reduce phase&lt;/span&gt; takes place on the coordinator node. Here, the system receives the candidate lists from all the shards. It must reduce this multitude of lists into a single, ordered result set. This involves comparing the relevance scores from different shards and sorting them to identify the absolute best matches and by separating the work into a mapping step that runs in parallel and a reduction step that consolidates the output the system can process massive datasets successfully without overwhelming a single machine.&lt;/p&gt;

      &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/search-engine-II/map-reduce.png&quot; class=&quot;my-10 w-[850px] mx-auto&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

      &lt;p class=&quot;text-xl py-3 font-serif&quot;&gt;Coordinating and Merging Results&lt;/p&gt;

      &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;It requires careful sorting logic. Each shard returns a list of documents ranked by relevance based on its local view of the data amd the coordinator cannot simply append these lists together. It must merge them into a single, sorted list. This process involves taking the top results from each shard and re-ranking them to find the global best matches.&lt;/p&gt;

      &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;If a user requests the top ten results, the coordinator cannot just ask for ten items from each shard. It might need to retrieve the top fifty or one hundred results from each shard to ensure accuracy and this buffer is necessary because a document ranked fifteenth on one specific shard might actually be more relevant globally than the top result on another shard. The coordinator uses a priority queue or a merge algorithm to compare the heads of these lists and select the highest scoring documents until the final page of results is complete.&lt;/p&gt;

      &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;We are all covered for the second part of this Search Engines series next week we will be moving ahead with the last part of this series which is the study of architecture of &lt;span class=&quot;font-bold&quot;&gt;ElasticSearch&lt;/span&gt; Hope I was able to add some value to your today&#39;s learning ^^ &lt;br&gt; Happy Learning Anon&lt;/p&gt;

      
    
  

</description><link>https://mrinalxdev.github.io/mrinalxblogs/blogs/search-engine-II.html</link><guid isPermaLink="false">https://mrinalxdev.github.io/mrinalxblogs/blogs/search-engine-II.html</guid><pubDate>Invalid Date</pubDate><author>Mrinal</author></item><item><title>Search Engines 101 : From a Beginners POV</title><description>&lt;hr class=&quot;mt-3&quot;&gt;

    &lt;h1 class=&quot;text-4xl mt-[57px] mb-3 font-serif&quot;&gt;
      Search Engines from Beginners POV
    &lt;/h1&gt;
    &lt;span class=&quot;text-sm text-gray-500&quot;&gt;1st March, 2026&lt;/span&gt;

    &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;
      Search engines are simple to define with respect to their core job which
      is to return the most relevant documents for a query in milliseconds. But
      still it is arguably the most complex software systems in existence.
    &lt;/p&gt;

    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/search-engines/banner.png&quot; class=&quot;w-full max-w-[550px] h-auto mx-auto my-10&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

    &lt;h1 class=&quot;text-3xl font-serif&quot;&gt;How Inverted Indices Work&lt;/h1&gt;

    &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;
      To understand the &quot;Search&quot; part of search engines, one must first
      understand why traditional databases fail at it. In a standard relational
      database (like PostgreSQL or MySQL), data is stored in rows. If you want
      to find a specific word in a description column, the database effectively
      has to open every single row and scan the text to see if the word exists.
      In computer science terms, this is an \( O(n) \) operation which means as
      my data will grow, the speed to reach that drops linearly. For a web scale
      dataset this is unacceptably slow. &lt;br&gt;
      The solution for this is Inverted Index
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;
      Instead of mapping Documenting terms like a book&#39;s chapter, an inverted
      index maps the terms according to the documents.
    &lt;/p&gt;

    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/search-engines/2.png&quot; class=&quot;w-full max-w-[600px] h-auto mx-auto my-10&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

    &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;
      Inverted Index consists of two components, first one is
      &lt;span class=&quot;font-bold&quot;&gt;Term Dictionary&lt;/span&gt; which is an aplhabetized
      list of every unique word (term) found in entire dataset. This is often
      kept in memory using a Hash Map or a Trie(Prefix tree) for speed. Second
      one is &lt;span class=&quot;font-bold&quot;&gt;Posting Lists&lt;/span&gt; for every term in the
      dictionary, there is an associated list of document IDs where that term
      appears.
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;
      This makes a search engine to query millions of documents in thee exact
      same amount of time it takes to query one but the questions is how does it
      even happen ??
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;
      When the user searches for the word &quot;data,&quot; the engine does not scan
      documents. Instead it hashes the word &quot;data&quot; and then jumps directly to
      that entry in the term dictionary (an \(O(1)\) or constant time
      operation). Than retrieves the the posting list like [Doc1, Doc4, Doc87]
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;
      However, this raw speed relies on exact matching. A computer views
      &quot;Running&quot; and &quot;run&quot; as completely different binary strings. If our index
      is too literal, it becomes brittle. But if we just store every word, how
      do we handle &quot;running&quot; vs &quot;run&quot; or typos ??
    &lt;/p&gt;

    &lt;h1 class=&quot;text-3xl font-serif my-7&quot;&gt;
      Tokenization, Stemming and Analysis
    &lt;/h1&gt;

    &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;
      So to handle the variation of human language is not by indexing instead by
      transforming the data before it enters the index. This process is called
      &lt;span class=&quot;font-bold&quot;&gt;Analysis&lt;/span&gt;. When we insert text into a search
      engine, it doesn&#39;t just store the string. It passes the text through an
      Analysis Chain, a pipeline of processors that standardize the text
    &lt;/p&gt;

    &lt;p class=&quot;text-xl py-3 font-serif&quot;&gt;The Analysis Pipeline&lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif&quot;&gt;
      (&lt;span class=&quot;font-bold&quot;&gt;Character filters&lt;/span&gt;) The raw stream is
      cleaned, like the stripping HTML tags to make &amp;lt;&quot;h1&quot;&amp;gt;Hello&amp;lt;&quot;/h1&quot;&amp;gt; into
      Hello or converting &amp;amp; to and. Then comes (&lt;span class=&quot;font-bold&quot;&gt;Tokenizer&lt;/span&gt;) the text is chopped into discrete chunks called tokens. A standard
      whitespace tokenizer splits &quot;Hello, myself Mrinal&quot; into [Hello, myself,
      Mrinal]
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif&quot;&gt;
      (&lt;span class=&quot;font-bold&quot;&gt;Tokenizers&lt;/span&gt;) the text is chopped into
      discrete chunks called tokens. A standard whitespace tokenizer splits &quot;The
      quick brown fox&quot; into [The, quick, brown, fox]
    &lt;/p&gt;

    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/search-engines/3.png&quot; class=&quot;w-full max-w-[700px] h-auto mx-auto my-10&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

    &lt;p class=&quot;text-lg font-serif&quot;&gt;
      Now there are few steps which get followed for the process where the
      normalization happens. The tokens flow through a series of transformations
    &lt;/p&gt;

    &lt;ul class=&quot;list-disc ml-8 my-5 font-serif text-lg&quot;&gt;
      &lt;li&gt;
        &lt;span class=&quot;font-bold&quot;&gt;Lowercasing&lt;/span&gt; : &quot;The&quot; becomes &quot;the&quot;. this
        ensures searches are case insensitive.
      &lt;/li&gt;

      &lt;li&gt;
        &lt;span class=&quot;font-bold&quot;&gt;Stop word removal&lt;/span&gt; : Common words with
        little semantic value (like &quot;a&quot;, &quot;an&quot;, &quot;the&quot;, &quot;is&quot;) are often removed to
        save space and reduce noice.
      &lt;/li&gt;

      &lt;li&gt;
        &lt;span class=&quot;font-bold&quot;&gt;Stemming&lt;/span&gt; : This algorithm reduces words
        to their root form. It chops suffixes, turning &quot;running,&quot; &quot;runs,&quot; and
        &quot;ran&quot; all into the root token &quot;run.&quot; This ensures a search for one tense
        finds all variations.
      &lt;/li&gt;

      &lt;li&gt;
        &lt;span class=&quot;font-bold&quot;&gt;Synonyms&lt;/span&gt; : You can inject rules where if
        the engine sees &quot;notebook,&quot; it also indexes the token &quot;laptop.&quot;
      &lt;/li&gt;
    &lt;/ul&gt;

    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/search-engines/4.png&quot; class=&quot;w-full max-w-[800px] h-auto mx-auto my-10&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

    &lt;p class=&quot;text-xl py-3 font-serif&quot;&gt;Why &quot;CAT&quot; != &quot;cat != &quot;kitten&quot;&lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif&quot;&gt;
      Without this pipeline, the byte sequence for &quot;CAT&quot; does not match &quot;cat&quot;.
      By running both the document text and the user&#39;s query text through the
      same analysis chain, we ensure they meet in the middle. If the document
      contains &quot;Running&quot; and the user searches &quot;run,&quot; the analyzer reduces both
      to &quot;run,&quot; creating a match
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif&quot;&gt;
      Now we have a system that can tolerate human variation and retrieve all
      documents containing our terms. However, mere retrieval is not enough. If
      I search for &quot;News,&quot; I might get 10 millions documents. So we can index
      text effectively, but how do we actually decide what results matter most
      ??
    &lt;/p&gt;

    &lt;h1 class=&quot;text-3xl font-serif my-7&quot;&gt;Ranking and Relevance&lt;/h1&gt;

    &lt;p class=&quot;text-lg font-serif&quot;&gt;
      We decide what matters most by calculating a
      &lt;span&gt;Relevance Score&lt;/span&gt; for every matching document. This is not
      boolean &quot;yes/no&quot; but a floating point number representing how well a
      document matches the query. Although newer engines uses machine learning
      (learning to rank), the foundational algorithms rely on statitical
      probablity
    &lt;/p&gt;

    &lt;p class=&quot;text-2xl py-3 font-serif my-5&quot;&gt;TF-IDF | Measuring the rarity&lt;/p&gt;

    &lt;p class=&quot;font-serif text-lg&quot;&gt;
      Term Frequency Inverse Document Frequency. This method quantifies how
      important a word is to a document within a larger collection (or corpus)
      by balancing two key intuition
    &lt;/p&gt;

    &lt;p class=&quot;text-xl py-3 font-serif my-3&quot;&gt;TF (Term Frequency)&lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif&quot;&gt;
      This measures how frequently a term appears in a specific document. The
      underlying idea is that repetition signals importance. For instance, if
      the search term &quot;quantum&quot; appears 5 times in Document A and only once in
      Document B, Document A is likely more relevant to a query about quantum
      physics. The basic formula is \[ \text{TF (t, d)} = \text{count of term t
      in document d} \] Variations exist, such as normalized TF to account for
      document lenght \[ \text{TF(t, d)} = \frac{ \text{count of t in d}}{
      \text{total words in d}} \] this prevents longer documents from being
      unfairly favoured due to huge size.
    &lt;/p&gt;

    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/search-engines/5.png&quot; class=&quot;w-full max-w-[650px] h-auto mx-auto my-10&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/search-engines/6.png&quot; class=&quot;w-full max-w-[500px] h-auto mx-auto my-10&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

    &lt;p class=&quot;text-xl py-3 font-serif my-3&quot;&gt;IDF (Inverse Document Frequency)&lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif&quot;&gt;
      Not all words are created equal, common ones like &quot;the&quot; or &quot;and&quot; appear
      everywhere and offer little discriminatory power. IDF downweights these by
      highlighting rarity. For example in a search for &quot;The Matrix,&quot; the word
      &quot;The&quot; is universal and useless, while &quot;Matrix&quot; is rarer and thus more
      informative. The formula is &lt;br&gt;
      \[ \text{IDF(t)} = \log \frac{\text{Total number of documents in
      corpus}}{\text{Number of documents containing t}} \]
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif&quot;&gt;
      The logarithm smooths the scale and adding 1 to the denominator avoids
      division by zero ... &lt;br&gt;
      \[ \text{IDF(t)} = \log \frac{\text{Total number of documents in corpus +
      1}}{\text{Number of documents containing t + 1}} \]
    &lt;/p&gt;

    &lt;p class=&quot;font-serif text-lg&quot;&gt;
      The final TF-IDF weight for a term in a document combines these \[
      Weight(t, d) = TF(t, d) \times IDF(t) \] Higher weights indicate terms
      that are both frequent in the document and rare across the corpus, making
      them strong indicators of relevance.
    &lt;/p&gt;

    &lt;p class=&quot;text-xl py-3 font-serif my-3&quot;&gt;
      Example usecase using a calculation
    &lt;/p&gt;

    &lt;p class=&quot;font-serif text-lg&quot;&gt;
      we have a corpus of 100 documents, and we&#39;re querying for &quot;apple
      computer.&quot; The term &quot;apple&quot; appears in 10 documents (IDF = log(100/10) ≈
      1.0), while &quot;computer&quot; appears in 20 (IDF ≈ 0.7). In Document A: &quot;apple&quot;
      appears 3 times (TF=3), &quot;computer&quot; 2 times (TF=2). TF-IDF for &quot;apple&quot; = 3
      × 1.0 = 3; for &quot;computer&quot; = 2 × 0.7 = 1.4. The document&#39;s score could be
      the sum or average of these, depending on the implementation.
    &lt;/p&gt;

    &lt;h1 class=&quot;text-3xl font-serif my-7&quot;&gt;Vector Space Model&lt;/h1&gt;

    &lt;p class=&quot;font-serif text-lg&quot;&gt;
      TF-IDF weights form the foundation for representing text in a mathematical
      framework called the Vector Space Model (VSM). Here, each document and
      query is treated as a vector in a high-dimensional space, where each
      dimension corresponds to a unique term in the vocabulary.
    &lt;/p&gt;

    &lt;ul class=&quot;ml-4 list-disc font-serif text-lg&quot;&gt;
      &lt;li class=&quot;p-2&quot;&gt;
        &lt;span class=&quot;italic&quot;&gt;Vector Representation&lt;/span&gt; : If the corpus
        vocabulary has 10,000 unique words, every document becomes a
        10,000-dimensional vector. The value in each dimension is the TF-IDF
        weight for that term (or 0 if absent). For a query like &quot;The Matrix,&quot;
        its vector would have non-zero weights only for relevant terms.
        &lt;br&gt;This sparse representation (mostly zeros) is efficient but can be
        computationally intensive for large vocabularies.
      &lt;/li&gt;

      &lt;li class=&quot;p-2&quot;&gt;
        &lt;span&gt;Similarity Measurement&lt;/span&gt; : To rank documents, we compare the query vector  \(  \vec{q} \) to each document vector \(  \vec{d}  \). The most common metric is Cosine Similarity, which measures the angle between vectors (ignoring magnitude to focus on direction/orientation) &lt;br&gt;
        \[   Cosine(\vec{q}, \vec{d}) = \frac{\vec{q} \cdot \vec{d}}{||\vec{q}|| \times ||\vec{d}||}   \]

        Where \[  \vec{q} \cdot \vec{d}  \] is the dot product, and \[  ||\vec{q}||  \] is the Euclidean norm. Scores range from -1 (opposite) to 1 (identical); higher values indicate closer semantic alignment. A smaller angle means better relevance.
      &lt;/li&gt;
    &lt;/ul&gt;

    &lt;h1 class=&quot;text-3xl font-serif my-7&quot;&gt;Whats Next ??&lt;/h1&gt;

    &lt;p class=&quot;font-serif text-lg&quot; &quot;=&quot;&quot;&gt;We have covered how to find and rank text, but what happens when the data is too big to fit on one machine? In Part II, we will look at Distributed Search, exploring Sharding, Replication, and the consensus algorithms that keep the engine running when servers fail.&lt;/p&gt;

    &lt;p class=&quot;font-serif text-lg&quot;&gt;That&#39;s all from my side for the first part, I am working on part II and will be releasing it soon .... Hope I was able to add some value to your learning ^^&lt;/p&gt;

    
  
</description><link>https://mrinalxdev.github.io/mrinalxblogs/blogs/search-engines.html</link><guid isPermaLink="false">https://mrinalxdev.github.io/mrinalxblogs/blogs/search-engines.html</guid><pubDate>Invalid Date</pubDate><author>Mrinal</author></item><item><title>Redis 101 : From a Beginners POV</title><description>&lt;hr class=&quot;mt-3&quot;&gt;

    &lt;h1 class=&quot;text-4xl mt-[57px] mb-3 font-serif&quot;&gt;
      Redis 101 : From a Beginners POV
    &lt;/h1&gt;
    &lt;span class=&quot;text-sm text-gray-500&quot;&gt;2nd October, 2025&lt;/span&gt;

    
    &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;
        Whenever I have talked about redis in my projects people woud think it as a cache to use . But redis is more than that we can use redis as rate limiter, message broker and as a database ... But what is even redis, why is it even so fast and how are we even using it . Raising all this question made me curious about this topic and so I want you to be ...
    &lt;/p&gt;


    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/redis/banner.png&quot; class=&quot;w-[750px] mx-auto my-10&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

    &lt;h1 class=&quot;text-2xl font-serif&quot;&gt;Foundation&lt;/h1&gt;

    &lt;p class=&quot;font-serif mt-4 text-lg&quot;&gt;Lets first start with &lt;span class=&quot;font-bold&quot;&gt;What is Cache&lt;/span&gt; so its simple caching is like keeping frequently used items on your desk instead of fetching them from a storage room. Caching stores frequently accessed data in a temporary, high-speed storage layer, reducing latency and improving performance by minimizing redundant computations or database queries. Now Redis is our &lt;span class=&quot;font-bold&quot;&gt;high speed storage layer&lt;/span&gt; stands for remote dictionary server, its a single threaded, in memory data structure storage model .. Which means unlike databases like PostgreSQL, MySQL which stores data on slower mechanical or solid state drives, redis keeps all its data in RAM. This means every read and write operation happens at memory speed wihtout the worrying about disk input / output &lt;/p&gt;

    &lt;h1 class=&quot;text-2xl font-serif my-7&quot;&gt;Why Redis is this fast ??&lt;/h1&gt;

    &lt;p class=&quot;font-serif text-lg mt-3&quot;&gt;There are three main pillers behind this speed, first being the &lt;span class=&quot;font-bold&quot;&gt;In Memory Data Storage&lt;/span&gt;, this is the most significant factor as accessing data from RAM is orders of magnitude faster than from even the fastest SSDs or NVMe drives. Main memory access latency is typically in the nanosecond range, while disk access is in the microsecond to millisecond range. By keeping the entire dataset in RAM, redis eliminates biggest bottleneck in database systems which is disk I/O&lt;/p&gt;

    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/redis/ram.png&quot; class=&quot;my-10&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

    &lt;p class=&quot;font-serif text-lg mt-3&quot;&gt;Second reason being &lt;span class=&quot;font-bold&quot;&gt;Single threaded command execution&lt;/span&gt;, redis processes all commands on a single thread. This design avoids the overhead of multithreading. There are no locks to acquire, no context switching between threads and no race conditions to manage. The CPU can focus purely on executing commands sequentially without interruption, which is incredibly efficient for the workload Redis is designed for (many small, fast operations).&lt;/p&gt;

    &lt;p class=&quot;font-serif text-lg mt-3&quot;&gt;Third reason being &lt;span class=&quot;font-bold&quot;&gt;highly optimized C code and data structures&lt;/span&gt;, redis is written in ANSI C, a language known for its performance. Beyond the language, it uses custom, highly-tuned data structures. For example, its Simple Dynamic String (SDS) and the various encodings for Hashes and Sets (like ziplists) are designed to minimize memory usage and CPU cycles for common operations, ensuring that not only is the data in RAM, but it&#39;s stored in the most efficient way possible.&lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;You might get a question that redis must handle thousand of concurrent client connections and execute commands with microsecond latency, what architectural mode allows it to manage this so effieciently??&lt;/p&gt;

    &lt;h1 class=&quot;my-6 text-2xl font-serif&quot;&gt;The single threaded nature&lt;/h1&gt;

    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/concurrency/multi-threaded.png&quot; class=&quot;my-10&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;The core of Redis&#39;s command processing is single threaded. This means it uses a single CPU core to process all incoming commands, parse them and execute them. This choice is intentional,as it eliminates the complexity and performance overhead of multithreading, such as lock contention, race condition and context switching&lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;To handle concurrency, redis employes an event driven architecture using an &lt;span class=&quot;font-bold&quot;&gt;I/O multiplexing&lt;/span&gt; mechanism. The main thread runs an event loop that uses system calls epoll, kqueue or IOCP to effieciently observe multiple network sockets&lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;Lets take up a scene in which you are the only one who knows how to cook and chop veggies, but you can only chop one ingredient at a time(the single redis thread). But you have multiple assistants (your friends ofc) (the operating system&#39;s I/0 multiplexing features, like kqueue and IOCP). You told your friends to watch all these pots on the stove. The moment one is ready, they should inform you. All this to not waste your time standing and string at the pots. Instead you chop veggies, when one of your assistant shouts, &quot;pot#3 is boiling !!&quot; then you immediately stop what ever was being done, deal with that pot and then go back to chopping. So in this scenario &lt;span class=&quot;font-bold&quot;&gt;you&lt;/span&gt; are the redis main event loop, &lt;span class=&quot;font-bold&quot;&gt;pots&lt;/span&gt; are client connections and &lt;span class=&quot;font-bold&quot;&gt;your friends&lt;/span&gt;  are the operating system&#39;s kernel, which efficiently notifies Redis when a client has sent a request or is ready to receive a response.&lt;/p&gt;

    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/redis/io.png&quot; class=&quot;my-10&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;So this is what the actual process looks like : &lt;/p&gt;

    &lt;ul class=&quot;font-serif text-lg list-disc ml-6 my-4&quot;&gt;
      &lt;li&gt;The event loop registers all client sockets with the multiplexing API.&lt;/li&gt;
      &lt;li&gt;The API notifies the Redis event loop only when a socket is ready for an I/O operation (e.g., a client has sent data, or a TCP buffer is ready to receive a response).&lt;/li&gt;
      &lt;li&gt;The single thread then processes the ready event: it reads the command from the socket, parses it, executes it, and writes the response back to the socket.&lt;/li&gt;
    &lt;/ul&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;This non-blocking I/O model ensures the single thread is never idle waiting for network or disk operations. It is always busy processing events, which is how it achieves high throughput and concurrency with a single thread.&lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;As a engineer you should get this question, that Redis&#39;s primary storage is volatile RAM. What mechanisms does it provide to ensure data persistence and durability, allowing it to recover from server restarts or crashes? &lt;/p&gt;

    &lt;h1 class=&quot;my-6 text-2xl font-serif&quot;&gt;Lets talk about Persistance&lt;/h1&gt;

    &lt;p class=&quot;font-serif text-lg mt-3&quot;&gt;Redis provides two distinct, complementary persistence mechanisms to save the in-memory dataset to non-volatile storage.&lt;/p&gt;

    &lt;ul class=&quot;font-serif text-lg list-disc ml-6 my-4&quot;&gt;
      &lt;li&gt;RDB (Redis Database): This persistence method creates point-in-time snapshots of the dataset. It works by forking a child process, as described previously. The child process writes the entire dataset to a single, compact, binary .rdb file on disk. This is efficient in terms of CPU and I/O. The main advantage is that the resulting file is perfect for backups and allows for fast data restoration on restart. The primary disadvantage is the potential for data loss: if the server crashes between two configured snapshots, all writes since the last snapshot are lost.&lt;/li&gt;

      &lt;li&gt;AOF (Append Only File): This method logs every write operation command that modifies the dataset. These commands are appended to an appendonly.aof file. Upon restart, Redis re-executes these commands in sequence to reconstruct the original dataset. Durability is controlled by the appendfsync configuration:

        
        &lt;ul class=&quot;ml-4 list-decimal&quot;&gt;
          &lt;li&gt;always: Syncs after every write. Slowest but safest.&lt;/li&gt;

        &lt;li&gt;everysec: Syncs once per second. The recommended default, providing a good balance of speed and safety (max 1 second of data loss).&lt;/li&gt;

        &lt;li&gt;no: Lets the OS decide when to flush. Fastest but least safe.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;


    &lt;/ul&gt;

    &lt;p class=&quot;font-serif text-lg mt-3&quot;&gt;To prevent the AOF file from growing indefinitely, Redis can automatically rewrite it in the background. It forks a child process that writes the minimal set of commands needed to recreate the current dataset into a new, temporary AOF file, which is then atomically swapped with the old one.&lt;/p&gt;

    &lt;p class=&quot;font-serif text-lg mt-3&quot;&gt;For maximum durability, it is common practice to use both AOF for near-real-time persistence and RDB for periodic backups.&lt;/p&gt;

    &lt;p class=&quot;font-serif text-lg mt-3&quot;&gt;Lets take a some good use cases of redis in production grade application&lt;/p&gt;

    &lt;p class=&quot;font-serif text-lg mt-3&quot;&gt;First which is commonly known and used by every developers and engineers out there, &lt;span class=&quot;font-bold&quot;&gt;Redis as cache layer&lt;/span&gt;.&lt;/p&gt;

    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets//redis/basic-sys.png&quot; class=&quot;my-10&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

    &lt;p class=&quot;font-serif text-lg mt-3&quot;&gt;Lets say you have a web application where users frequently view their profiles fetching this data from a disk based database like MySQL everytime can be slow instead we can use redis to cache the user profile data so when a user requests their profile the application first checks redis, if the desired data is in redis it&#39;s a &lt;span class=&quot;font-bold&quot;&gt;cache hit&lt;/span&gt; it is returned immediately, if the data is not in redis it&#39;s a &lt;span class=&quot;font-bold&quot;&gt;cache miss&lt;/span&gt; the cache miss the application fetches it from the primary database stores it in redis and then returns it to the user. The data in redis can have &lt;span class=&quot;font-bold&quot;&gt;TTL&lt;/span&gt; or &lt;span class=&quot;font-bold&quot;&gt;Time To Live&lt;/span&gt; so it can automatically expire after a certain time for example say 15 to 20 minutes to ensure fresh is there all the time.&lt;/p&gt;

    &lt;p class=&quot;font-serif text-lg mt-3&quot;&gt;Second scenario is using &lt;span class=&quot;font-bold&quot;&gt;Redis as Database&lt;/span&gt; specially for use cases where speed and low latency are very much important, just like building a gaming application.&lt;/p&gt;

    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/redis/rdb.png&quot; class=&quot;my-10&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

    &lt;p class=&quot;text-lg font-serif&quot;&gt;Here we need to maintain a realtime leaderboard where player scores are constantly updated and we need to display the top 10 players instantly. So here we can use redis as sorted set data structure to store player scores, each player score is added to the sorted set with their ID as the key and the score as the value this automatically sorts the scores so we can quickly retrieve the top 10 players using a single command like &lt;span class=&quot;font-bold&quot;&gt;ZREVRANGE leaderboard 0 9&lt;/span&gt;. Redis can then process this data to disk using RDB or AOF to ensure durability. &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;What internal data structures and optimizations allow it to store complex data types with minimal overhead?&lt;/p&gt;

    &lt;h1 class=&quot;text-2xl font-serif my-7&quot;&gt;Memory Management&lt;/h1&gt;

    &lt;p class=&quot;font-serif text-lg&quot;&gt;Redis&#39;s memory efficiency stems from its use of custom, highly-optimized data structures and dynamic encoding strategies.&lt;/p&gt;

    &lt;ul class=&quot;text-lg font-serif mt-4 ml-4 list-disc&quot;&gt;
      &lt;li&gt; Redis does not use standard C-style null-terminated strings. Instead, it uses its own SDS structure. An SDS &lt;span class=&quot;font-bold&quot;&gt;(Simple Dynamic String)&lt;/span&gt; is a struct that contains metadata (like the length of the string and the total allocated memory) followed by a byte array holding the actual data. This design provides several advantages which are&lt;/li&gt;

      &lt;ul&gt;
        &lt;li&gt;O(1) Length Lookup: The length is stored directly in the struct, avoiding the need to scan the entire string.&lt;/li&gt;

        &lt;li&gt;When an SDS is grown, it allocates more memory than immediately required (e.g., 1MB of free space for a 1MB string), so subsequent appends may not require a new reallocation and memory copy.&lt;/li&gt;
      &lt;/ul&gt;

      &lt;li&gt;Redis dynamically switches internal encodings for a data type based on the data&#39;s size and content to save memory. For example &lt;/li&gt;

      &lt;ul class=&quot;ml-4 list-disc&quot;&gt;
        &lt;li&gt;A Hash with few, small elements might be encoded as a ziplist (or listpack in newer versions), which stores all elements in a single, contiguous block of memory with no pointers, drastically reducing overhead. As the hash grows, Redis automatically converts it to a full hashtable for better performance on large datasets.&lt;/li&gt;

        &lt;li&gt;A Set containing only integers may be encoded as an intset, a specialized data structure that stores integers in a sorted array without any overhead.&lt;/li&gt;

        &lt;li&gt;Small Sorted Sets can also be encoded as a ziplist.&lt;/li&gt;
      &lt;/ul&gt;
    &lt;/ul&gt;


    &lt;p class=&quot;font-serif text-lg mt-4&quot;&gt;That&#39;s all from my side for the very first part of deep diving into redis, we got more parts for redis to explore for next few blogs :) Hope I was able to add few value to your today&#39;s learning :)&lt;/p&gt;


    &lt;hr class=&quot;my-10&quot;&gt;
    
  

</description><link>https://mrinalxdev.github.io/mrinalxblogs/blogs/redis.html</link><guid isPermaLink="false">https://mrinalxdev.github.io/mrinalxblogs/blogs/redis.html</guid><pubDate>Invalid Date</pubDate><author>Mrinal</author></item><item><title>Distributed Systems 101 : From a Beginners POV</title><description>&lt;hr class=&quot;mt-3&quot;&gt;

    &lt;h1 class=&quot;text-4xl mt-[57px] mb-3 font-serif&quot;&gt;
      Distributed Systems 101 : From a Beginners POV
    &lt;/h1&gt;
    &lt;span class=&quot;text-sm text-gray-500&quot;&gt;8th August, 2025&lt;/span&gt;

    &lt;p class=&quot;text-lg font-serif mt-6&quot;&gt;
      Distributed Systems is one best topics which I encounter on daily basis. A
      collection of computers or nodes which are independent have to work
      together to perform a task, isn&#39;t this alone so much interesting to know
      how does it all work behind the scene ??
    &lt;/p&gt;

    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/distributed-systems/banner.png&quot; class=&quot;w-[70%] mx-auto my-10&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

    &lt;h1 class=&quot;text-2xl font-serif&quot;&gt;The Foundation&lt;/h1&gt;

    &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;
      For the very simple start, distributed system is a collection of
      independent computers or we also call it nodes, that appear to users as a
      single coherent (as one) system. These computers communicate over a
      network to coordinate their actions and share resources.
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;
      But the fundamental challenge is making multiple independent computers
      work together seamlessly while dealing with network delays, failures and
      inconsistency
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;
      Cool isn&#39;t it, but what happens when these independent computers can&#39;t
      agree on something ?? What happens then ??
    &lt;/p&gt;

    &lt;h1 class=&quot;text-2xl font-serif my-7&quot;&gt;
      Why distributed systems can&#39;t be perfect ?
    &lt;/h1&gt;

    &lt;p class=&quot;text-lg font-serif&quot;&gt;
      When independent computers in a distributed system can&#39;t agree, it creates
      a conflict that must be resolved to main system reliability. This
      challenge is addressed by the CAP theorem, which states that a distributed
      system can only guarantee two out of three properties which is
      &lt;span class=&quot;font-bold&quot;&gt;Consistency&lt;/span&gt; this ensure all nodes have the
      same data at the same time,
      &lt;span class=&quot;font-bold&quot;&gt;Availability&lt;/span&gt; ensures every request receives
      a response, and &lt;span class=&quot;font-bold&quot;&gt;Partition Tolerance&lt;/span&gt; ensures
      the system continues to operate despite network failures. Now according to
      this theorem we need to have 2/3 ratio and sacrifice one :(
    &lt;/p&gt;

    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/distributed-systems/cap.png&quot; class=&quot;w-[60%] my-10 mx-auto&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

    &lt;p class=&quot;text-lg font-serif&quot;&gt;
      Here comes another one, network partition (P) will happen in any real
      distributed system. Internet get cut, routers fail, data centers lose
      connectivity. So we must choose between C and A
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;
      Consistency focused systems (CP), like banking databases, ensures all
      nodes have the same accurate data, such as correct account balances, even
      if it means temporarily halting operations during a failure (that means
      sacrificing A of CAP). For example, MongoDB stops accepting updates during
      network issues to maintain data accuracy
    &lt;/p&gt;

    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/distributed-systems/CP.png&quot; class=&quot;my-10&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

    &lt;p class=&quot;text-lg font-serif&quot;&gt;
      Whereas, Availability focused systems like DNS or Amazon&#39;s shopping cart,
      keep operating despite failure, even if it risks delivering slightly
      outdated information (that means sacrificing C of CAP). For example an old
      IP address or an inconsistent cart count
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;
      Everything is cool, but if we have to choose between consistency and
      availability, how do we actually make that choice in practice?
    &lt;/p&gt;

    &lt;h1 class=&quot;text-2xl font-serif my-6&quot;&gt;
      The Spectrum of &quot;Good Enough&quot; | Consistency Models
    &lt;/h1&gt;

    &lt;p class=&quot;text-lg font-serif&quot;&gt;
      The answer lies in selecting the right consistency model a set of rules
      defining how “consistent” the system’s data needs to be. Different
      applications have different needs. &lt;span&gt;Strong Consistency&lt;/span&gt; ensures
      that every read retrieves the latest write, providing a unified view of
      data across all nodes. This is serious for systems like banking databases,
      where showing an outdated account balance could cause serious issues.
      Traditional databases like PostgreSQL often use this model, but it comes
      at a cost: slower response times and reduced availability during network
      issues, as the system waits to ensure all nodes agree. &lt;br&gt;
      &lt;span class=&quot;font-bold&quot;&gt;Eventual Consistency&lt;/span&gt; prioritizes
      availability, allowing temporary differences in data across nodes, with
      the promise that updates will sync over time. For example, in Amazon’s
      DynamoDB or email systems, a sent message might take a moment to appear
      everywhere, but the system stays operational. This model suits
      applications where slight delays are acceptable, offering high
      availability and the ability to scale easily. &lt;br&gt;
      &lt;span class=&quot;font-bold&quot;&gt;Casual Consistency&lt;/span&gt; ensures that events with
      a cause-and-effect relationship are seen in the correct order. Like on
      social media platforms, everyone sees a reply after its original post, but
      unrelated posts might appear in different orders for different users. This
      strikes a balance between strict consistency and flexibility, maintaining
      logical order for related actions without requiring instant global
      agreement. &lt;br&gt;
      &lt;span class=&quot;font-bold&quot;&gt;Session Consistency&lt;/span&gt; ensures that within a
      single user session, a user sees their own changes immediately. For
      example, when we upload a photo to a platform like Facebook, we see it
      right away, even if it takes a moment to appear for others. This model
      enhances user experience by prioritizing personal consistency while
      allowing slight delays for others. &lt;br&gt;
      &lt;span&gt;&lt;/span&gt;
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;Why &quot;Eventual Consistency&quot; wins ??&lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;
      Most successful companies, especially those operating at massive scale,
      lean toward eventual consistency. Why? Users rarely notice brief delays in
      data syncing, and the high availability and scalability it offers outweigh
      the need for instant consistency in many cases. Systems like Amazon’s
      shopping cart or WhatsApp prioritize staying online and responsive, even
      if it means occasional, minor inconsistencies. By carefully choosing a
      consistency model that aligns with their priorities, companies ensure
      their distributed systems are both reliable and efficient, meeting user
      needs without overcomplicating the infrastructure.
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;
      This makes sense, but how do we actually implement these consistency
      guarantees ?? What happens under the hood when we&#39;re trying to keep data
      synchronized across multiple machines?
    &lt;/p&gt;

    &lt;h1 class=&quot;font-serif text-2xl my-7&quot;&gt;Getting Computers to Agree | Consensus Algorithms&lt;/h1&gt;

    &lt;p class=&quot;text-lg font-serif&quot;&gt;Here consensus algorithms work in, they are the mechanisms that allow nodes to agree on shared state, even when some are unreliable. Consensus algorithms ensure everyone ends up on the same page&lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;The challenge, often called the Byzantine Generals Problem, tells the core issue: a group of generals (nodes) must agree to attack or retreat together, but some messages might get lost, and some generals could even act maliciously. In distributed systems, nodes face similar obstacles—network delays, crashes, or even intentional sabotage and still need to reach a unified decision.&lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;One widely used solution is the &lt;span class=&quot;font-bold&quot;&gt;Raft algorithm&lt;/span&gt;, which simplifies consensus by electing a leader. The process works in three steps: nodes vote to select a leader, the leader handles all client requests and replicates them to follower nodes, and changes are finalized only when a majority of nodes confirm they’ve received them. For example &lt;span class=&quot;font-bold&quot;&gt;etcd&lt;/span&gt;, a key-value store used by Kubernetes, relies on Raft to maintain consistent cluster state across nodes, ensuring reliable coordination even if some nodes fail.&lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;Another approach is the &lt;span class=&quot;font-bold&quot;&gt;Paxos algorithm&lt;/span&gt;, favored in academic settings and used by systems like Google’s Chubby lock service. Paxos is robust, handling complex failure scenarios, but it’s harder to implement due to its complexity. &lt;br&gt; &lt;wbr&gt;here malicious nodes are a concern, like in blockchain, the &lt;span class=&quot;font-bold&quot;&gt;Practical Byzantine Fault Tolerance (PBFT)&lt;/span&gt; algorithm steps in. PBFT ensures agreement even when some nodes behave dishonestly, though it’s slower and more resource-intensive.&lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;Few Notes on trade offs we are making while using these&lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;Raft is fast and straightforward but assumes nodes fail innocently. PBFT handles malicious nodes but sacrifices speed. Proof of Work offers high security at the cost of efficiency.&lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;Okay, so we can get computers to agree on things, but what about the actual data ?? How do we store and retrieve information across multiple machines efficiently ??&lt;/p&gt;

    &lt;h1 class=&quot;text-2xl font-serif my-7&quot;&gt;Data Partitioning and Sharding&lt;/h1&gt;

    &lt;p class=&quot;text-lg font-serif&quot;&gt;I have written an overview of data partitioning in this blog &lt;a class=&quot;italic underline underline-offset-4&quot; href=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/system-design.html&quot;&gt;System Design 101&lt;/a&gt; you can check this out too. &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;To handle massive datasets in distributed systems, data partitioning or sharding splits information across multiple machines, enabling scalability and faster queries. &lt;span class=&quot;font-bold&quot;&gt;Range Based Partitioning&lt;/span&gt; divides data into segments based on a key’s value range, such as sorting user records by surname. For example, one node might store surnames A–F, another G–M, and a third N–Z. This approach shines for range queries, like finding all users with surnames starting with “C,” as the system knows exactly which node to check. However, it can lead to uneven data distribution if some ranges are more populated like having many “Singh”s in one partition causing bottlenecks.&lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;&lt;span class=&quot;font-bold&quot;&gt;Hash-Based Partitioning &lt;/span&gt; uses a hash function to evenly distribute data across nodes. Like, a user ID might be hashed and assigned to one of several partitions, ensuring a balanced spread. If user ID 12345 hashes to partition 1 and 67890 to partition 3, the load stays roughly equal across nodes. This method excels for scalability and uniform data distribution, making it ideal for systems like Apache Cassandra.&lt;/p&gt;

    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/distributed-systems/hash-partition.png&quot; class=&quot;w-[70%] my-10 mx-auto&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

    &lt;p class=&quot;text-lg font-serif&quot;&gt;The downside? Range queries become slower, as the system may need to check all partitions, since hashed values don’t preserve order.&lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;&lt;span class=&quot;font-bold&quot;&gt;Directory Based Partitioning&lt;/span&gt; relies on a lookup service to track where each piece of data is stored. Instead of calculating a partition based on the data itself, the system queries a directory to find the right node. Amazon’s DynamoDB uses this approach to route data efficiently using partition keys. This method offers flexibility, as it can adapt to complex data placement needs, but the lookup service must be fast and reliable to avoid becoming a performance bottleneck.&lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;All these are cool for storing data, but how do we ensure our data doesn&#39;t disappear when machines fail ??&lt;/p&gt;


    &lt;h1 class=&quot;text-2xl font-serif my-7&quot;&gt;Replication&lt;/h1&gt;

    &lt;p class=&quot;text-lg font-serif&quot;&gt;It plays as a major role, replication is technique that create multiple copies of data across different nodes to ensure fault tolerance. Like keeping copies of vital documents in a safe deposit box and the cloud, replication ensures your data remains accessible and secure even if a machine goes offline. &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;There are types of replications too (I am way too cooked while writing this)&lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;&lt;span class=&quot;font-bold&quot;&gt;Master-Slave (Primary - Replica) Replication&lt;/span&gt; &lt;br&gt; In this model, one primary server handles all write operations, while multiple replica servers handle read requests. The primary server sends updates to the replicas, which store copies of the data. For example, MySQL’s master-slave setup uses this approach. A client writes to the primary, and the changes are copied to replicas, from which clients can read. This setup is straightforward, ensures consistent writes through a single source of truth, and scales well for read-heavy workloads, but if the primary server fails, writes are disrupted until a new primary is chosen. Additionally, replication lag can lead to slightly outdated data on replicas&lt;/p&gt;

    
    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/distributed-systems/master-slave.png&quot; class=&quot;my-10 mx-auto&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
    &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;&lt;span class=&quot;font-bold&quot;&gt;Master - Master (Multi Primary) Replication&lt;/span&gt; &lt;br&gt;
    Here, multiple servers can handle both reads and writes, synchronizing changes between them. Systems like CouchDB or MySQL’s master-master configuration use this model, allowing clients to interact with any primary node. This is useful for geographically distributed systems, where users in different regions can write to nearby servers. This eliminates a single point of failure for writes and improves scalability for both reads and writes but synchronizing writes across multiple primaries can lead to conflicts, requiring complex resolution mechanisms, and managing the system is more challenging. 
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-5&quot;&gt;&lt;span class=&quot;font-bold&quot;&gt;Peer to Peer Replication&lt;/span&gt; &lt;br&gt; 
    In peer-to-peer replication, all nodes are equal, capable of handling both read and write requests, with data copied to multiple nodes. Systems like Apache Cassandra and Amazon DynamoDB use this approach, often relying on consensus algorithms to maintain consistency. Any node can serve client requests, and data is replicated to a set number of nodes for redundancy.
    &lt;/p&gt;

    
    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/distributed-systems/master-master.png&quot; class=&quot;my-10 mx-auto&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
    &lt;p class=&quot;font-serif text-lg&quot;&gt;Small Note : MySQL’s master-slave setup is ideal for read-heavy applications, while Cassandra’s peer-to-peer model suits systems needing high availability across regions&lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;replication protects our data, but what about when users are scattered across the globe ?? How do we serve them efficiently from the closes location ??&lt;/p&gt;

    &lt;h1 class=&quot;text-2xl font-serif my-7&quot;&gt;Content Delivery Network (CDNs)&lt;/h1&gt;

    &lt;p class=&quot;text-lg font-serif&quot;&gt;CDNs comes in clutch to deliver content from the closest possible location, slashing latency and performance. Like you can imagine the frustration of waiting for a webpage to load, CDNs solves this by bringing data closer to you.&lt;/p&gt;

    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/distributed-systems/cdn.png&quot; class=&quot;mx-auto my-10&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

    &lt;p class=&quot;text-lg font-serif&quot;&gt;The problem starts with physics: data travels through fiber optic cables at about 200,000 km/second, which sounds fast but isn’t enough for today’s expectations. For instance, a round trip from New York to Sydney (~15,000 km) takes ~75ms just for light to travel, and with routing, processing, and queuing, you’re looking at 200–300ms of delay. Yet, users demand web pages to load in under 100ms. CDNs resolve this by acting like local coffee shops scattered worldwide, serving content quickly instead of relying on one distant central hub.&lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;CDNs work by deploying edge servers, or Points of Presence (PoPs), in strategic locations: major cities like New York and Tokyo (Tier 1), regional hubs like Austin or Osaka (Tier 2), and even smaller cities for popular content (Tier 3). When a user requests content, like a video or webpage, the request goes to the nearest edge server. If the content is cached there, it’s served instantly. If not, the edge server fetches it from the origin server, caches it locally, and delivers it to the user, minimizing future delays.&lt;/p&gt;

    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/distributed-systems/cdn-working.png&quot; class=&quot;w-[70%] my-10 mx-auto&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;CDNs works well with static content, like images, CSS, JavaScript files, videos, or software downloads, which can be cached for hours, days, or weeks since they rarely change. Dynamic content, like personalized web pages or real-time API responses, is trickier. Solutions like Edge-Side Includes (ESI) cache page templates while inserting dynamic parts, or caching different versions for user segments, help balance speed and accuracy.&lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;Netflix serves 95% of its traffic through its custom CDN, Open Connect, with appliances in ISP data centers. Popular shows are pre-positioned worldwide based on predictive algorithms, ensuring fast streaming with minimal buffering. YouTube delivers billions of hours of video daily, caching popular videos at edge servers and adjusting quality based on your connection. Steam uses CDNs to distribute massive game downloads, saturating your connection while reducing strain on central servers.&lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;There are challenges here too, one is known as &lt;span class=&quot;font-bold&quot;&gt;Cache Invalidation&lt;/span&gt; updating cached content when the origin changes—is notoriously tough. Strategies like Time To Live (TTL) for automatic expiration, manual purging, or URL versioning help. &lt;span class=&quot;font-bold&quot;&gt;Cache coherence&lt;/span&gt; is another different edge servers might hold different versions of content. Eventual consistency or regional cache hierarchies can address this.&lt;/p&gt;


    &lt;p class=&quot;text-lg font-serif mt-6&quot;&gt;All this from my side on Distributed System 101 : Part 1, for the part 2 I have some interesting topics to cover and some use cases to share which I learned during my internships. Hope I was able to make you learn something new today .. HAVE A GREAT DAY AHEAD :)&lt;/p&gt;

  
    
    &lt;hr class=&quot;my-10&quot;&gt;
    
  

</description><link>https://mrinalxdev.github.io/mrinalxblogs/blogs/distributed-systems.html</link><guid isPermaLink="false">https://mrinalxdev.github.io/mrinalxblogs/blogs/distributed-systems.html</guid><pubDate>Invalid Date</pubDate><author>Mrinal</author></item><item><title>Sockets 101 : From a Beginners POV</title><description>&lt;hr class=&quot;mt-3&quot;&gt;

    &lt;h1 class=&quot;text-4xl mt-[57px] mb-3 font-serif&quot;&gt;
      Sockets 101 : From a Beginners POV
    &lt;/h1&gt;
    &lt;span class=&quot;text-sm text-gray-500&quot;&gt;26th July, 2025&lt;/span&gt;

    &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;
      When your web browser fetches this blog post, when your messaging app
      sends a text, or when you stream a video, there&#39;s a fundamental mechanism
      at work, we call it SOCKETS
    &lt;/p&gt;

    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/websockets/banner.png&quot; class=&quot;w-[75%] mx-auto my-10&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

    &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;
      Sockets are the endpoints of communication channels that allow processes
      to exchange data, whether they&#39;re on the same machine or across the globe.
      At its core, a socket is an abstraction provided by the operating system
      that represents one endpoint of a bidirectional communication link. The
      socket API, originally developed for Unix systems, has become the standard
      interface for network programming across virtually.
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      Socket operate at different layers of the network stack. TCP sockets
      provide reliable, ordered data delivery with error detection and
      correction. UDP sockets offer faster, connection less communication
      without delivery guarantees
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;
      The socket abstraction hides the complexity of network protocols, hardware
      interface and routing decisions. When you create a socket, the operating
      systems allocates kernel data structures, assigns network resources, and
      manages the connection lifecycle. This abstraction enables developers to
      focus on application logic rather than low-level network details.
    &lt;/p&gt;

    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/websockets/abstraction.png&quot; class=&quot;my-10 w-[60%] mx-auto&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

    &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;
      But how do processes on the same machine communicate without going through
      the network stack at all ??
    &lt;/p&gt;

    &lt;h1 class=&quot;text-2xl font-serif my-7&quot;&gt;The Silent Communication Channel&lt;/h1&gt;

    &lt;p class=&quot;text-lg font-serif&quot;&gt;
      An anonymous pipe is a unidirectional communication channel that exists
      only in memory. Unlike named pipes (FIFOs), anonymous pipes have no
      filesystem representation and can only be shared between related
      processes, typically a parent and its child processes
    &lt;/p&gt;

    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/websockets/layers.png&quot; class=&quot;mx-auto w-[70%] my-10&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      The kernel implements anonymous pipes using a circular buffer, typically
      64KB on Linux systems. This buffer acts as a temporary storage area
      between the writing and reading processes. When the buffer fills up,
      writers are blocked until readers consume data, providing natural flow
      control.
    &lt;/p&gt;

    &lt;details class=&quot;my-6 bg-gray-700 text-gray-100 rounded-lg overflow-x-auto&quot;&gt;
      &lt;summary class=&quot;p-4 cursor-pointer font-serif text-lg outline-none&quot;&gt;
        Anonymous Pipes working in C
      &lt;/summary&gt;
      &lt;pre class=&quot;font-mono text-sm p-4&quot;&gt;&lt;code class=&quot;language-c&quot;&gt;#include &amp;lt;&quot;stdio.h&quot;&amp;gt;
#include &amp;lt;&quot;unistd.h&quot;&amp;gt;
#include &amp;lt;&quot;stdio.h&quot;&amp;gt;

int main() {
    int pipefd[2];
    pid_t pid;
    
    // creating a pipe
    if (pipe(pipefd) == -1) {
        perror(&quot;pipe&quot;);
        return 1;
    }
    
    pid = fork();
    if (pid == 0) {
        // child process - writer
        close(pipefd[0]); // Close read end
        write(pipefd[1], &quot;Hello from child&quot;, 16);
        close(pipefd[1]);
    } else {
        //parent process - reader
        char buffer[20];
        close(pipefd[1]); // Close write end
        read(pipefd[0], buffer, 16);
        printf(&quot;Received: %s\n&quot;, buffer);
        close(pipefd[0]);
    }
    
    return 0;
}
&lt;/code&gt;&lt;/pre&gt;
    &lt;/details&gt;

    &lt;p class=&quot;font-serif text-lg&quot;&gt;
      The pipe() system call creates two file descriptors: pipefd[0] for reading
      and pipefd[1] for writing. The kernel maintains a circular buffer
      (typically 64KB on Linux) between these endpoints. When the buffer fills
      up, writers block until readers consume data.
    &lt;/p&gt;

    &lt;p class=&quot;font-serif text-lg mt-3&quot;&gt;
      The creation of anonymous pipes involves the operating system allocating
      two file descriptors: one for reading and one for writing. These
      descriptors can be inherited by child processes through fork(), enabling
      parent-child communication. The pipe exists as long as at least one
      process holds either descriptor open.
    &lt;/p&gt;

    &lt;p class=&quot;font-serif text-lg mt-4&quot;&gt;
      Unlike network sockets, pipes operate entirely within kernel memory,
      making them extremely fast for local communication. There&#39;s no network
      protocol overhead, no packet serialization, and no routing decisions just
      direct memory-to-memory data transfer managed by the kernel.
    &lt;/p&gt;

    &lt;p class=&quot;font-serif text-lg mt-2&quot;&gt;
      But what exactly are these file descriptors that pipes return, and how
      does the operating system manage them?
    &lt;/p&gt;

    &lt;h1 class=&quot;text-2xl font-serif my-6&quot;&gt;File Descriptors&lt;/h1&gt;

    &lt;p class=&quot;font-serif text-lg&quot;&gt;
      File descriptors are the answer to our previous question about how the OS
      manages communication endpoints. A file descriptor (fd) is a non-negative
      integer that serves as an abstract handle for accessing files, sockets,
      pipes, devices, and other I/O resources in Unix-like systems.
    &lt;/p&gt;

    &lt;p class=&quot;font-serif text-lg mt-3&quot;&gt;
      The operating system maintains a file descriptor table for each process,
      mapping fd numbers to kernel data structures that contain the actual
      details about the resource. This indirection allows the kernel to manage
      resources centrally while providing processes with simple integer handles.
    &lt;/p&gt;

    &lt;!-- &lt;details class=&quot;my-6 bg-gray-700 text-gray-100 rounded-lg overflow-x-auto&quot;&gt;
  &lt;summary class=&quot;p-4 cursor-pointer font-serif text-lg outline-none&quot;&gt;
    File Descriptors in C
  &lt;/summary&gt;
  &lt;pre class=&quot;font-mono text-sm p-4&quot;&gt;
&lt;code class=&quot;language-c&quot;&gt;#include &lt;sys/socket.h&gt;
#include &lt;netinet/in.h&gt;
#include &lt;unistd.h&gt;

int main() {
    // Creating different types of file descriptors
    
    // 1. Socket file descriptor
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    printf(&quot;Socket fd: %d\n&quot;, sockfd);
    
    // 2. File descriptor for regular file
    int filefd = open(&quot;/tmp/test.txt&quot;, O_CREAT | O_RDWR, 0644);
    printf(&quot;File fd: %d\n&quot;, filefd);
    
    // 3. Pipe file descriptors
    int pipefd[2];
    pipe(pipefd);
    printf(&quot;Pipe read fd: %d, write fd: %d\n&quot;, pipefd[0], pipefd[1]);
    
    // All can be used with same I/O operations
    char buffer[100];
    read(sockfd, buffer, 100);    // Read from socket
    read(filefd, buffer, 100);    // Read from file
    read(pipefd[0], buffer, 100); // Read from pipe
    
    close(sockfd);
    close(filefd);
    close(pipefd[0]);
    close(pipefd[1]);
    
    return 0;
}
&lt;/code&gt;&lt;/pre&gt;
    &lt;/details&gt; --&gt;

    &lt;details class=&quot;my-6 bg-gray-700 text-gray-100 rounded-lg overflow-x-auto&quot;&gt;
      &lt;summary class=&quot;p-4 cursor-pointer font-serif text-lg outline-none&quot;&gt;
        File Descriptors in C
      &lt;/summary&gt;
      &lt;pre class=&quot;font-mono text-sm p-4&quot;&gt;&lt;code class=&quot;language-c&quot;&gt;#include &amp;lt;&quot;sys/socket.h&quot;&amp;gt;
#include &amp;lt;&quot;netinet/in.h&quot;&amp;gt;
#include &amp;lt;&quot;unistd.h&quot;&amp;gt;

int main() {
    // Creating different types of file descriptors
    
    // 1. Socket file descriptor
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    printf(&quot;Socket fd: %d\n&quot;, sockfd);
    
    // 2. File descriptor for regular file
    int filefd = open(&quot;/tmp/test.txt&quot;, O_CREAT | O_RDWR, 0644);
    printf(&quot;File fd: %d\n&quot;, filefd);
    
    // 3. Pipe file descriptors
    int pipefd[2];
    pipe(pipefd);
    printf(&quot;Pipe read fd: %d, write fd: %d\n&quot;, pipefd[0], pipefd[1]);
    
    // All can be used with same I/O operations
    char buffer[100];
    read(sockfd, buffer, 100);    // Read from socket
    read(filefd, buffer, 100);    // Read from file
    read(pipefd[0], buffer, 100); // Read from pipe
    
    close(sockfd);
    close(filefd);
    close(pipefd[0]);
    close(pipefd[1]);
    
    return 0;
}
&lt;/code&gt;
  &lt;/pre&gt;
    &lt;/details&gt;
    &lt;p class=&quot;text-lg font-serif&quot;&gt;
      Whether we are dealing with network socket, a regular file, or a pipe, you
      use the same system calls : read(), write(), close(), and others. This
      abstraction is what makes Unix-like systems so powerful for system
      programming.
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif&quot;&gt;
      File descriptors are process-specific resources. When a process forks, the
      child inherits copies of the parent&#39;s file descriptors, but subsequent
      operations on these descriptors in either process don&#39;t affect the other.
      However, both processes share the same underlying kernel file description,
      so operations like changing file position affect both processes.
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif&quot;&gt;
      The kernel enforces limits on file descriptors to prevent resource
      exhaustion. Each process has both soft and hard limits on the maximum
      number of open file descriptors. These limits can typically be viewed and
      modified using system utilities, and they&#39;re crucial for server
      applications that handle many concurrent connections.
    &lt;/p&gt;

    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/websockets/kfd.png&quot; class=&quot;my-10 mx-auto&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

    &lt;p class=&quot;font-serif text-lg&quot;&gt;
      But how do we efficiently monitor multiple file descriptors for activity
      without constantly polling them?
    &lt;/p&gt;

    &lt;h1 class=&quot;text-2xl font-serif my-7&quot;&gt;Managing Multiple Connections&lt;/h1&gt;

    &lt;p class=&quot;text-lg font-serif&quot;&gt;
      I/O multiplexing solves the challenge of monitoring multiple file
      descriptors simultaneously. Instead of creating separate threads for each
      connection or constantly polling each descriptor, multiplexing allows a
      single thread to wait for activity on multiple file descriptors at once.
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      The fundamental problem that I/O multiplexing addresses is the blocking
      nature of I/O operations. When a process calls read() on a socket with no
      available data, the process blocks until data arrives. For a server
      handling multiple clients, this means either dedicating one thread per
      connection or missing data from other connections.
    &lt;/p&gt;
    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/websockets/multi.png&quot; class=&quot;my-10 mx-auto&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

    &lt;p class=&quot;text-lg font-serif&quot;&gt;
      I/O multiplexing enables a single process to efficiently handle multiple
      input/output sources, such as sockets, without blocking on each one
      individually. The application process communicates with an I/O multiplexer
      (e.g., select, poll, or epoll), requesting it to monitor a set of file
      descriptors (FDs) in this case, three socket FDs. The multiplexer
      continuously checks the status of these FDs and blocks the process until
      one or more of them become &quot;ready&quot; (e.g., data is available to read). When
      an event occurs on a monitored FD (like FD 1 or FD 3 becoming readable),
      the multiplexer returns control to the process with information about
      which FDs are ready.
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      The process can then perform non-blocking I/O only on those specific
      descriptors. This mechanism allows efficient use of system resources by
      avoiding the need to spawn multiple threads or processes for each I/O
      source.
    &lt;/p&gt;

    &lt;details class=&quot;my-6 bg-gray-700 text-gray-100 rounded-lg overflow-x-auto&quot;&gt;
      &lt;summary class=&quot;p-4 cursor-pointer font-serif text-lg outline-none&quot;&gt;
        epoll() in C
      &lt;/summary&gt;
      &lt;pre class=&quot;font-mono text-sm p-4&quot;&gt;&lt;code class=&quot;language-c&quot;&gt;#include &amp;lt;&quot;sys/epoll.h&quot;&amp;gt;

int epoll_fd = epoll_create1(0);
struct epoll_event event, events[MAX_EVENTS];

// Add socket to epoll
event.events = EPOLLIN;
event.data.fd = socket_fd;
epoll_ctl(epoll_fd, EPOLL_CTL_ADD, socket_fd, &amp;amp;event);

// Wait for events
int num_events = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
&lt;/code&gt;
  &lt;/pre&gt;
    &lt;/details&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      I/O multiplexing enables servers to handle thousands of concurrent
      connections with a single thread, but what about connections that are
      meant to be temporary and don&#39;t need to persist?
    &lt;/p&gt;

    &lt;h1 class=&quot;font-serif text-2xl my-6&quot;&gt;The Temporary Connection Endpoints&lt;/h1&gt;

    &lt;p class=&quot;font-serif text-lg mt-2&quot;&gt;
      Ephemeral ports provide the answer to temporary connections. When a client
      application creates an outbound connection, it doesn&#39;t typically specify a
      source port. Instead, the operating system automatically assigns an
      ephemeral (temporary) port from a predefined range.
    &lt;/p&gt;

    &lt;p class=&quot;font-serif text-lg mt-2&quot;&gt;
      The ephemeral port range varies by operating system. Linux typically uses
      ports 32768-60999, while Windows uses 1024-65535. These ranges are
      configurable and represent a balance between providing enough ports for
      concurrent connections while reserving lower-numbered ports for well-known
      services.
    &lt;/p&gt;

    &lt;details class=&quot;my-6 bg-gray-700 text-gray-100 rounded-lg overflow-x-auto&quot;&gt;
      &lt;summary class=&quot;p-4 cursor-pointer font-serif text-lg outline-none&quot;&gt;
        How ephermal ports work in practice
      &lt;/summary&gt;
      &lt;pre class=&quot;font-mono text-sm p-4&quot;&gt;&lt;code class=&quot;language-c&quot;&gt;#include &amp;lt;&quot;sys/socket.h&quot;&amp;gt;
#include &amp;lt;&quot;netinet/in.h&quot;&amp;gt;
#include &amp;lt;&quot;arpa/inet.h&quot;&amp;gt;

int main() {
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in server_addr, local_addr;
    socklen_t addr_len = sizeof(local_addr);
    
    // Connect to server (OS assigns ephemeral port automatically)
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(80);
    inet_pton(AF_INET, &quot;93.184.216.34&quot;, &amp;amp;server_addr.sin_addr); // example.com
    
    connect(sockfd, (struct sockaddr*)&amp;amp;server_addr, sizeof(server_addr));
    
    // Check what ephemeral port was assigned
    getsockname(sockfd, (struct sockaddr*)&amp;amp;local_addr, &amp;amp;addr_len);
    printf(&quot;Local port assigned: %d\n&quot;, ntohs(local_addr.sin_port));
    
    close(sockfd);
    return 0;
}
&lt;/code&gt;
  &lt;/pre&gt;
    &lt;/details&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      Ephemeral port allocation strategies differ across operating systems. Some
      use sequential allocation, starting from the lowest available port in the
      range. Others use random or hash-based algorithms to distribute ports more
      evenly across the range. The choice affects performance, security, and the
      ability to handle high connection rates.
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      The lifecycle of an ephemeral port begins when a client initiates an
      outbound connection. The operating system selects an available port, binds
      it to the socket, and uses it as the source port for the connection. When
      the connection closes, the port enters a TIME_WAIT state before becoming
      available for reuse.
    &lt;/p&gt;

    &lt;div class=&quot;my-10&quot;&gt;
      &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/websockets/ephermal.png&quot; class=&quot;my-10 mx-auto&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
      &lt;p class=&quot;text-sm text-gray-500 text-center font-serif&quot;&gt;
        TCP (Transmission Control Protocol) state machine, which outlines the
        various states a TCP connection transitions through during its
        lifecycle.
      &lt;/p&gt;
    &lt;/div&gt;

    &lt;p class=&quot;font-serif text-lg&quot;&gt;
      TIME_WAIT is a crucial TCP state that prevents delayed packets from a
      closed connection from interfering with new connections using the same
      port pair. The typical TIME_WAIT duration is twice the Maximum Segment
      Lifetime (MSL), often 60-120 seconds. This can become a limiting factor
      for applications making many short-lived connections.
    &lt;/p&gt;

    &lt;p class=&quot;font-serif text-lg&quot;&gt;
      Port exhaustion occurs when all ephemeral ports are in use or in TIME_WAIT
      state. This is a common problem for high-traffic proxy servers or
      applications making many outbound connections. Solutions include using
      multiple IP addresses, tuning TIME_WAIT parameters, or implementing
      connection pooling.
    &lt;/p&gt;

    &lt;h1 class=&quot;font-serif text-2xl my-6&quot;&gt;Raw Sockets and custom protocols&lt;/h1&gt;

    &lt;p class=&quot;font-serif text-lg&quot;&gt;
      What about scenarios where we need to implement custom protocols or handle
      raw network data?
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-2&quot;&gt;
      Raw sockets provide direct access to network protocols below the transport
      layer, allowing applications to craft custom packets or implement
      protocols not directly supported by the operating system.
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-2&quot;&gt;
      Operating systems typically provide TCP and UDP socket abstractions that
      handle most application needs. However, some applications require
      lower-level access to implement custom protocols, perform network
      analysis, or bypass standard protocol limitations.
    &lt;/p&gt;

    &lt;details class=&quot;my-6 bg-gray-700 text-gray-100 rounded-lg overflow-x-auto&quot;&gt;
      &lt;summary class=&quot;p-4 cursor-pointer font-serif text-lg outline-none&quot;&gt;
        Implementing raw sockets
      &lt;/summary&gt;
      &lt;pre class=&quot;font-mono text-sm p-4&quot;&gt;&lt;code class=&quot;language-c&quot;&gt;#include &amp;lt;&quot;sys/socket.h&quot;&amp;gt;
#include &amp;lt;&quot;netinet/ip.h&quot;&amp;gt;
#include &amp;lt;&quot;netinet/tcp.h&quot;&amp;gt;
#include &amp;lt;&quot;arpa/inet.h&quot;&amp;gt;

// Creating a raw socket (requires root privileges)
int create_raw_socket() {
    int sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
    if (sockfd &amp;lt; 0) {
        perror(&quot;raw socket creation failed&quot;);
        return -1;
    }
    
    // Tell kernel not to add IP header (we&#39;ll craft it ourselves)
    int one = 1;
    if (setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &amp;amp;one, sizeof(one)) &amp;lt; 0) {
        perror(&quot;setsockopt IP_HDRINCL failed&quot;);
        return -1;
    }
    
    return sockfd;
}

// Craft a custom TCP packet
void craft_tcp_packet(char *packet, const char *src_ip, const char *dst_ip, 
                      uint16_t src_port, uint16_t dst_port) {
    struct iphdr *ip_header = (struct iphdr *)packet;
    struct tcphdr *tcp_header = (struct tcphdr *)(packet + sizeof(struct iphdr));
    
    // Fill IP header
    ip_header-&amp;gt;version = 4;
    ip_header-&amp;gt;ihl = 5;
    ip_header-&amp;gt;tos = 0;
    ip_header-&amp;gt;tot_len = htons(sizeof(struct iphdr) + sizeof(struct tcphdr));
    ip_header-&amp;gt;id = htons(12345);
    ip_header-&amp;gt;frag_off = 0;
    ip_header-&amp;gt;ttl = 64;
    ip_header-&amp;gt;protocol = IPPROTO_TCP;
    ip_header-&amp;gt;check = 0; // Kernel will calculate
    inet_pton(AF_INET, src_ip, &amp;amp;ip_header-&amp;gt;saddr);
    inet_pton(AF_INET, dst_ip, &amp;amp;ip_header-&amp;gt;daddr);
    
    // Fill TCP header
    tcp_header-&amp;gt;source = htons(src_port);
    tcp_header-&amp;gt;dest = htons(dst_port);
    tcp_header-&amp;gt;seq = htonl(1000);
    tcp_header-&amp;gt;ack_seq = 0;
    tcp_header-&amp;gt;doff = 5;
    tcp_header-&amp;gt;syn = 1; // SYN flag
    tcp_header-&amp;gt;window = htons(65535);
    tcp_header-&amp;gt;check = 0; // Calculate separately
    tcp_header-&amp;gt;urg_ptr = 0;
}
&lt;/code&gt;
  &lt;/pre&gt;
    &lt;/details&gt;

    &lt;p class=&quot;text-lg font-serif mt-&quot;&gt;
      Raw sockets operate at the IP level or even lower, depending on the socket
      type and options. Applications using raw sockets must manually construct
      protocol headers and handle details normally managed by the operating
      system, such as checksums, fragmentation, and addressing.
    &lt;/p&gt;

    &lt;h1 class=&quot;text-2xl font-serif my-6&quot;&gt;
      Notes on Performance and Optimization
    &lt;/h1&gt;

    &lt;p class=&quot;text-lg font-serif&quot;&gt;
      Buffer management significantly impacts socket performance. The
      bandwidth-delay product determines optimal buffer sizes - the product of
      network bandwidth and round-trip time indicates how much data should be
      &quot;in flight&quot; for maximum throughput. Undersized buffers limit throughput,
      while oversized buffers waste memory.
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      Connection reuse and pooling strategies reduce the overhead of connection
      establishment and teardown. HTTP/1.1 introduced persistent connections to
      avoid repeated TCP handshakes. HTTP/2 multiplexes multiple streams over
      single connections. Connection pools maintain ready-to-use connections to
      frequently accessed servers.
    &lt;/p&gt;

    &lt;details class=&quot;my-6 bg-gray-700 text-gray-100 rounded-lg overflow-x-auto&quot;&gt;
      &lt;summary class=&quot;p-4 cursor-pointer font-serif text-lg outline-none&quot;&gt;
        Connection reusing and pooling
      &lt;/summary&gt;
      &lt;pre class=&quot;font-mono text-sm p-4&quot;&gt;&lt;code class=&quot;language-c&quot;&gt;typedef struct {
    int *sockets;
    int count;
    int capacity;
    pthread_mutex_t mutex;
} connection_pool_t;

int get_connection(connection_pool_t *pool, const char *host, int port) {
    pthread_mutex_lock(&amp;amp;pool-&amp;gt;mutex);
    
    if (pool-&amp;gt;count &amp;gt; 0) {
        // Reuse existing connection
        int sockfd = pool-&amp;gt;sockets[--pool-&amp;gt;count];
        pthread_mutex_unlock(&amp;amp;pool-&amp;gt;mutex);
        return sockfd;
    }
    
    pthread_mutex_unlock(&amp;amp;pool-&amp;gt;mutex);
    
    // Create new connection
    return create_connection(host, port);
}

void return_connection(connection_pool_t *pool, int sockfd) {
    pthread_mutex_lock(&amp;amp;pool-&amp;gt;mutex);
    
    if (pool-&amp;gt;count &amp;lt; pool-&amp;gt;capacity) {
        pool-&amp;gt;sockets[pool-&amp;gt;count++] = sockfd;
    } else {
        close(sockfd); // Pool full, close connection
    }
    
    pthread_mutex_unlock(&amp;amp;pool-&amp;gt;mutex);
}
&lt;/code&gt;
  &lt;/pre&gt;
    &lt;/details&gt;

    &lt;p class=&quot;text-lg font-serif&quot;&gt;
      Memory mapping can improve performance for applications that repeatedly
      access the same data. By mapping files into memory, applications can avoid
      system call overhead and benefit from the operating system&#39;s virtual
      memory management.
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      Zero-copy operations eliminate unnecessary data copying between user and
      kernel space. Techniques like sendfile() allow the kernel to transfer data
      directly from files to sockets without involving user-space buffers. This
      approach significantly improves performance for file serving applications.
    &lt;/p&gt;

    &lt;details class=&quot;my-6 bg-gray-700 text-gray-100 rounded-lg overflow-x-auto&quot;&gt;
      &lt;summary class=&quot;p-4 cursor-pointer font-serif text-lg outline-none&quot;&gt;
        Zero Copy operations
      &lt;/summary&gt;
      &lt;pre class=&quot;font-mono text-sm p-4&quot;&gt;        &lt;code class=&quot;language-c&quot;&gt;#include &lt;sys sendfile.h=&quot;&quot;&gt;
          
          // Use sendfile() for efficient file transfers
          ssize_t send_file_efficient(int out_fd, int in_fd, off_t offset, size_t count) {
            return sendfile(out_fd, in_fd, &amp;amp;offset, count);
          }
          
          // Use splice() for pipe-to-socket transfers (Linux)
          ssize_t splice_data(int fd_in, int fd_out, size_t len) {
            int pipefd[2];
            pipe(pipefd);
            
            // Move data from input to pipe
            ssize_t bytes_in = splice(fd_in, NULL, pipefd[1], NULL, len, SPLICE_F_MOVE);
            
            // Move data from pipe to output
            ssize_t bytes_out = splice(pipefd[0], NULL, fd_out, NULL, bytes_in, SPLICE_F_MOVE);
            
            close(pipefd[0]);
            close(pipefd[1]);
            
            return bytes_out;
          }
        &lt;/sys&gt;&lt;/code&gt;
      &lt;/pre&gt;
    &lt;/details&gt;

    &lt;p class=&quot;text-lg my-4 font-serif&quot;&gt;
      Network programming is ultimately about enabling communication between
      processes, whether they&#39;re on the same machine or across the globe. Hope I
      was able to add value to your today&#39;s learning :)
    &lt;/p&gt;
    &lt;hr class=&quot;my-10&quot;&gt;
    
  

</description><link>https://mrinalxdev.github.io/mrinalxblogs/blogs/sockets.html</link><guid isPermaLink="false">https://mrinalxdev.github.io/mrinalxblogs/blogs/sockets.html</guid><pubDate>Invalid Date</pubDate><author>Mrinal</author></item><item><title>Vector Database 101 : From a Beginners POV</title><description>&lt;hr class=&quot;mt-3&quot;&gt;

    &lt;h1 class=&quot;text-4xl mt-[57px] mb-3 font-serif&quot;&gt;
      Vector Database from a Beginners POV
    &lt;/h1&gt;
    &lt;span class=&quot;text-sm text-gray-500&quot;&gt;3rd July, 2025&lt;/span&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      Vector databases have been generating a lot of excitement lately, with
      companies raising hundreds of millions of dollars to develop them. Some
      even call them the new era of AI databases because they’re designed to
      handle complex data, like embeddings used in AI applications. They’re
      incredibly powerful and enable some amazing use cases, such as real-time
      recommendation systems or advanced search features. However, for many
      projects, using a vector database might be overkill, as simpler solutions
      could work just fine.
    &lt;/p&gt;

    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/vector-db/banner.png&quot; class=&quot;w-[65%] mx-auto my-10&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

    &lt;p class=&quot;text-lg font-serif&quot;&gt;
      About 80% of the data we encounter today is unstructured, meaning it
      doesn’t neatly fit into the rows and columns of traditional relational
      databases. This includes things like social media posts, images, videos,
      audio files, and even emails or text documents. Unlike structured data,
      such as numbers or predefined categories, unstructured data is messy and
      complex, making it hard to maintain and query using conventional
      databases. Lets take an example of a image if we want to put this into
      relational database in order to search for similar
    &lt;/p&gt;

    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/vector-db/1stpara.png&quot; class=&quot;w-[80%] my-10 mx-auto&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

    &lt;p class=&quot;text-lg font-serif&quot;&gt;
      What ends up up happening is that often we manually assign keywords or
      tags to it because from the pixel values alone we cannot search for
      similar images and the same hodls true for unstructured text blobs or
      audio and video data.
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif&quot;&gt;
      So to ease this up here comes
      &lt;span class=&quot;font-bold&quot;&gt;vector embeddings&lt;/span&gt; or
      &lt;span class=&quot;font-bold&quot;&gt;vector databases&lt;/span&gt;
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      Vector databases solve this problem by understanding that &quot;maroon,&quot;
      &quot;orange,&quot; and &quot;black&quot; are mathematically similar, even though they&#39;re
      different words. They store information as numbers (vectors) and use math
      to find similar items instead of looking for exact matches.
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      This way it helps how we build smart applications, from search engines
      that understand what we really mean to, recommendation systems that knows
      our preferences better than we do. But how exactly do it turn words,
      images, and other data into numbers that computers can compare
      mathematically?
    &lt;/p&gt;

    &lt;h1 class=&quot;text-2xl font-serif my-7&quot;&gt;Converting Data into Numbers&lt;/h1&gt;
    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      It uses clever algorithms to so called the vector embeddings this is done
      using a Machine Learning Model, a vector embedding is simply a list of
      numbers, like [0.2, 0.8, 0.1, 0.9]. We can take it as coordinates that
      describe where something sits in a mathematical space.
    &lt;/p&gt;

    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/vector-db/vector.png&quot; class=&quot;my-10&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
    &lt;p class=&quot;font-serif mt-4 text-lg&quot;&gt;
      Taking colors as example like, each position in our color vector
      represents
      &lt;span class=&quot;font-bold&quot;&gt;[first number (how much red 0.0 = minimum red, 1.0 = maximum red),
        second number(how much green), third number (how much blue)]&lt;/span&gt;
      we call rgb color code so for Red it becomes
      &lt;span class=&quot;font-bold&quot;&gt;[1.0, 0.0, 0.0]&lt;/span&gt; for Blue is becomes
      &lt;span&gt;[0.0, 0.0, 0.1]&lt;/span&gt; for green it becomes
      &lt;span class=&quot;font-bold&quot;&gt;[0.0, 1.0, 0.0]&lt;/span&gt; and for purple it becomes
      &lt;span class=&quot;font-bold&quot;&gt;[0.5, 0.0, 0.5]&lt;/span&gt;. Now if we want to find
      colors similar to purple, we can use math to calculate which other colors
      are closest. Purple [0.5, 0.0, 0.5] is mathematically closer to red than
      to green. How ?? in purple if we look into closely [0.5 (50% is red), 0.0
      (0% green), 0.5 (50% blue)]
    &lt;/p&gt;

    &lt;p class=&quot;font-serif text-lg mt-4&quot;&gt;
      For text, the process is more complex but follows the same principle. We
      use machine learning models to convert words into vectors of hundreds or
      thousands of numbers. These numbers capture the meaning and relationships
      between words. For example: &quot;Sedan&quot; might become [0.2, 0.8, 0.1, 0.9, 0.3,
      ...], &quot;SUV&quot; might become [0.3, 0.7, 0.2, 0.8, 0.4, ...], &quot;Chocolates&quot;
      might become [0.9, 0.1, 0.8, 0.2, 0.1, ...]. Notice how &quot;SEDAN&quot; and &quot;SUV&quot;
      have similar numbers, while &quot;Chocolates&quot; has very different numbers. This
      mathematical similarity reflects their real-world relationship.

      &lt;br&gt;
      But once we have these vectors, how do we actually calculate which ones
      are similar to each other?
    &lt;/p&gt;

    &lt;h1 class=&quot;text-2xl font-serif my-7&quot;&gt;How Computers Find &quot;Close&quot; Vectors&lt;/h1&gt;

    &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;
      When we have vectors, we need mathematical formulas to measure how similar
      they are. The most common methods are cosine similarityand euclidean
      distance (I have only tried these twoo
      &lt;span class=&quot;font-mono&quot;&gt;T_T&lt;/span&gt; )
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;
      &lt;span class=&quot;font-bold&quot;&gt;Cosine Similarity&lt;/span&gt; measures the angle
      between two vectors. Two vectors pointing in the same direction have a
      cosine similarity of 1.0, while vectors pointing in opposite directions
      have a similarity of -1.0. The formula is
      &lt;span class=&quot;text-xl&quot;&gt;\(\text{cosine_similarity} = \frac{\mathbf{A} \cdot
        \mathbf{B}}{|\mathbf{A}| \times |\mathbf{B}|}\)&lt;/span&gt;
    &lt;/p&gt;

    &lt;p class=&quot;font-serif text-lg mt-3&quot;&gt;
      Let&#39;s calculate this for two simple vectors:
    &lt;/p&gt;
    &lt;ul class=&quot;list-disc font-serif text-lg mt-3 ml-5&quot;&gt;
      &lt;li&gt;Vector A = \([1, 2, 3]\)&lt;/li&gt;
      &lt;li&gt;Vector B = \([2, 4, 6]\)&lt;/li&gt;
    &lt;/ul&gt;

    &lt;p class=&quot;font-serif text-lg mt-3&quot;&gt;
      First, we calculate the dot product (A · B): \(A · B = (1×2) + (2×4) +
      (3×6) = 2 + 8 + 18 = 28\)
    &lt;/p&gt;
    &lt;p class=&quot;font-serif text-lg mt-3&quot;&gt;Next, we calculate the magnitudes:&lt;/p&gt;

    &lt;ul class=&quot;font-serif text-lg mt-2&quot;&gt;
      &lt;li&gt;\(|A| = √(1² + 2² + 3²) = √(1 + 4 + 9) = √14 ≈ 3.74\)&lt;/li&gt;
      &lt;li&gt;\(|B| = √(2² + 4² + 6²) = √(4 + 16 + 36) = √56 ≈ 7.48\)&lt;/li&gt;
    &lt;/ul&gt;

    &lt;p class=&quot;font-serif text-lg mt-3&quot;&gt;
      Finally: cosine_similarity = \(28 / (3.74 × 7.48) ≈ 1.0\)
    &lt;/p&gt;
    &lt;p class=&quot;font-serif text-lg mt-1&quot;&gt;
      This result of 1.0 makes sense because vector B is exactly twice vector A,
      so they point in the same direction.
    &lt;/p&gt;

    &lt;p class=&quot;mt-5 font-serif text-lg&quot;&gt;
      &lt;span class=&quot;font-bold&quot;&gt;Euclidean distance&lt;/span&gt; is a fundamental metric
      used in vector databases to measure the &quot;straight-line&quot; distance between
      two points (or vectors) in a multi-dimensional space. It is derived from
      the Pythagorean theorem and is particularly useful for quantifying the
      similarity or dissimilarity between data points represented as vectors,
      such as embeddings for text, images, or other data types in a vector
      database. \[\text{distance} = \sqrt{(A_1 - B_1)^2 + (A_2 - B_2)^2 + \cdots
      + (A_n - B_n)^2}\]
    &lt;/p&gt;

    &lt;div class=&quot;my-10&quot;&gt;
      &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/vector-db/convertion.png&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

      &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/vector-db/euclidean.png&quot; class=&quot;w-[60%] mx-auto&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
    &lt;/div&gt;

    &lt;p class=&quot;font-serif mt-5 text-lg&quot;&gt;
      In vector databases, Euclidean distance is used to find nearest neighbors
      or cluster similar items. Like, when searching for similar documents or
      images, the database compares the Euclidean distance between their vector
      representations (embeddings). Smaller distances indicate greater
      similarity.
    &lt;/p&gt;

    &lt;p class=&quot;font-serif mt-5 text-lg&quot;&gt;
      Time to face a canon event question : How do we organize millions of
      vectors so we can find similar ones quickly ?? &lt;br&gt;
      here comes
    &lt;/p&gt;

    \(\text{distance} = \sqrt{\sum_{i=1}^{n} (A_i - B_i)^2}\)

    &lt;h1 class=&quot;text-2xl font-serif my-7&quot;&gt;Vector Indexing&lt;/h1&gt;
    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      Vector databases faces challenges while storing millions of vectors, they
      need an system to find similar vector quickly.
    &lt;/p&gt;
    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      This is where vector indexing comes in. An index is like a sophisticate
      filing system that organizes vectors based on thier similarity, allowing
      the database to skip most vectors during a search. Its similar to what
      database indexing we have discussed during
      &lt;a href=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/system-design.html&quot;&gt;&lt;span class=&quot;italic underline underline-offset-2&quot;&gt;System Design 101&lt;/span&gt;&lt;/a&gt;
    &lt;/p&gt;

    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/vector-db/vector-indexing.png&quot; class=&quot;my-10&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      where indexes (e.g., B-trees or hash tables) optimize retrieval by
      organizing data for efficient access. In vector databases, specialized
      indexing techniques like Approximate Nearest Neighbor (ANN) algorithms,
      hierarchical navigable small world (HNSW) graphs, or product quantization
      are often used to balance speed, accuracy, and memory usage, making sure
      that our database is scalable and performant similarity searches even with
      massive datasets.
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      Now that we understand the math, how do these calculations help us build
      useful applications?
    &lt;/p&gt;

    &lt;h1 class=&quot;text-2xl font-serif my-7&quot;&gt;Where Vector Math Solves Problems&lt;/h1&gt;

    &lt;p class=&quot;text-lg font-serif&quot;&gt;
      &lt;span class=&quot;font-bold&quot;&gt;Search Engines&lt;/span&gt; are one of the best examples
      when we search for &quot;how to fix a broken faucet,&quot; the search engine
      converts your query into a high-dimensional vector using techniques like
      word embeddings or transformer models. It then compares this query vector
      to vectors representing web pages, finding those with similar semantic
      content, even if they use different phrasing, such as &quot;repair leaky tap&quot;
      or &quot;plumbing maintenance.&quot; By leveraging vector similarity, search engines
      deliver relevant results that align with the user&#39;s intent, regardless of
      exact keyword matches.
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      Instagram converts photos into vectors that describe colors, shapes,
      objects, and even abstract features like artistic style. These vectors
      enable the platform to recommend visually similar photos, detect duplicate
      uploads, or identify content that violates community guidelines.
      Similarly, video platforms use vector representations to analyze scenes or
      frames, enabling features like content-based video recommendations or
      automated highlight detection.
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      The math remains the same in all these cases, we&#39;re calculating similarity
      between vectors using the formulas we learned earlier. The difference is
      in how we create the vectors and what we do with the similarity results.
    &lt;/p&gt;

    &lt;p class=&quot;mt-4 text-lg font-serif&quot;&gt;
      This is all from myside on Vector Database. Hope I was able to add few
      value to your today&#39;s learning :)
    &lt;/p&gt;
    &lt;hr class=&quot;my-10&quot;&gt;
    
  

</description><link>https://mrinalxdev.github.io/mrinalxblogs/blogs/vector-db.html</link><guid isPermaLink="false">https://mrinalxdev.github.io/mrinalxblogs/blogs/vector-db.html</guid><pubDate>Invalid Date</pubDate><author>Mrinal</author></item><item><title>Graphs 101 : From a Beginners POV</title><description>&lt;hr class=&quot;mt-3&quot;&gt;

    &lt;h1 class=&quot;text-4xl mt-[57px] mb-3 font-serif&quot;&gt;
      Graph : From a Beginners POV
    &lt;/h1&gt;
    &lt;span class=&quot;text-sm text-gray-500&quot;&gt;1st July, 2025&lt;/span&gt;

    &lt;p class=&quot;font-serif mt-5 text-lg&quot;&gt;
      So a graph data structure is like a map of connections, like a bunch of
      dots that represent stuffs like people, cities or even web pages. Then
      you&#39;ve got lines which connects these dots, showing some kind off
      relationships, like who&#39;s friends with who or which cities have direct
      roads between them.
    &lt;/p&gt;

    &lt;div class=&quot;&quot;&gt;
      &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/graphs/banner.png&quot; class=&quot;w-[60%] mx-auto my-10&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
    &lt;/div&gt;

    &lt;p class=&quot;font-serif text-lg mt-3&quot;&gt;Unlike linear data structures like arrays or linked lists, graphs represent relationships between entities in way that mirrors how connections are formed. At its core, graph is simply collection of nodes connected by edges. Its like  a network where each point represents an entity, and the lines between them represent relationships or connections&lt;/p&gt;
    &lt;h1 class=&quot;font-serif text-2xl my-6&quot;&gt;Covering the fundamentals&lt;/h1&gt;

    &lt;p class=&quot;font-serif text-lg mt-3&quot;&gt;Graphs are simple and flexible, every graph consists of just two fundamental components which are vertices and edges. Vertices are the individual data point or nodes that store information, while edges are the connections that define relationships between these vertices.&lt;/p&gt;

    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/graphs/fundamentals.png&quot; class=&quot;&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

    &lt;p class=&quot;font-serif text-lg mt-4&quot;&gt;Taking an example like LinkedIN. Yeahh LinkedIN XDD Each user would be represented as a vertex, containing information like name, age and location. The friendship/connection between users would be represented as edges connecting these vertices. This simple model can represent millions of users and their complex web of relationships&lt;/p&gt;

    &lt;p class=&quot;font-serif text-lg mt-2&quot;&gt;Edges can carry additional information too. In a weighted graph, each edge has numerical value associated with it. For instance we in a road network, vertices might represent cities, and edges might represent roads with weights indicating the distance or travel time between cities. This additional information transforms a simple connection into a rich data relationship.&lt;/p&gt;

    &lt;p class=&quot;font-serif text-lg mt-3&quot;&gt;Now that we understand the basic building blocks, how do we actually store and organize this information in computer memory?&lt;/p&gt;
    &lt;h1 class=&quot;font-serif text-2xl my-4&quot;&gt;Graph Representation and Memory&lt;/h1&gt;

    &lt;p class=&quot;font-serif text-lg mt-3&quot;&gt;When it comes to storing graphs in computer memory, we have two primary approaches: adjacency matrices and adjacency lists. Each method has its own strengths and is suited for different scenarios, depending on whether the graph is directed or undirected. In a directed graph, edges have a direction, meaning the relationship from vertex A to vertex B is not necessarily reciprocal. In an undirected graph, edges are bidirectional, so an edge between A and B implies a mutual connection..&lt;/p&gt;

    &lt;p class=&quot;font-serif text-lg mt-2&quot;&gt;Adjacency matrices use a 2D array where entry (i,j) indicates whether there&#39;s an edge between vertex i and vertex j. For a graph with n vertices, this creates an n×n matrix. In an undirected graph, the matrix is symmetric because an edge from i to j implies an edge from j to i, whereas in a directed graph, the matrix may be asymmetric since edges are one-way. While this approach uses more memory (O(n²) space), it provides constant-time lookup (O(1)) to check if two vertices are connected, making it ideal for dense graphs or when frequent edge queries are needed.&lt;/p&gt;

    &lt;div class=&quot;mt-6 border rounded-xl p-4 bg-gray-900 text-white font-mono&quot; id=&quot;code-div-9&quot;&gt;
      &lt;div class=&quot;flex justify-between items-center border-b border-gray-700&quot;&gt;
        &lt;div class=&quot;flex&quot;&gt;
          &lt;button class=&quot;px-4 py-2 bg-gray-800 text-white font-semibold rounded-t-md focus:outline-none language-tab active&quot; data-lang=&quot;javascript&quot; onclick=&quot;switchLanguage( &#39;code-div-9&#39;)&quot;&gt;
            JavaScript
          &lt;/button&gt;
        &lt;/div&gt;
        &lt;button class=&quot;px-4 py-2 text-gray-400 hover:text-white focus:outline-none&quot; onclick=&quot;toggleCollapse(&#39;code-div-9&#39;)&quot;&gt;
          Expand
        &lt;/button&gt;
      &lt;/div&gt;
      &lt;div class=&quot;mt-4 code-content hidden&quot;&gt;
        &lt;pre id=&quot;code-javascript&quot; class=&quot;language-javascript&quot;&gt;&lt;code&gt;class AdjacencyMatrix {
  constructor(n) {
    this.numVertices = n;
    // Initialize a 2D matrix with false (no edges initially)
    this.matrix = new Array(n);
    for (let i = 0; i &amp;lt; n; i++) {
        this.matrix[i] = new Array(n).fill(false);
    }
}

    // Add an undirected edge between u and v
    addEdge(u, v) {
      this.matrix[u][v] = true;
      this.matrix[v][u] = true; // For undirected graph
    }

    // Check if there is an edge between u and v
    hasEdge(u, v) {
      return this.matrix[u][v];
    }
}


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

    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/graphs/matrix.png&quot; class=&quot;my-10&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

    &lt;p class=&quot;font-serif mt-3 text-lg&quot;&gt;Lets talk about some memory here, For n vertices, adjacency matrices require exactly n² memory locations, regardless of the actual number of edges. With boolean values, this means n²/8 bytes (since booleans can be packed). For a social network with 1 million users, this translates to 125 GB of memory just for the adjacency matrix, even if most users have only a few hundred connections.
      The memory layout is cache-friendly for row-wise access patterns, but checking all neighbors of a vertex requires scanning an entire row, touching n memory locations regardless of the actual degree.&lt;/p&gt;


    &lt;p class=&quot;font-serif text-lg mt-6&quot;&gt;Adjacency lists, conversely, store a graph by maintaining a list for each vertex, where each list contains the vertices adjacent to it. For an undirected graph, each edge appears in the lists of both vertices it connects, while in a directed graph, an edge from i to j appears only in i&#39;s list. This method is more memory-efficient for sparse graphs (O(V + E) space, where V is vertices and E is edges) but requires O(degree(v)) time to check if an edge exists, where degree(v) is the number of neighbors of vertex v.&lt;/p&gt;

    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/graphs/list.png&quot; class=&quot;my-10&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

    &lt;p class=&quot;font-serif mt-3 text-lg&quot;&gt;In adjaceny lists emory usage scales with O(V + E), where V is vertices and E is edges. For our million-user social network with an average of 300 connections per user, this requires only about 2.4 GB of memory - a 50x improvement over adjacency matrices.
      However, checking if a specific edge exists becomes O(degree) operation, requiring a linear search through the neighbor list. This can be optimized using hash sets instead of vectors for neighbor storage.&lt;/p&gt;

    
      &lt;div class=&quot;mt-6 border rounded-xl p-4 bg-gray-900 text-white font-mono&quot; id=&quot;code-div-2&quot;&gt;
      &lt;div class=&quot;flex justify-between items-center border-b border-gray-700&quot;&gt;
        &lt;div class=&quot;flex&quot;&gt;
          &lt;button class=&quot;px-4 py-2 bg-gray-800 text-white font-semibold rounded-t-md focus:outline-none language-tab active&quot; data-lang=&quot;javascript&quot; onclick=&quot;switchLanguage(&#39;code-div-2&#39;)&quot;&gt;
            JavaScript
          &lt;/button&gt;
        &lt;/div&gt;
        &lt;button class=&quot;px-4 py-2 text-gray-400 hover:text-white focus:outline-none&quot; onclick=&quot;toggleCollapse(&#39;code-div-2&#39;)&quot;&gt;
          Expand
        &lt;/button&gt;
      &lt;/div&gt;
      &lt;div class=&quot;mt-4 code-content hidden&quot;&gt;
        &lt;pre id=&quot;code-javascript&quot; class=&quot;language-javascript&quot;&gt;&lt;code&gt;class AdjacencyList {
    constructor(n) {
        this.numVertices = n;
        this.adjList = new Array(n);
        for (let i = 0; i &amp;lt; n; i++) {
            this.adjList[i] = []; // Initialize each vertex&#39;s neighbor list
        }
    }

    // Add an undirected edge between u and v
    addEdge(u, v) {
        this.adjList[u].push(v);
        this.adjList[v].push(u); // For undirected graph
    }

    // Get neighbors of vertex u
    getNeighbors(u) {
        return this.adjList[u];
    }
}

const graph = new AdjacencyList(5);

graph.addEdge(0, 1);
graph.addEdge(1, 2);
graph.addEdge(2, 3);

console.log(graph.getNeighbors(0)); // [1]
console.log(graph.getNeighbors(1)); // [0, 2]
console.log(graph.getNeighbors(2)); // [1, 3]
&lt;/code&gt;&lt;/pre&gt;
      &lt;/div&gt;
    &lt;/div&gt;


    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;With our data properly organized, what can actually do with these graph structures ??&lt;/p&gt;


    &lt;h1 class=&quot;text-2xl font-serif my-7&quot;&gt;Exploring Graphs&lt;/h1&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;Graph traversal algorithms are the foundation for most graph operations. They allow us to systematically visit every vertex in a graph, forming the basis for more complex algorithms. The two fundamental traversal methods are Depth-First Search (DFS) and Breadth-First Search (BFS).&lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-2&quot;&gt;For new audience (if any, yeah I am delusional) I have explained &lt;span class=&quot;font-bold&quot;&gt;Depth First Search&lt;/span&gt; and &lt;span class=&quot;font-bold&quot;&gt;Breadth First Search&lt;/span&gt; in my previous blog about &lt;a class=&quot;italic underline underline-offset-2&quot; href=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/algorithms.html&quot;&gt;Algorithms from Beginners POV&lt;/a&gt; do check it out. I will be just skimming through the topics here :))&lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;Depth-First Search explores a graph by going as deep as possible along each branch before backtracking. It&#39;s like we are exploring a maze by always taking the first available path and only turning back when we hit a dead end. DFS uses a stack (either explicitly or through recursion) to keep track of vertices to visit. This approach is excellent for problems like detecting cycles, finding connected components, or exploring all possible paths.&lt;/p&gt;

    &lt;!-- &lt;img src=&quot;./assets/dsa-2/dfs.png&quot; class=&quot;w-[40%]&quot; alt=&quot;&quot;&gt; --&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;Breadth-First Search, conversely, explores all vertices at the current depth before moving to vertices at the next depth level. It&#39;s like ripples spreading out from a stone dropped in water. BFS uses a queue to ensure vertices are visited in order of their distance from the starting point. This makes it perfect for finding the shortest path in unweighted graphs or for level-order traversals.&lt;/p&gt;

    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/dsa-2/bfs.png&quot; class=&quot;w-[55%] mx-auto my-10&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;These traversal methods sound useful, but how do they help us solve real-world problems like finding the shortest route between two locations?&lt;/p&gt;

    &lt;h1 class=&quot;font-serif text-2xl mt-4&quot;&gt;Finding the Optimal Route&lt;/h1&gt;

    &lt;p class=&quot;font-serif text-lg mt-3&quot;&gt;Finding the shortest path between two points is one of the most practical applications of graph algorithms. While BFS can find the shortest path in unweighted graphs, real-world scenarios often involve weighted edges where we need more sophisticated approaches.&lt;/p&gt;

    &lt;p class=&quot;font-serif text-lg mt-3&quot;&gt;Dijkstra&#39;s algorithm is the gold standard for finding shortest paths in weighted graphs with non-negative edge weights. It works by maintaining a set of vertices whose shortest distance from the source is known, gradually expanding this set by always choosing the vertex with the minimum tentative distance. Think of it as simultaneously exploring all possible routes from your starting point, but always prioritizing the most promising paths.&lt;/p&gt;

    &lt;video autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; class=&quot;mx-auto my-10 rounded-xl p-2&quot;&gt;&lt;source src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/graphs/dijkit.mp4&quot; type=&quot;video/mp4&quot;&gt;&lt;/video&gt;

    &lt;p class=&quot;font-serif text-lg mt-3&quot;&gt;The algorithm maintains a priority queue of vertices to visit, always processing the one with the smallest known distance first. As it visits each vertex, it updates the distances to its neighbors if a shorter path is found. This greedy approach guarantees finding the optimal solution.&lt;/p&gt;

    &lt;video autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; class=&quot;mx-auto my-10 rounded-xl&quot;&gt;&lt;source src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/graphs/dijkit2.mp4&quot; type=&quot;video/mp4&quot;&gt;&lt;/video&gt;

    &lt;p class=&quot;font-serif text-lg mt-3&quot;&gt;For graphs with negative edge weights, the Bellman-Ford algorithm provides a solution, though it&#39;s slower than Dijkstra&#39;s algorithm. It works by repeatedly relaxing all edges, gradually improving distance estimates until no further improvements are possible.&lt;/p&gt;

    &lt;p class=&quot;font-serif text-lg mt-2&quot;&gt;These algorithms power GPS navigation systems, network routing protocols, and any application where finding optimal paths is crucial.&lt;/p&gt;

    &lt;p class=&quot;font-serif text-lg mt-5&quot;&gt;Shortest paths are fascinating, but what about scenarios where we need to connect multiple points efficiently, like designing a network infrastructure ??&lt;/p&gt;

    &lt;h1 class=&quot;text-2xl font-serif my-7&quot;&gt;Connecting Everything Efficiently&lt;/h1&gt;
    &lt;p class=&quot;font-serif text-lg mt-3&quot;&gt;When we need to connect all vertices in a graph with the minimum total cost, we are looking for a Minimum Spanning Tree (MST). This is crucial in network design, where we want to ensure all nodes are connected while minimizing the total cost of connections.&lt;/p&gt;

    &lt;p class=&quot;font-serif text-lg mt-3&quot;&gt;A spanning tree of a graph is a subgraph that includes all vertices and is connected (you can reach any vertex from any other vertex) but contains no cycles. The minimum spanning tree is the spanning tree with the smallest total edge weight.&lt;/p&gt;

    &lt;!-- video  --&gt;

    &lt;!-- video end  --&gt;

    &lt;p class=&quot;font-serif text-lg mt-4 &quot;&gt;Kruskal&#39;s algorithm approaches this problem by sorting all edges by weight and adding them to the MST one by one, skipping any edge that would create a cycle. It uses a disjoint set data structure to efficiently detect cycles. This greedy approach works because the optimal solution always includes the cheapest available connection that doesn&#39;t create redundancy.&lt;/p&gt;

    &lt;video autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; class=&quot;mx-auto my-10 rounded-xl&quot;&gt;&lt;source src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/graphs/kruskal.mp4&quot; type=&quot;video/mp4&quot;&gt;&lt;/video&gt;

    &lt;p class=&quot;font-serif text-lg mt-3&quot;&gt;Prim&#39;s algorithm takes a different approach, starting with an arbitrary vertex and growing the MST by repeatedly adding the cheapest edge that connects a vertex in the MST to a vertex outside it. Both algorithms guarantee finding the optimal solution, but they approach the problem from different angles.&lt;/p&gt;

    &lt;div class=&quot;mt-6 border rounded-xl p-4 bg-gray-900 text-white font-mono&quot; id=&quot;code-div-6&quot;&gt;
      &lt;div class=&quot;flex justify-between items-center border-b border-gray-700&quot;&gt;
        &lt;div class=&quot;flex&quot;&gt;
          &lt;button class=&quot;px-4 py-2 bg-gray-800 text-white font-semibold rounded-t-md focus:outline-none language-tab active&quot; data-lang=&quot;javascript&quot; onclick=&quot;switchLanguage(&#39;code-div-6&#39;)&quot;&gt;
            JavaScript
          &lt;/button&gt;
        &lt;/div&gt;
        &lt;button class=&quot;px-4 py-2 text-gray-400 hover:text-white focus:outline-none&quot; onclick=&quot;toggleCollapse(&#39;code-div-6&#39;)&quot;&gt;
          Expand
        &lt;/button&gt;
      &lt;/div&gt;
      &lt;div class=&quot;mt-4 code-content hidden&quot;&gt;
        &lt;pre id=&quot;code-javascript&quot; class=&quot;language-javascript&quot;&gt;&lt;code&gt;class PriorityQueue {
    constructor() {
        this.items = [];
    }

    enqueue(item, priority) {
        this.items.push({ item, priority });
        this.items.sort((a, b) =&amp;gt; a.priority - b.priority);
    }

    dequeue() {
        return this.items.shift().item;
    }

    isEmpty() {
        return this.items.length === 0;
    }
}

function primMST(graph) {
    const vertices = Object.keys(graph);
    if (vertices.length === 0) return [];

    // Initialize data structures
    const parent = {};
    const key = {};
    const inMST = {};
    const pq = new PriorityQueue();

    // Initialize all keys to Infinity and parents to null
    vertices.forEach(vertex =&amp;gt; {
        key[vertex] = Infinity;
        parent[vertex] = null;
        inMST[vertex] = false;
    });

    // Start with the first vertex
    const startVertex = vertices[0];
    key[startVertex] = 0;
    pq.enqueue(startVertex, 0);

    while (!pq.isEmpty()) {
        const currentVertex = pq.dequeue();
        inMST[currentVertex] = true;

        // Explore all adjacent vertices
        for (const neighbor in graph[currentVertex]) {
            const weight = graph[currentVertex][neighbor];

            // If neighbor is not in MST and weight is less than current key
            if (!inMST[neighbor] &amp;amp;&amp;amp; weight &amp;lt; key[neighbor]) {
                parent[neighbor] = currentVertex;
                key[neighbor] = weight;
                pq.enqueue(neighbor, key[neighbor]);
            }
        }
    }

    // Construct the MST edges (excluding the root)
    const mst = [];
    for (const vertex in parent) {
        if (parent[vertex] !== null) {
            mst.push({
                from: parent[vertex],
                to: vertex,
                weight: graph[parent[vertex]][vertex]
            });
        }
    }

    return mst;
}

// using Prim&#39;s algorithm
const graph = {
    &#39;A&#39;: { &#39;B&#39;: 2, &#39;D&#39;: 6 },
    &#39;B&#39;: { &#39;A&#39;: 2, &#39;C&#39;: 3, &#39;D&#39;: 8, &#39;E&#39;: 5 },
    &#39;C&#39;: { &#39;B&#39;: 3, &#39;E&#39;: 7 },
    &#39;D&#39;: { &#39;A&#39;: 6, &#39;B&#39;: 8, &#39;E&#39;: 9 },
    &#39;E&#39;: { &#39;B&#39;: 5, &#39;C&#39;: 7, &#39;D&#39;: 9 }
};

const minimumSpanningTree = primMST(graph);
console.log(&quot;Minimum Spanning Tree Edges:&quot;);
console.log(minimumSpanningTree);
&lt;/code&gt;&lt;/pre&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;p class=&quot;font-serif text-lg mt-3&quot;&gt;These algorithms are essential in designing telecommunication networks, electrical grids, and any infrastructure where you need universal connectivity at minimum cost.&lt;/p&gt;

    &lt;h1 class=&quot;text-2xl my-6 font-serif&quot;&gt;Directed Graphs and Network Flow&lt;/h1&gt;
    &lt;p class=&quot;font-serif text-lg&quot;&gt;Directed graphs introduce concepts like in-degree and out-degree (the number of incoming and outgoing edges for each vertex). They also enable topological sorting, which arranges vertices in a linear order such that for every directed edge from vertex A to vertex B, A appears before B in the ordering. This is crucial for scheduling tasks with dependencies.&lt;/p&gt;

    &lt;p class=&quot;font-serif text-lg mt-3&quot;&gt;Network flow problems take directed graphs further by adding capacity constraints to edges. Like a network of pipes where each pipe can only carry a certain amount of fluid. The maximum flow problem asks: what&#39;s the maximum amount of flow you can push from a source to a sink?&lt;/p&gt;

    &lt;p class=&quot;font-serif text-lg mt-3&quot;&gt;The Ford-Fulkerson algorithm solves this by repeatedly finding augmenting paths (paths from source to sink with available capacity) and pushing flow along them until no more augmenting paths exist. This approach has applications in traffic management, resource allocation, and even matching problems.&lt;/p&gt;

    &lt;div class=&quot;mt-6 border rounded-xl p-4 bg-gray-900 text-white font-mono&quot; id=&quot;code-div-7&quot;&gt;
      &lt;div class=&quot;flex justify-between items-center border-b border-gray-700&quot;&gt;
        &lt;div class=&quot;flex&quot;&gt;
          &lt;button class=&quot;px-4 py-2 bg-gray-800 text-white font-semibold rounded-t-md focus:outline-none language-tab active&quot; data-lang=&quot;javascript&quot; onclick=&quot;switchLanguage(&#39;code-div-7&#39;)&quot;&gt;
            JavaScript
          &lt;/button&gt;
        &lt;/div&gt;
        &lt;button class=&quot;px-4 py-2 text-gray-400 hover:text-white focus:outline-none&quot; onclick=&quot;toggleCollapse(&#39;code-div-7&#39;)&quot;&gt;
          Expand
        &lt;/button&gt;
      &lt;/div&gt;
      &lt;div class=&quot;mt-4 code-content hidden&quot;&gt;
        &lt;pre id=&quot;code-javascript&quot; class=&quot;language-javascript&quot;&gt;&lt;code&gt;/**
* Ford-Fulkerson Algorithm for Maximum Flow in a Flow Network
* 
* This implementation uses the Edmonds-Karp approach (BFS for finding augmenting paths)
* to ensure polynomial time complexity O(VE²).
* 
* The algorithm finds the maximum possible flow from a source node to a sink node
* in a directed graph where each edge has a capacity.
*/

class FlowNetwork {
    /**
    * Initialize the flow network with adjacency list representation
    * @param {number} vertices - Number of vertices in the graph
    */
    constructor(vertices) {
        this.V = vertices; // Number of vertices
        this.graph = new Array(vertices); // Residual graph
        
        // Initialize adjacency list for each vertex
        for (let i = 0; i &amp;lt; vertices; i++) {
            this.graph[i] = new Array(vertices).fill(0);
        }
    }

    /**
    * Add an edge to the flow network with a given capacity
    * @param {number} u - Source vertex
    * @param {number} v - Destination vertex
    * @param {number} capacity - Maximum flow capacity of the edge
    */
    addEdge(u, v, capacity) {
        this.graph[u][v] = capacity; // Forward edge capacity
        this.graph[v][u] = 0; // Backward edge initially 0 (for residual graph)
    }

    /**
    * Breadth-First Search to find if there&#39;s a path from source to sink with available capacity
    * Also stores the path found in parent[] array
    * @param {number} s - Source vertex
    * @param {number} t - Sink vertex
    * @param {number[]} parent - Array to store the path
    * @returns {boolean} - True if path exists, False otherwise
    */
    bfs(s, t, parent) {
        // Create a visited array and mark all vertices as not visited
        const visited = new Array(this.V).fill(false);
        
        // Create a queue for BFS, enqueue source vertex
        const queue = [];
        queue.push(s);
        visited[s] = true;
        parent[s] = -1; // Source has no parent

        // Standard BFS loop
        while (queue.length &amp;gt; 0) {
            const u = queue.shift();

            // Explore all adjacent vertices
            for (let v = 0; v &amp;lt; this.V; v++) {
                // If vertex not visited and residual capacity &amp;gt; 0
                if (!visited[v] &amp;amp;&amp;amp; this.graph[u][v] &amp;gt; 0) {
                    // If we reach the sink, we have a path
                    if (v === t) {
                        parent[v] = u;
                        return true;
                    }
                    
                    queue.push(v);
                    parent[v] = u;
                    visited[v] = true;
                }
            }
        }

        // We didn&#39;t reach the sink
        return false;
    }

    /**
    * Main function implementing Ford-Fulkerson algorithm
    * @param {number} source - Source vertex
    * @param {number} sink - Sink vertex
    * @returns {number} - Maximum flow from source to sink
    */
    fordFulkerson(source, sink) {
        // Validate input
        if (source &amp;lt; 0 || source &amp;gt;= this.V || sink &amp;lt; 0 || sink &amp;gt;= this.V) {
            throw new Error(&quot;Invalid source or sink vertex&quot;);
        }
        if (source === sink) {
            return 0; // No flow if source and sink are same
        }

        // This array is filled by BFS and stores path
        const parent = new Array(this.V).fill(-1);
        let maxFlow = 0; // Initialize max flow to 0

        // Augment the flow while there is path from source to sink
        while (this.bfs(source, sink, parent)) {
            // Find minimum residual capacity of the edges along the path
            let pathFlow = Infinity;
            
            // Traverse from sink to source using parent array
            for (let v = sink; v !== source; v = parent[v]) {
                const u = parent[v];
                pathFlow = Math.min(pathFlow, this.graph[u][v]);
            }

            // Update residual capacities of the edges and reverse edges
            for (let v = sink; v !== source; v = parent[v]) {
                const u = parent[v];
                // Subtract path flow from forward edge
                this.graph[u][v] -= pathFlow;
                // Add path flow to reverse edge
                this.graph[v][u] += pathFlow;
            }

            // Add path flow to overall flow
            maxFlow += pathFlow;
        }

        return maxFlow;
    }
}


function main() {
    // Create a flow network with 6 vertices (0 to 5)
    const g = new FlowNetwork(6);

    // Add edges with capacities
    g.addEdge(0, 1, 16); // s -&amp;gt; v1
    g.addEdge(0, 2, 13); // s -&amp;gt; v2
    g.addEdge(1, 2, 10); // v1 -&amp;gt; v2
    g.addEdge(1, 3, 12); // v1 -&amp;gt; v3
    g.addEdge(2, 1, 4);  // v2 -&amp;gt; v1
    g.addEdge(2, 4, 14); // v2 -&amp;gt; v4
    g.addEdge(3, 2, 9);  // v3 -&amp;gt; v2
    g.addEdge(3, 5, 20); // v3 -&amp;gt; t
    g.addEdge(4, 3, 7);  // v4 -&amp;gt; v3
    g.addEdge(4, 5, 4);  // v4 -&amp;gt; t

    const source = 0; // Source vertex (s)
    const sink = 5;   // Sink vertex (t)

    console.log(&quot;Running Ford-Fulkerson algorithm...&quot;);
    const maxFlow = g.fordFulkerson(source, sink);
    console.log(`The maximum possible flow from ${source} to ${sink} is: ${maxFlow}`);
}

main();
&lt;/code&gt;&lt;/pre&gt;
      &lt;/div&gt;
    &lt;/div&gt;


    &lt;h1 class=&quot;mt-6 text-xl font-serif&quot;&gt;Here&#39;s my few notes on graphs and why am I investing my time in graphs &lt;/h1&gt;
    &lt;p class=&quot;mt-4 text-lg font-serif&quot;&gt;Web search engines model the internet as a massive directed graph where web pages are vertices and hyperlinks are edges. Google&#39;s PageRank algorithm uses this graph structure to determine page importance based on the link structure, revolutionizing how we find information online.&lt;/p&gt;

    &lt;p class=&quot;mt-4 text-lg font-serif&quot;&gt;After spending so much time with machine learning algorithms and neural network,  ml on graphs is an ongoing thing which everyone should once go through, with graph neural networks learning representations directly from graph structure. This opens new possibilities for problems like node classification, link prediction, and graph generation.&lt;/p&gt;


    &lt;p class=&quot;mt-4 text-lg font-serif&quot;&gt;This is all from myside on Graphs. Hope I was able to add few value to your today&#39;s learning :) &lt;/p&gt;



    &lt;hr class=&quot;my-10&quot;&gt;
    



    
  

</description><link>https://mrinalxdev.github.io/mrinalxblogs/blogs/graphs.html</link><guid isPermaLink="false">https://mrinalxdev.github.io/mrinalxblogs/blogs/graphs.html</guid><pubDate>Invalid Date</pubDate><author>Mrinal</author></item><item><title>Algorithms 101 : From Beginners POV</title><description>&lt;hr class=&quot;mt-3&quot;&gt;

    &lt;h1 class=&quot;text-4xl mt-[57px] mb-3 font-serif&quot;&gt;
      Algorithms 101 : From a Beginners POV
    &lt;/h1&gt;
    &lt;span class=&quot;text-sm text-gray-500&quot;&gt;12th June, 2025 &lt;/span&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      Before writing this I took a minute and remembered how I
      imagined myself writing algorithms for optimizing data models which
      fastens up the data retrieval rate would look like. But by time I grew in
      this field I got to know that algorithms aren’t just code. These are some
      of the smart ways to tackle a problem and make data work faster
    &lt;/p&gt;

    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/dsa-2/banner.png&quot; class=&quot;w-[75%] mx-auto my-10&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

    &lt;p class=&quot;font-serif text-serif text-lg&quot;&gt;
      As ritual I will be covering few algo topics here which I use/have used on
      basis of my projects, paid gigs etc. The complexity of these algorithms
      will rise up gradually as the blog continues.
      &lt;br&gt;
      I hope you all know what is &lt;span class=&quot;font-bold&quot;&gt;Linear Search&lt;/span&gt; ?
      &lt;br&gt;
      If not no worries this is the most common technique used by algorithms to
      lookup for a solution to the problem, take it as searching for word in
      dictionary before knowing &quot;How to search words in dictionary&quot; going
      through all the pages, but its okkay if the dictionary had only 10 to 15
      pages but you would need a better and optimized way when there are
      literally 800+ pages
    &lt;/p&gt;

    &lt;h1 class=&quot;font-serif text-2xl my-6&quot;&gt;Binary Search&lt;/h1&gt;
    &lt;p class=&quot;text-lg font-serif&quot;&gt;
      This is a fast and efficient algorithms but only for sorted array or list,
      works by repeatedly dividing in the search space in half, which reduces
      the number of elements to check. Starting at the middle of the array, it
      compares the target value to middle element. If the target matches, the
      search is complete.
      &lt;br&gt;If the target is smaller, it searches the left half, if larger the
      right half. This process continues until the value is found
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif&quot;&gt;
      For algorithms we will be talking more about time complexity. So Binary
      Search&#39;s time complexity is \(O (\log n)\), making it faster than linear
      search for large sorted datasets
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      This is mainly used in searching databases, lookup tables, or implementing
      features like autocomplete. Here is an example of an api function which
      searches for a user by ID in a sorted list of users.
    &lt;/p&gt;

    &lt;div class=&quot;mt-6 border rounded-xl p-4 bg-gray-900 text-white font-mono&quot; id=&quot;code-div-2&quot;&gt;
      &lt;div class=&quot;flex justify-between items-center border-b border-gray-700&quot;&gt;
        &lt;div class=&quot;flex&quot;&gt;
          &lt;button class=&quot;px-4 py-2 bg-gray-800 text-white font-semibold rounded-t-md focus:outline-none language-tab active&quot; data-lang=&quot;javascript&quot; onclick=&quot;switchLanguage(&#39;code-div-2&#39;)&quot;&gt;
            JavaScript
          &lt;/button&gt;
        &lt;/div&gt;
        &lt;button class=&quot;px-4 py-2 text-gray-400 hover:text-white focus:outline-none&quot; onclick=&quot;toggleCollapse(&#39;code-div-2&#39;)&quot;&gt;
          Expand
        &lt;/button&gt;
      &lt;/div&gt;
      &lt;div class=&quot;mt-4 code-content hidden&quot;&gt;
        &lt;pre id=&quot;code-javascript&quot; class=&quot;language-javascript&quot;&gt;&lt;code&gt;// Using Linear Search an going in sequential order
// it will take 10k iterations if we want to find the last user
const users = [
{ id: 1, name: &quot;Sonita&quot; },
{ id: 2, name: &quot;Bonita&quot; },
{ id: 3, name: &quot;Aarav&quot; },
// ... 10 thousand more more
];
function findUser(userId) {
  return users.find(user =&amp;gt; user.id === userId); // O(n)
}
&lt;/code&gt;&lt;/pre&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;p class=&quot;mt-4 font-serif text-lg&quot;&gt;
      After using Binary Search Algorithm, for 10k users it just needs 14
      comparisons at most to find any user
    &lt;/p&gt;

    &lt;div class=&quot;mt-6 border rounded-xl p-4 bg-gray-900 text-white font-mono&quot; id=&quot;code-div-1&quot;&gt;
      &lt;div class=&quot;flex justify-between items-center border-b border-gray-700&quot;&gt;
        &lt;div class=&quot;flex&quot;&gt;
          &lt;button class=&quot;px-4 py-2 bg-gray-800 text-white font-semibold rounded-t-md focus:outline-none language-tab active&quot; data-lang=&quot;javascript&quot; onclick=&quot;switchLanguage(&#39;code-div-1&#39;)&quot;&gt;
            JavaScript
          &lt;/button&gt;
        &lt;/div&gt;
        &lt;button class=&quot;px-4 py-2 text-gray-400 hover:text-white focus:outline-none&quot; onclick=&quot;toggleCollapse(&#39;code-div-1&#39;)&quot;&gt;
          Expand
        &lt;/button&gt;
      &lt;/div&gt;
      &lt;div class=&quot;mt-4 code-content hidden&quot;&gt;
        &lt;pre id=&quot;code-javascript&quot; class=&quot;language-javascript&quot;&gt;&lt;code&gt;// ideal for static, sorted data like indexes or databases 
function binarySearch(users, userId) {
  let left = 0, right = users.length - 1;
  while (left &amp;lt;= right) {
    let mid = Math.floor((left + right) / 2);
    if (users[mid].id === userId) return users[mid];
    if (users[mid].id &amp;lt; userId) left = mid + 1;
    else right = mid - 1;
  }
  return null;
}
&lt;/code&gt;&lt;/pre&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;
      This algorithm can also be applied in client side for searching an item in
      a sorted dropdown list
    &lt;/p&gt;

    &lt;h1 class=&quot;font-serif text-2xl my-6&quot;&gt;Depth First Search&lt;/h1&gt;

    &lt;p class=&quot;font-serif text-lg&quot;&gt;
      The idea of DFS is starting with the root node and go as far down one
      branch as possible, all the way to the end.
    &lt;/p&gt;

    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/dsa-2/dfs.png&quot; class=&quot;w-[63%] mx-auto my-10&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

    &lt;p class=&quot;text-lg font-serif&quot;&gt;
      After reaching the dead end we come back to the last visited node, this
      process of going back to the last visited node is called
      &lt;span class=&quot;font-bold&quot;&gt;Backtracking&lt;/span&gt;[2]. We check if there are any
      unvisited nodes left. If there are, we explore those nodes next. If not,
      we backtrack again to the previous node. This process repeats until every
      node in the graph or tree has been visited[3].
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      The time complexity of DFS depends on the graph&#39;s structure. For a graph
      with &lt;span class=&quot;font-bold&quot;&gt;V&lt;/span&gt;vertices (nodes) and
      &lt;span class=&quot;font-bold&quot;&gt;E&lt;/span&gt; edges (connections), using a list of
      connected nodes. DFS takes \(O(V + E)\) time. This because it visits each
      vertex once and checks all edges to explore neighbors. It’s fast for most
      graphs, especially sparse ones like social networks, as it only processes
      the actual connections
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;
      One of the OSS issue on which I worked was related to ui rendering nested
      comments inefficiently with manual looping, which struggled with deep
      nesting
    &lt;/p&gt;

    &lt;div class=&quot;mt-6 border rounded-xl p-4 bg-gray-900 text-white font-mono&quot; id=&quot;code-div-3&quot;&gt;
      &lt;div class=&quot;flex justify-between items-center border-b border-gray-700&quot;&gt;
        &lt;div class=&quot;flex&quot;&gt;
          &lt;button class=&quot;px-4 py-2 bg-gray-800 text-white font-semibold rounded-t-md focus:outline-none language-tab active&quot; data-lang=&quot;javascript&quot; onclick=&quot;switchLanguage(&#39;code-div-3&#39;)&quot;&gt;
            JavaScript
          &lt;/button&gt;
        &lt;/div&gt;
        &lt;button class=&quot;px-4 py-2 text-gray-400 hover:text-white focus:outline-none&quot; onclick=&quot;toggleCollapse(&#39;code-div-3&#39;)&quot;&gt;
          Expand
        &lt;/button&gt;
      &lt;/div&gt;
      &lt;div class=&quot;mt-4 code-content hidden&quot;&gt;
        &lt;pre id=&quot;code-javascript&quot; class=&quot;language-javascript&quot;&gt;&lt;code&gt;// the comments where fetched from db and stored in a list
const comments = [
  { id: 1, text: &quot;Great!&quot;, replies: [{ id: 2, text: &quot;Thanks!&quot; }] },
  { id: 3, text: &quot;Cool&quot;, replies: [] },
];
function renderComments() {
  let html = &quot;&quot;;
  for (let comment of comments) {
    html += `&lt;div&gt;${comment.text}&lt;/div&gt;`;
    if (comment.replies) {
      for (let reply of comment.replies) {
        html += `&lt;div style=&quot;margin-left: 20px&quot;&gt;${reply.text}&lt;/div&gt;`;
      }
    }
  }
  return html;
}
&lt;/code&gt;&lt;/pre&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;p class=&quot;text-lg font-serif my-4&quot;&gt;
      My Pull request for the same issue, used DFS. I have attached the full
      anatomy here
    &lt;/p&gt;

    &lt;div class=&quot;mt-6 border rounded-xl p-4 bg-gray-900 text-white font-mono&quot; id=&quot;code-div-4&quot;&gt;
      &lt;div class=&quot;flex justify-between items-center border-b border-gray-700&quot;&gt;
        &lt;div class=&quot;flex&quot;&gt;
          &lt;button class=&quot;px-4 py-2 bg-gray-800 text-white font-semibold rounded-t-md focus:outline-none language-tab active&quot; data-lang=&quot;javascript&quot; onclick=&quot;switchLanguage(&#39;javascript&#39;, &#39;code-div-4&#39;)&quot;&gt;
            JavaScript
          &lt;/button&gt;
        &lt;/div&gt;
        &lt;button class=&quot;px-4 py-2 text-gray-400 hover:text-white focus:outline-none&quot; onclick=&quot;toggleCollapse(&#39;code-div-4&#39;)&quot;&gt;
          Expand
        &lt;/button&gt;
      &lt;/div&gt;
      &lt;div class=&quot;mt-4 code-content hidden&quot;&gt;
        &lt;pre id=&quot;code-javascript&quot; class=&quot;language-javascript&quot;&gt;&lt;code&gt;//  Ideal for exploring all paths, detecting cycles, or solving problems requiring exhaustive search.

// &quot;comments&quot; is an array of comment objects
// &quot;deep&quot; is an optional parameter indicating how deep in the reply
// hierarchy we are, will be starting at 0 (top-comment)
function renderComments(comments, depth = 0) {
  // this will hold the final html output that gets
  // returned
  let html = &quot;&quot;;
  // helps in iterating through each comment
  for (let comment of comments) {
    // appending the current comment&#39;s text to
    // the html string
    &quot;html += `${comment.text}`;&quot;

    // using recursion here
    if (comment.replies) {

      // if the comment has replies &#39;comment.replies&#39; exits, then recursively renderComments
      // on those replies
      // and increase the depth by 1 to indicate you are now
      // rendering a deeper level of replies
      html += renderCommentsDFS(comment.replies, depth + 1);
    }
  }
  return html;
}
&lt;/code&gt;&lt;/pre&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      This can also be used for detecting cycles in dependency graphs for
      building package managers.
    &lt;/p&gt;

    &lt;h1 class=&quot;font-serif text-2xl my-6&quot;&gt;Breadth First Search&lt;/h1&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      In Breadth first search it explores graphs differently. Instead of diving
      deep like DFS, BFS visits all nodes at the current &quot;level&quot; before moving
      to next.
    &lt;/p&gt;

    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/dsa-2/bfs.png&quot; class=&quot;my-10 w-[70%] mx-auto&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      Starting from a chosen node, it explores all its immediate neighbors
      first, then their neighbors, and so on. This makes BFS ideal for finding
      the shortest path in unweighted graphs for exploring nodes closer to
      starting point.
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;
      For the time complexity part we can say its similar to DFS which is \(O (V
      + E) \) but the only difference is, BFS uses queue to track nodes,
      ensuring it explores closer nodes first, which is why its great for
      finding shortest paths in unweighted graphs, like in navigation apps or
      GPS
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      Code Dissection of Friends graph is written below
    &lt;/p&gt;

    &lt;div class=&quot;mt-6 border rounded-xl p-4 bg-gray-900 text-white font-mono&quot; id=&quot;code-div-5&quot;&gt;
      &lt;div class=&quot;flex justify-between items-center border-b border-gray-700&quot;&gt;
        &lt;div class=&quot;flex&quot;&gt;
          &lt;button class=&quot;px-4 py-2 bg-gray-800 text-white font-semibold rounded-t-md focus:outline-none language-tab active&quot; data-lang=&quot;javascript&quot; onclick=&quot;switchLanguage(&#39;code-div-5&#39;)&quot;&gt;
            JavaScript
          &lt;/button&gt;
        &lt;/div&gt;
        &lt;button class=&quot;px-4 py-2 text-gray-400 hover:text-white focus:outline-none&quot; onclick=&quot;toggleCollapse(&#39;code-div-5&#39;)&quot;&gt;
          Expand
        &lt;/button&gt;
      &lt;/div&gt;
      &lt;div class=&quot;mt-4 code-content hidden&quot;&gt;
        &lt;pre id=&quot;code-javascript&quot; class=&quot;language-javascript&quot;&gt;&lt;code&gt;
const users = {
  &#39;Sonita&#39;: [&#39;Aarav&#39;, &#39;Charlie&#39;],
  &#39;Bonita&#39;: [&#39;Vegeta&#39;, &#39;David&#39;],
  &#39;Gojita&#39;: [&#39;Vegito&#39;],
  &#39;Majin Buu&#39;: [&#39;Mr. Satan&#39;]
};

function findConnection(user1, user2) {
  // starting with user1 with a connection distance of 0
  const queue = [[user1, 0]];
  // this const keeps track and avoids revisiting
  const visited = new Set([user1]);

  // this is the main loop for BFS
  while (queue.length) {
    // taking the front node using &#39;shift()&#39; is used because it&#39;s a
    // queue, &#39;user&#39; is the current person being explored
    // distance is how many steps away this user is from user1
    const [user, distance] = queue.shift();

    // if the current user is the target, return the distance
    // this also shows no.of steps needed to get from user1 to user2
    if (user === user2) return distance;

    // for every friend of current user
    // if we haven&#39;t seen this friend before
    // mark them as visited
    // add them to queue with an updated distance (distance + 1) 
    // one more step away from user1
    for (let friend of users[user]) {
      if (!visited.has(friend)) {
        visited.add(friend);
        queue.push([friend, distance + 1]);
      }
    }
  }

  // if loop finishes without any friends
  // than we return -1 means (not found)
  return -1;
}
&lt;/code&gt;&lt;/pre&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;h1 class=&quot;font-serif text-2xl my-6&quot;&gt;Insertion Sort Algorithm&lt;/h1&gt;

    &lt;p class=&quot;mt-4 font-serif text-lg&quot;&gt;
      Insertion sort is a simple sorting algorithm that builds a sorted array
      one element at a time.
    &lt;/p&gt;

    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/dsa-2/insertion.png&quot; class=&quot;my-10&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      Starting with the second element, insertion sort compares it to the
      previous ones, shifting larger elements right until it finds the right
      spot to &quot;insert&quot; the element. This process repeats for each element until
      the entire array is sorted. Works well for small datasets or nearly sorted
      lists, like organizing a short list of names or numbers.
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      The time complexity of Insertion Sort depends on the array size and its
      initial order. For an array with n elements, the worst-case time
      complexity is \(O(n^2)\), as each element may need to be compared and
      shifted against all previous elements, like when the array is
      reverse-sorted. In the best case, such as a nearly sorted array, it runs
      in \(O(n)\) time, as each element requires minimal comparisons and shifts.
      This makes Insertion Sort efficient for small or nearly sorted datasets
      but less ideal for large, unsorted lists compared to faster algorithms
      like Quick Sort.
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif my-2&quot;&gt;
      We can code a Search history using insertion sort
    &lt;/p&gt;
    &lt;div class=&quot;mt-6 border rounded-xl p-4 bg-gray-900 text-white font-mono&quot; id=&quot;code-div-6&quot;&gt;
      &lt;div class=&quot;flex justify-between items-center border-b border-gray-700&quot;&gt;
        &lt;div class=&quot;flex&quot;&gt;
          &lt;button class=&quot;px-4 py-2 bg-gray-800 text-white font-semibold rounded-t-md focus:outline-none language-tab active&quot; data-lang=&quot;javascript&quot; onclick=&quot;switchLanguage(&#39;code-div-6&#39;)&quot;&gt;
            JavaScript
          &lt;/button&gt;
        &lt;/div&gt;
        &lt;button class=&quot;px-4 py-2 text-gray-400 hover:text-white focus:outline-none&quot; onclick=&quot;toggleCollapse(&#39;code-div-6&#39;)&quot;&gt;
          Expand
        &lt;/button&gt;
      &lt;/div&gt;
      &lt;div class=&quot;mt-4 code-content hidden&quot;&gt;
        &lt;pre id=&quot;code-javascript&quot; class=&quot;language-javascript&quot;&gt;&lt;code&gt;
function insertionSort(arr) {
  // Start from the second element (i = 1), since the first element is considered &quot;sorted&quot;
  for (let i = 1; i &amp;lt; arr.length; i++) {
    
    // &#39;key&#39; is the current element we want to insert into the sorted part of the array
    let key = arr[i];

    // &#39;j&#39; marks the end of the sorted portion (just before the current element)
    let j = i - 1;

    // Move elements of arr[0..i-1], that are less than &#39;key.time&#39;, one position ahead
    // We sort in descending order based on &#39;time&#39; property
    while (j &amp;gt;= 0 &amp;amp;&amp;amp; arr[j].time &amp;lt; key.time) {
      // Shift the element to the right
      arr[j + 1] = arr[j];
      j--; // Move one step back in the array
    }

    // Insert the &#39;key&#39; in its correct position
    arr[j + 1] = key;
  }

  // Return the sorted array
  return arr;
}
&lt;/code&gt;&lt;/pre&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;h1 class=&quot;font-serif text-2xl my-6&quot;&gt;Merge Sort Algorithm&lt;/h1&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      Its a reliable sorting algorithm which uses a divide and conquer approach
      to sort arrays efficiently.
    &lt;/p&gt;
    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      It works by splitting the array into two halves, sorting each half
      recursively, and then merging the sorted halves back together to create a
      fully sorted array. Its stable meaning, it preserves the relative order of
      equal elements, and is ideal for large datasets, like sorting customer
      records or database entries, due to its consistent performance.
    &lt;/p&gt;

    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/dsa-2/attention.png&quot; class=&quot;my-10&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      Lets talk a little about the time complexity here, merge sort has a time
      complexity of \(O(n log n)\) in all cases from best, average to worst. For
      example lets take the above figure which is [4, 2, 5, 1, 8, 3, 7, 6] here
      \(n=8\) elements and for \(n=8\), it takes \(log_2 8 = 3\) levels of
      division (8 -&amp;gt; 4 pairs -&amp;gt; 2 groups of 4 -&amp;gt; 1 group of 8). Our figure
      starts with four groups of two, which is part of this process
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      At each level, all \(n\) elements are merged. Merging two sorted lists
      compares and combines elements in linear time. Merging four pairs \(([4,
      2], [5, 1], [8, 3], [7, 6])\) into two groups takes about 8 comparisons
      total. Merging two groups \(([1, 2, 4, 5], [3, 6, 7, 8])\) into one takes
      another 8 comparisons &lt;br&gt;
      The O(n log n) complexity holds because the number of divisions is
      logarithmic \(log n \), and each merge step scales linearly with \(n \).
      Unlike Insertion Sort&#39;s \(O(n^2)\) (upto 64 operations for n = 8)
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      &lt;span class=&quot;font-bold&quot;&gt;Before&lt;/span&gt; &lt;br&gt;
      The API gets session data from the DB. Uses
      &lt;span&gt;.sort()&lt;/span&gt; which may be unstable or optimized differently
      depending on V8 engine. So we get less control over performance in large
      datasets
    &lt;/p&gt;

    &lt;div class=&quot;mt-6 border rounded-xl p-4 bg-gray-900 text-white font-mono&quot; id=&quot;code-div-7&quot;&gt;
      &lt;div class=&quot;flex justify-between items-center border-b border-gray-700&quot;&gt;
        &lt;div class=&quot;flex&quot;&gt;
          &lt;button class=&quot;px-4 py-2 bg-gray-800 text-white font-semibold rounded-t-md focus:outline-none language-tab active&quot; data-lang=&quot;javascript&quot; onclick=&quot;switchLanguage( &#39;code-div-7&#39;)&quot;&gt;
            JavaScript
          &lt;/button&gt;
        &lt;/div&gt;
        &lt;button class=&quot;px-4 py-2 text-gray-400 hover:text-white focus:outline-none&quot; onclick=&quot;toggleCollapse(&#39;code-div-7&#39;)&quot;&gt;
          Expand
        &lt;/button&gt;
      &lt;/div&gt;
      &lt;div class=&quot;mt-4 code-content hidden&quot;&gt;
        &lt;pre id=&quot;code-javascript&quot; class=&quot;language-javascript&quot;&gt;&lt;code&gt;// routes/sessionStats.js
app.get(&#39;/api/sessions/sorted&#39;, async (req, res) =&amp;gt; {
  const sessions = await db.getUserSessions(); // returns array like [120, 30, 45, 60]
  
  // Using built-in sort (not always stable or predictable)
  const sorted = sessions.sort((a, b) =&amp;gt; a - b);

  res.json({ sorted });
});

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

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      &lt;span class=&quot;font-bold&quot;&gt;After using Merge Sort&lt;/span&gt; &lt;br&gt;
      After using our own implementation of merge sort and replacing it with
      built-in sort, it helped with performance tuning and custom rules which
      can handling large logs or preprocessing logs offline
    &lt;/p&gt;

    &lt;div class=&quot;mt-6 border rounded-xl p-4 bg-gray-900 text-white font-mono&quot; id=&quot;code-div-8&quot;&gt;
      &lt;div class=&quot;flex justify-between items-center border-b border-gray-700&quot;&gt;
        &lt;div class=&quot;flex&quot;&gt;
          &lt;button class=&quot;px-4 py-2 bg-gray-800 text-white font-semibold rounded-t-md focus:outline-none language-tab active&quot; data-lang=&quot;javascript&quot; onclick=&quot;switchLanguage(&#39;code-div-8&#39;)&quot;&gt;
            JavaScript
          &lt;/button&gt;
        &lt;/div&gt;
        &lt;button class=&quot;px-4 py-2 text-gray-400 hover:text-white focus:outline-none&quot; onclick=&quot;toggleCollapse(&#39;code-div-8&#39;)&quot;&gt;
          Expand
        &lt;/button&gt;
      &lt;/div&gt;
      &lt;div class=&quot;mt-4 code-content hidden&quot;&gt;
        &lt;pre id=&quot;code-javascript&quot; class=&quot;language-javascript&quot;&gt;&lt;code&gt;// utils/mergeSort.js
function mergeSort(arr) {
  if (arr.length &amp;lt;= 1) return arr;

  const mid = Math.floor(arr.length / 2);
  const left = mergeSort(arr.slice(0, mid));
  const right = mergeSort(arr.slice(mid));

  return merge(left, right);
}

function merge(left, right) {
  const result = [];
  let i = 0, j = 0;

  while (i &amp;lt; left.length &amp;amp;&amp;amp; j &amp;lt; right.length) {
    if (left[i] &amp;lt; right[j]) result.push(left[i++]);
    else result.push(right[j++]);
  }

  return result.concat(left.slice(i)).concat(right.slice(j));
}

module.exports = { mergeSort };


// on different file we can call the function and use it
const { mergeSort } = require(&#39;../utils/mergeSort&#39;);

app.get(&#39;/api/sessions/sorted&#39;, async (req, res) =&amp;gt; {
  const sessions = await db.getUserSessions();

  const sorted = mergeSort(sessions);

  res.json({ sorted });
});
&lt;/code&gt;&lt;/pre&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;h1 class=&quot;font-serif text-2xl my-6&quot;&gt;Quick Sort Algorithm&lt;/h1&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      This uses the same strategy as Merge Sort algorithm which is divide and
      conquer strategy to sort arrays. But it works by picking a &quot;pivot&quot;
      element, partitioning the array so that element smaller than the pivot are
      on its left and larger ones on its right, then recursively sorting the
      left and right sub-arrays.
    &lt;/p&gt;

    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/dsa-2/quick.png&quot; alt=&quot;&quot; class=&quot;my-10&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      Quick Sort is fast and widely used for large datasets, like sorting
      student grades or product lists, due to its average-case speed.
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      For an array with n elements, Quick Sort’s time complexity is \(O (n log
      n)\) on average, making it very fast for most cases. It divides the array
      into two parts around a pivot, ideally halving the problem size each time,
      requiring log n levels and n comparisons per level. sorting an array of 8
      elements takes about 24 operations (8 * log 8). In the worst case, like a
      sorted or reverse-sorted array with a poor pivot choice, it can degrade to
      O(n²), but this is rare with good pivot strategies.
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      Choosing a good pivot is crucial for efficiency, as it effects how evenly
      the array is split. Here are some common steps you can include while
      choosing one :
    &lt;/p&gt;

    &lt;ul class=&quot;text-lg ml-4 mt-3 font-serif list-disc&quot;&gt;
      &lt;li&gt;
        &lt;span class=&quot;font-bold&quot;&gt;First / Last Element&lt;/span&gt;: Pick the first or
        last element, but this can lead to \(O(n^2)\) time in sorted or
        reverse-sorted average performance.
      &lt;/li&gt;
      &lt;li class=&quot;mt-3&quot;&gt;
        &lt;span class=&quot;font-bold&quot;&gt;Random Pivot&lt;/span&gt; : Select a random element to
        reduce the chance of worst-case scenarios, improving average
        performance. But how you would ask. Choosing a random pivot in quick
        sort increases avg. performance by reducing the likelihood of
        consistently poor partitions, which can lead to worst-case \(O(n^2)\)
        time complexity.When a pivot is randomly selected from the array, it’s
        unlikely to repeatedly pick the smallest or largest element, as happens
        in sorted or nearly sorted arrays with fixed pivots (e.g., first
        element). Instead, random pivots tend to create more balanced
        partitions, splitting the array closer to half each time, which aligns
        with the ideal \(O(n log n)\) average-case performance. For example, in
        \([4, 3, 5, 2, 6, 1, 7, 8]\), a random pivot like 5 might split into [4,
        3, 2, 1] and [6, 7, 8], keeping sub-arrays roughly equal. This
        randomness averages out bad cases over many runs, ensuring partitions
        are balanced more often, with each level taking O(n) comparisons across
        log n levels.
      &lt;/li&gt;
    &lt;/ul&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      &lt;span class=&quot;font-bold&quot;&gt;Before&lt;/span&gt; &lt;br&gt;
      The best way I learned quick sort algorithm was by implementing it in a
      e-commerce api in which products were sorted by price, at first I thought
      using &lt;span&gt;.sort()&lt;/span&gt; would be but NVM XDD. It was simple and short
      but lacked control and it can&#39;t handle complex logic lick preprocessing,
      side effects, or tracing steps for debugging
    &lt;/p&gt;

    &lt;div class=&quot;mt-6 border rounded-xl p-4 bg-gray-900 text-white font-mono&quot; id=&quot;code-div-9&quot;&gt;
      &lt;div class=&quot;flex justify-between items-center border-b border-gray-700&quot;&gt;
        &lt;div class=&quot;flex&quot;&gt;
          &lt;button class=&quot;px-4 py-2 bg-gray-800 text-white font-semibold rounded-t-md focus:outline-none language-tab active&quot; data-lang=&quot;javascript&quot; onclick=&quot;switchLanguage( &#39;code-div-9&#39;)&quot;&gt;
            JavaScript
          &lt;/button&gt;
        &lt;/div&gt;
        &lt;button class=&quot;px-4 py-2 text-gray-400 hover:text-white focus:outline-none&quot; onclick=&quot;toggleCollapse(&#39;code-div-9&#39;)&quot;&gt;
          Expand
        &lt;/button&gt;
      &lt;/div&gt;
      &lt;div class=&quot;mt-4 code-content hidden&quot;&gt;
        &lt;pre id=&quot;code-javascript&quot; class=&quot;language-javascript&quot;&gt;&lt;code&gt;// routes/products.js
app.get(&#39;/api/products/sorted&#39;, async (req, res) =&amp;gt; {
  const products = await db.getProducts(); // [{ name: &quot;Shoes&quot;, price: 80 }, ...]

  const sorted = products.sort((a, b) =&amp;gt; a.price - b.price);

  res.json({ sorted });
});
&lt;/code&gt;&lt;/pre&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      &lt;span class=&quot;font-bold&quot;&gt;After&lt;/span&gt; &lt;br&gt;
      After learning and implementing my own Quick Sort to sort products by
      price, this let me add debug logs, skip invalid prices, add thresholds or
      filtering inline, or customize order (ascending / descending)
    &lt;/p&gt;

    &lt;div class=&quot;mt-6 border rounded-xl p-4 bg-gray-900 text-white font-mono&quot; id=&quot;code-div-10&quot;&gt;
      &lt;div class=&quot;flex justify-between items-center border-b border-gray-700&quot;&gt;
        &lt;div class=&quot;flex&quot;&gt;
          &lt;button class=&quot;px-4 py-2 bg-gray-800 text-white font-semibold rounded-t-md focus:outline-none language-tab active&quot; data-lang=&quot;javascript&quot; onclick=&quot;switchLanguage( &#39;code-div-10&#39;)&quot;&gt;
            JavaScript
          &lt;/button&gt;
        &lt;/div&gt;
        &lt;button class=&quot;px-4 py-2 text-gray-400 hover:text-white focus:outline-none&quot; onclick=&quot;toggleCollapse(&#39;code-div-10&#39;)&quot;&gt;
          Expand
        &lt;/button&gt;
      &lt;/div&gt;
      &lt;div class=&quot;mt-4 code-content hidden&quot;&gt;
        &lt;pre id=&quot;code-javascript&quot; class=&quot;language-javascript&quot;&gt;&lt;code&gt;function quickSortProducts(arr, ascending = true) {
  if (arr.length &amp;lt;= 1) return arr;

  const pivot = arr[arr.length - 1];
  const left = [];
  const right = [];

  for (let i = 0; i &amp;lt; arr.length - 1; i++) {
    if (!arr[i].price) continue; // skip if price is missing

    if (ascending ? arr[i].price &amp;lt; pivot.price : arr[i].price &amp;gt; pivot.price) {
      left.push(arr[i]);
    } else {
      right.push(arr[i]);
    }
  }

  return [
    ...quickSortProducts(left, ascending),
    pivot,
    ...quickSortProducts(right, ascending),
  ];
}

module.exports = { quickSortProducts };

const { quickSortProducts } = require(&#39;../utils/quickSortProducts&#39;);

app.get(&#39;/api/products/sorted&#39;, async (req, res) =&amp;gt; {
  const products = await db.getProducts();

  const order = req.query.order || &#39;asc&#39;; // ?order=desc
  const sorted = quickSortProducts(products, order === &#39;asc&#39;);

  res.json({ sorted });
});
&lt;/code&gt;&lt;/pre&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;p class=&quot;mt-6 text-lg font-serif&quot;&gt;
      I wanted to add greedy algorithm and DP but that would be an overkill for
      this blog, these are searching and sorting algorithms which is mainly used
      during development &lt;br&gt;
      Hope I was able to add few value to your today&#39;s learning :)
    &lt;/p&gt;

    &lt;hr class=&quot;my-10&quot;&gt;
    
  

  

</description><link>https://mrinalxdev.github.io/mrinalxblogs/blogs/algorithms.html</link><guid isPermaLink="false">https://mrinalxdev.github.io/mrinalxblogs/blogs/algorithms.html</guid><pubDate>Invalid Date</pubDate><author>Mrinal</author></item><item><title>Using Data Structures and Algorithms practically</title><description>&lt;hr class=&quot;mt-3&quot;&gt;

    &lt;h1 class=&quot;text-4xl mt-[57px] mb-3 font-serif&quot;&gt;
      Using Data Structures practically
    &lt;/h1&gt;
    &lt;span class=&quot;text-sm text-gray-500&quot;&gt;2nd June, 2025&lt;/span&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      Whenever I think of data structures and algorithms it scares me a little
      because, past few interviews I have been lacking on my algorithms skills a
      little bit. But when I changed my prespective to learn it through building
      projects with just raw code like &quot;Just working&quot; mindset and then picking
      up every topic of data structures, learning it, and then applying the
      topic in the &quot;Just working&quot; project to make it more optimize
    &lt;/p&gt;

    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/dsa/banner.png&quot; class=&quot;my-5&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

    &lt;p class=&quot;text-lg mt-3 font-serif&quot;&gt;
      I will be covering few ds and algo that I use on everyday basis for my
      development of project, paid gigs etc. &lt;br&gt;
      For the very first lets start with data structure topics, so going by the
      name it means structuring a data or large set of data in a mannered way .
      :)) WOOWWW !!
    &lt;/p&gt;

    &lt;h1 class=&quot;text-3xl mt-6 font-serif&quot;&gt;Data Structures and its usage&lt;/h1&gt;

    &lt;p class=&quot;text-lg mt-3 font-serif&quot;&gt;
      Starting with the easiest one, which is arrays then gradually increase the
      complexity of topics.
    &lt;/p&gt;

    &lt;h1 class=&quot;text-2xl font-bold mt-4 font-serif&quot;&gt;Arrays&lt;/h1&gt;
    &lt;p class=&quot;text-lg mt-3 font-serif&quot;&gt;
      These are containers for storing multiple data types in a ordered manner,
      like a bunch of strings, a bunch of integers, or you can mix up the types
      of data that you want to be stored (only few languages allow this mix-up).
      Each elements in an array is assigned with a number known as &quot;indexing&quot;,
      and arrays are zero-indexed which means first element&#39;s index is 0.
    &lt;/p&gt;

    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/dsa/arrays.png&quot; class=&quot;w-[530px] mx-auto my-4&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

    &lt;p class=&quot;text-lg mt-3 font-serif&quot;&gt;
      Lets talk a little bit about memory here, see arrays are stored in
      contiguos manner means each elements are stored which means elements of
      arrays are next to one another this makes reading arrays faster which is
      O(1) according to time complexity, but this also makes insertion and
      deletion of items slower
    &lt;/p&gt;
    &lt;p class=&quot;text-lg mt-3 font-serif&quot;&gt;
      How doest insertion and deletion becomes slower ?? So here is the thing,
      arrays are always grouped together so if user pushes a new variable in the
      middle the arrays get updated accordingly. But what if the very next
      memory is not free, whole array with allocated memory needs to shift to a
      new place. This makes reading easier (O(1)) but insertion (O(n)) and
      deletion (O(n)) gets a bit slower.
    &lt;/p&gt;

    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/dsa/memory-array.png&quot; class=&quot;my-5&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

    &lt;p class=&quot;font-serif text-lg&quot;&gt;
      Now arrays are basic, foundational data structures commonly used in the
      first approach itself without even thinking, as they efficiently store and
      manage collections of elements. But we will look down for problem which it
      really solves. :))
    &lt;/p&gt;

    &lt;p class=&quot;text-lg mt-4 font-serif&quot;&gt;
      You are building a simple to-do list app for yourself, you want to store
      and display tasks they&#39;ve completed today.
    &lt;/p&gt;
    &lt;!-- &lt;div class=&quot;mt-4 border rounded-xl p-4 bg-gray-900 text-white font-mono&quot;&gt;
      &lt;div class=&quot;flex border-b border-gray-700&quot;&gt;
        &lt;button
          class=&quot;px-4 py-2 bg-gray-800 text-white font-semibold rounded-t-md focus:outline-none language-tab active&quot;
          data-lang=&quot;javascript&quot;
          onclick=&quot;switchLanguage(&#39;javascript&#39;)&quot;
        &gt;
          JavaScript
        &lt;/button&gt;
        &lt;button
          class=&quot;px-4 py-2 bg-gray-900 text-gray-400 font-semibold rounded-t-md focus:outline-none language-tab&quot;
          data-lang=&quot;python&quot;
          onclick=&quot;switchLanguage(&#39;python&#39;)&quot;
        &gt;
          Python
        &lt;/button&gt;
      &lt;/div&gt;
      &lt;div class=&quot;mt-4&quot;&gt;
        &lt;pre
          id=&quot;code-javascript&quot;
          class=&quot;language-javascript&quot;
        &gt;&lt;code&gt;// Without arrays - manual handling
let task1 = &quot;Buy groceries&quot;;
let task2 = &quot;Finish homework&quot;;
let task3 = &quot;Call mom&quot;;
          
console.log(&quot;Completed Tasks:&quot;);
console.log(&quot;1. &quot; + task1);
console.log(&quot;2. &quot; + task2);
console.log(&quot;3. &quot; + task3);

// After using Arrays
let tasks = [&quot;Buy groceries&quot;, &quot;Finish homework&quot;, &quot;Call mom&quot;];

console.log(&quot;Completed Tasks:&quot;);
for (let i = 0; i &lt; tasks.length; i++) {
    console.log((i + 1) + &quot;. &quot; + tasks[i]);
}
&lt;/code&gt;&lt;/pre&gt;
        &lt;pre id=&quot;code-python&quot; class=&quot;language-python hidden&quot;&gt;&lt;code&gt;
task1 = &quot;Buy groceries&quot;
task2 = &quot;Finish homework&quot;
task3 = &quot;Call mom&quot;

print(&quot;Completed Tasks:&quot;)
print(f&quot;1. {task1}&quot;)
print(f&quot;2. {task2}&quot;)
print(f&quot;3. {task3}&quot;)


# using arrays, in python known as lists
tasks = [&quot;Buy groceries&quot;, &quot;Finish homework&quot;, &quot;Call mom&quot;]

print(&quot;Completed Tasks:&quot;)
for i in range(len(tasks)):
    print(f&quot;{i + 1}. {tasks[i]}&quot;)
&lt;/code&gt;&lt;/pre&gt;
      &lt;/div&gt;
    &lt;/div&gt; --&gt;

    &lt;div class=&quot;mt-4 border rounded-xl p-4 bg-gray-900 text-white font-mono&quot; id=&quot;code-div-2&quot;&gt;
      &lt;div class=&quot;flex justify-between items-center border-b border-gray-700&quot;&gt;
        &lt;div class=&quot;flex&quot;&gt;
          &lt;button class=&quot;px-4 py-2 bg-gray-800 text-white font-semibold rounded-t-md focus:outline-none language-tab active&quot; data-lang=&quot;javascript&quot; onclick=&quot;switchLanguage(&#39;javascript&#39;, &#39;code-div-2&#39;)&quot;&gt;
            JavaScript
          &lt;/button&gt;
        &lt;/div&gt;
        &lt;button class=&quot;px-4 py-2 text-gray-400 hover:text-white focus:outline-none&quot; onclick=&quot;toggleCollapse(&#39;code-div-2&#39;)&quot;&gt;
          Expand
        &lt;/button&gt;
      &lt;/div&gt;
      &lt;div class=&quot;mt-4 code-content&quot;&gt;
        &lt;pre id=&quot;code-javascript&quot; class=&quot;language-javascript&quot;&gt;&lt;code&gt;// Without arrays - manual handling
let task1 = &quot;Buy groceries&quot;;
let task2 = &quot;Finish homework&quot;;
let task3 = &quot;Call mom&quot;;
          
console.log(&quot;Completed Tasks:&quot;);
console.log(&quot;1. &quot; + task1);
console.log(&quot;2. &quot; + task2);
console.log(&quot;3. &quot; + task3);

// After using Arrays
let tasks = [&quot;Buy groceries&quot;, &quot;Finish homework&quot;, &quot;Call mom&quot;];

console.log(&quot;Completed Tasks:&quot;);
for (let i = 0; i &amp;lt; tasks.length; i++) {
    console.log((i + 1) + &quot;. &quot; + tasks[i]);
}
&lt;/code&gt;&lt;/pre&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;h1 class=&quot;text-2xl font-bold mt-7 font-serif&quot;&gt;Linked List&lt;/h1&gt;

    &lt;p class=&quot;text-lg mt-3 font-serif&quot;&gt;
      Linked list are just opposite to arrays, they are faster while insertion
      and deletion of items while a bit slow on reading items. It consists of
      nodes where each node holds data and a pointer(address to another node).
      Also
    &lt;/p&gt;

    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/dsa/linkedpointers.png&quot; class=&quot;my-4&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      This structure makes linked lists dynamic and flexible in scenarios where
      frequent insertions and deletions are required.
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;
      Let&#39;s talk about memory a little bit, each node is stored independently,
      containing the data and a pointer to next node, which allows linked lists
      to grow or shrink dynamically without needing to resize a predefined
      array. This dynamic allocation is memory efficient for datasets which are
      unpredictable with their sizes. However reading becomes slow as if you
      want a element from middle you need to get the first element then to the
      desired item, this some times leads to memory fragmentation over time, as
      nodes are scattered across memory.
    &lt;/p&gt;

    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/dsa/Linkedlist.png&quot; class=&quot;my-5&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

    &lt;p class=&quot;font-serif text-lg my-4&quot;&gt;
      Okkay how I learned it in a hard way ?? I was building a backend service
      to manage a queue of user support ticket. Each ticket needs to be
      processed in order, and new tickets can come in dynamincally.
    &lt;/p&gt;


    &lt;p class=&quot;my-5 text-lg font-serif&quot;&gt;
      After discussing with GPT, I got to realise this is not the most efficent
      methods to use, go then I got to know about Linked List and then how to
      use it, this is how I implemented it from scratch.
    &lt;/p&gt;

    &lt;div class=&quot;mt-4 border rounded-xl p-4 bg-gray-900 text-white font-mono&quot; id=&quot;code-div-4&quot;&gt;
      &lt;div class=&quot;flex justify-between items-center border-b border-gray-700&quot;&gt;
        &lt;div class=&quot;flex&quot;&gt;
          &lt;button class=&quot;px-4 py-2 bg-gray-800 text-white font-semibold rounded-t-md focus:outline-none language-tab active&quot; data-lang=&quot;javascript&quot; onclick=&quot;switchLanguage(&#39;javascript&#39;, &#39;code-div-4&#39;)&quot;&gt;
            JavaScript
          &lt;/button&gt;
        &lt;/div&gt;
        &lt;button class=&quot;px-4 py-2 text-gray-400 hover:text-white focus:outline-none&quot; onclick=&quot;toggleCollapse(&#39;code-div-4&#39;)&quot;&gt;
          Expand
        &lt;/button&gt;
      &lt;/div&gt;
      &lt;div class=&quot;mt-4 code-content hidden&quot;&gt;
        &lt;pre id=&quot;code-javascript&quot; class=&quot;language-javascript&quot;&gt;&lt;code&gt;// this represents the a single node in the linked list
// holding one ticket
class TicketNode {
    constructor(data) {
        this.data = data;
        this.next = null;
    }
}

// this class will be managing the queue of tickets using Linked List
// keeping the track of head(first node) and tail(last node) nodes
class TicketQueue {
    constructor() {
        this.head = null;
        this.tail = null;
    }
    
    // enqueue method adds a new ticket to the end of the queue
    // (FIFO principle : last in, processed last)
    // time complexity : O(1), as it 
    // only involves creating a node and updating pointers

    enqueue(data) {
        const newNode = new TicketNode(data);
        if (!this.head) {
            this.head = newNode;
            this.tail = newNode;
        } else {
            this.tail.next = newNode;
            this.tail = newNode;
        }
    }

    // this method removes and returns the ticket at the front of the queue
    // FIFO : first in, processed first
    // O(1) : as it only updates the pointer
    dequeue() {
        if (!this.head) return null;
        const removed = this.head.data;
        this.head = this.head.next;
        if (!this.head) this.tail = null;
        return removed;
    }

    // printAll method is like reading and displaying
    // O(n) : where n is the number of nodes, 
    // because its going to visit each node once 
    printAll() {
        let current = this.head;
        let index = 1;
        while (current) {
            console.log(`${index++}. ${current.data}`);
            current = current.next;
        }
    }
}

const queue = new TicketQueue();
queue.enqueue(&quot;Ticket #001: Login issue&quot;);
queue.enqueue(&quot;Ticket #002: Payment error&quot;);
queue.enqueue(&quot;Ticket #003: Forgot password&quot;);

console.log(&quot;Processing:&quot;, queue.dequeue());

console.log(&quot;Remaining Tickets:&quot;);
queue.printAll();
&lt;/code&gt;&lt;/pre&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;!-- &lt;div class=&quot;mt-4 border rounded-xl p-4 bg-gray-900 text-white font-mono&quot;&gt;
      &lt;div class=&quot;flex border-b border-gray-700&quot;&gt;
        &lt;button
          class=&quot;px-4 py-2 bg-gray-800 text-white font-semibold rounded-t-md focus:outline-none language-tab active&quot;
          data-lang=&quot;javascript&quot;
          onclick=&quot;switchLanguage(&#39;javascript&#39;)&quot;
        &gt;
          JavaScript
        &lt;/button&gt;
      &lt;/div&gt;
      &lt;div class=&quot;mt-4&quot;&gt;
        &lt;pre
          id=&quot;code-javascript&quot;
          class=&quot;language-javascript&quot;
          &gt;&lt;code&gt;
// this represents the a single node in the linked list
// holding one ticket
class TicketNode {
    constructor(data) {
        this.data = data;
        this.next = null;
    }
}

// this class will be managing the queue of tickets using Linked List
// keeping the track of head(first node) and tail(last node) nodes
class TicketQueue {
    constructor() {
        this.head = null;
        this.tail = null;
    }
    
    // enqueue method adds a new ticket to the end of the queue
    // (FIFO principle : last in, processed last)
    // time complexity : O(1), as it only involves creating a node and updating
    // pointers

    enqueue(data) {
        const newNode = new TicketNode(data);
        if (!this.head) {
            this.head = newNode;
            this.tail = newNode;
        } else {
            this.tail.next = newNode;
            this.tail = newNode;
        }
    }

    // this method removes and returns the ticket at the front of the queue
    // FIFO : first in, processed first
    // O(1) : as it only updates the pointer
    dequeue() {
        if (!this.head) return null;
        const removed = this.head.data;
        this.head = this.head.next;
        if (!this.head) this.tail = null;
        return removed;
    }

    // printAll method is like reading and displaying
    // O(n) : where n is the number of nodes, because its going to visit each node once 
    printAll() {
        let current = this.head;
        let index = 1;
        while (current) {
            console.log(`${index++}. ${current.data}`);
            current = current.next;
        }
    }
}

const queue = new TicketQueue();
queue.enqueue(&quot;Ticket #001: Login issue&quot;);
queue.enqueue(&quot;Ticket #002: Payment error&quot;);
queue.enqueue(&quot;Ticket #003: Forgot password&quot;);

console.log(&quot;Processing:&quot;, queue.dequeue());

console.log(&quot;Remaining Tickets:&quot;);
queue.printAll();
&lt;/code&gt;&lt;/pre&gt;
       
      &lt;/div&gt;
    &lt;/div&gt; --&gt;
    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;Now what is FIFO ?? its a simple way of saying how the data will be flowing in a particular way, like FIFO means First In First Out, and on the other hand we have LIFO which means Last In First Out&lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;As an engineer I would have questioned, how would I optimize a linked list for faster read operations if traversal time becomes a bottleneck ??&lt;/p&gt;


    &lt;h1 class=&quot;text-2xl font-bold mt-7 font-serif&quot;&gt;HashMaps&lt;/h1&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;Hash maps or Hash tables, are just like arrays but here the values of a key instead of a index number, which makes it a key-value pair. This makes the reading, inserting and deleting process faster typically O(1) on average. Hash maps use a clever trick called hashing to map keys directly to their values, making them incredibly efficient for specific use cases.&lt;/p&gt;

    &lt;p class=&quot;font-serif text-lg mt-3&quot;&gt;For example if we are storing capitals of a country then instead of indexing we can store the country name instead.&lt;/p&gt;

    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/dsa/hashmaps.png&quot; class=&quot;my-10 w-[85%] mx-auto&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;Here is a small example which I learned in python, it is also known as dictionary in python&lt;/p&gt;


    &lt;div class=&quot;mt-4 border rounded-xl p-4 bg-gray-900 text-white font-mono&quot; id=&quot;code-div-5&quot;&gt;
      &lt;div class=&quot;flex justify-between items-center border-b border-gray-700&quot;&gt;
        &lt;div class=&quot;flex&quot;&gt;
          &lt;button class=&quot;px-4 py-2 bg-gray-800 text-white font-semibold rounded-t-md focus:outline-none language-tab active&quot; data-lang=&quot;javascript&quot; onclick=&quot;switchLanguage(&#39;javascript&#39;, &#39;code-div-5&#39;)&quot;&gt;
            Python
          &lt;/button&gt;
        &lt;/div&gt;
        &lt;button class=&quot;px-4 py-2 text-gray-400 hover:text-white focus:outline-none&quot; onclick=&quot;toggleCollapse(&#39;code-div-5&#39;)&quot;&gt;
          Expand
        &lt;/button&gt;
      &lt;/div&gt;
      &lt;div class=&quot;mt-4 code-content hidden&quot;&gt;
        &lt;pre id=&quot;code-python&quot; class=&quot;language-python&quot;&gt;&lt;code&gt;user_map = {}

# Setting up Key-value pair 
user_map[&quot;mrinaltest@example.com&quot;] = {&quot;name&quot;: &quot;Mrinal&quot;, &quot;id&quot;: 123}
user_map[&quot;mrinaltest2@example.com&quot;] = {&quot;name&quot;: &quot;Pramanick&quot;, &quot;id&quot;: 456}

# Lookup in O(1) average time
print(user_map[&quot;mrinaltest3@example.com&quot;]) 
# Output: {&quot;name&quot;: &quot;Pramanick&quot;, &quot;id&quot;: 123}
&lt;/code&gt;&lt;/pre&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;Lets talk about memory little bit. Hash maps gives up on memory for speed. They allocate fized-size, which might waste space if not full utilized. Collisions can also slow things down if the hash function isn&#39;t well-designed or the load factor (ratio of entries to array size) gets to high. Unlike linked lists, hash maps don&#39;t preserve insertion order so they&#39;re not suited for sequential processing.&lt;/p&gt;

    &lt;h1 class=&quot;text-2xl font-bold mt-7 font-serif&quot;&gt;Stacks and Queues&lt;/h1&gt;

    &lt;p class=&quot;text-lg font-serif&quot;&gt;So you might have question what if we need to maintain the order of elements while also needing fast lookups ?? Here comes stacks, its a linear data structure that follows the Last In, First Out(LIFO) principle. A simple explaination of stacks would be a stack of plate, the first plate would be at bottom and picked at last, and the last plate would be picked up at first&lt;/p&gt;
    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/dsa/stacks.png&quot; class=&quot;w-[55%] my-10 mx-auto&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

    &lt;p class=&quot;font-serif text-lg&quot;&gt;there are four major operations performed on this and the upcoming data structure which are &lt;span class=&quot;font-bold&quot;&gt;Push&lt;/span&gt; (add an element to the top (O(1)). &lt;span class=&quot;font-bold&quot;&gt;Pop&lt;/span&gt; (remove and return the top element (O(1)). &lt;span class=&quot;font-bold&quot;&gt;&lt;/span&gt; &lt;span class=&quot;font-bold&quot;&gt;Peek/Top&lt;/span&gt; (view the top element without removing it (O(1)). &lt;span class=&quot;font-bold&quot;&gt;IsEmpty&lt;/span&gt; checks if the stack is empty (O(1))&lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-2&quot;&gt;My favourite part MEMORY, stacks can be implemented using arrays or linked lists. An array-based stack requires a fixed or dynamically resized array, which may waste space if not fully utilized(similar to hash maps). A linked list-based stack allocates memory per node (data + pointer), growing or shrinking dynamically like a linked list.    &lt;br&gt; Linked list-based stacks avoid resizing overhead but may cause memory fragmentation, as nodes are non-contiguous. Array-based stacks are more memory-efficient for predictable sizes but require resizing if the stack grows beyond capacity, temporarily doubling memory use during resizing &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;The best pactical way to use stacks is by building a UNDO or REDO funtion, each user action (e.g., typing or deleting) is to be pushed onto a stack. Pressing &quot;undo&quot; popped the most recent action, reverting the change. A stack is ideal because the last action needed to be undone first
    &lt;/p&gt;


    &lt;div class=&quot;mt-4 border rounded-xl p-4 bg-gray-900 text-white font-mono&quot; id=&quot;code-div-6&quot;&gt;
      &lt;div class=&quot;flex justify-between items-center border-b border-gray-700&quot;&gt;
        &lt;div class=&quot;flex&quot;&gt;
          &lt;button class=&quot;px-4 py-2 bg-gray-800 text-white font-semibold rounded-t-md focus:outline-none language-tab active&quot; data-lang=&quot;javascript&quot; onclick=&quot;switchLanguage(&#39;javascript&#39;, &#39;code-div-5&#39;)&quot;&gt;
            Python
          &lt;/button&gt;
        &lt;/div&gt;
        &lt;button class=&quot;px-4 py-2 text-gray-400 hover:text-white focus:outline-none&quot; onclick=&quot;toggleCollapse(&#39;code-div-6&#39;)&quot;&gt;
          Expand
        &lt;/button&gt;
      &lt;/div&gt;
      &lt;div class=&quot;mt-4 code-content hidden&quot;&gt;
        &lt;pre id=&quot;code-python&quot; class=&quot;language-python&quot;&gt;&lt;code&gt;class UndoStack:
def __init__(self):
    self.stack = []

def push_action(self, action):
    self.stack.append(action)

def undo(self):
    if self.stack:
        return self.stack.pop()
    return None

def is_empty(self):
    return len(self.stack) == 0

undo_stack = UndoStack()
undo_stack.push_action({&quot;id&quot;: 1, &quot;type&quot;: &quot;type&quot;, &quot;value&quot;: &quot;Hello&quot;})
undo_stack.push_action({&quot;id&quot;: 2, &quot;type&quot;: &quot;delete&quot;, &quot;value&quot;: &quot;o&quot;})
print(undo_stack.undo())  
# Output: {&quot;id&quot;: 2, &quot;type&quot;: &quot;delete&quot;, &quot;value&quot;: &quot;o&quot;}
&lt;/code&gt;&lt;/pre&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;&lt;span class=&quot;font-bold&quot;&gt;Queues&lt;/span&gt; are just opposite to stacks they follow the FIFO principle which means First In First Out,  like a line at a ticket counter: the first person in line is served first. Queues are ideal for processing tasks in the order they arrive. Also queues and stacks share the same memory implications&lt;/p&gt;
    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;One of the best ways to visualize a stack is with a YouTube channel&#39;s video list. The most recently uploaded video appears at the top, while the oldest video is at the bottom, resembling a stack&#39;s Last In, First Out (LIFO) structure.    &lt;/p&gt;


    &lt;p class=&quot;text-lg mt-4 font-serif&quot;&gt;The upcoming topics are one the best things I have learned so far, also do give some attempts for solving the few questions related to all the topics enlisted here :)&lt;/p&gt;

    &lt;h1 class=&quot;text-2xl font-bold mt-7 font-serif&quot;&gt;Trees&lt;/h1&gt;
   &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;Trees are hierarchical data structures consisting of nodes connected by edges, with a single root node at the top and child nodes branching out. Each node can have zero or more children, and nodes without children are called leaves.&lt;/p&gt;

   &lt;div class=&quot;flex justify-between my-4 max-sm:block&quot;&gt;
    &lt;p class=&quot;font-serif text-lg &quot;&gt;Nodes have parent child direction,  where each node (except the root) has exactly one parent, and a parent node can have zero or more children. This directional structure defines the hierarchy, with edges pointing from parent to child, enabling efficient modeling of relationships like organizational charts or file systems.    &lt;/p&gt;
    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/dsa/parent.png&quot; class=&quot;w-[40%]&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
   &lt;/div&gt;

   &lt;p class=&quot;text-lg mt-3 font-serif&quot;&gt;Knowing little about memory here, trees are memory efficient for hierarchical data but fragmented due to dynamic allocation, if a tree is balanced it optimizes memory and performance by keeping height low, while unbalanced trees waste memory on pointers for deep, linear structures&lt;/p&gt;

   &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;A question would pop on your mind, what is even a balanced tree ?? So memory scales with the number of nodes (O(n)). A balanced tree with n nodes has a height of O(log n), minimizing traversal time, while an unbalanced tree may resemble a linked list with O(n) height&lt;/p&gt;

   &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;Lets talk more indepthly about trees using Binary Search tree, a tree where the left child&#39;s value is less than the parent&#39;s, and the right child&#39;s value is greater, this enables O(log n) searches, insertions, deletions if balanced, but O(n) if skewed&lt;/p&gt;

   &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/dsa/bst.png&quot; class=&quot;mx-auto&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

   &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;One best usecase for BST could implementing a topic from my blog about &lt;i&gt;&lt;a href=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/system-design.html&quot;&gt;System Design&lt;/a&gt;&lt;/i&gt; which is database indexing for ordered data retrieval&lt;/p&gt;

   &lt;div class=&quot;mt-4 border rounded-xl p-4 bg-gray-900 text-white font-mono&quot; id=&quot;code-div-7&quot;&gt;
      &lt;div class=&quot;flex justify-between items-center border-b border-gray-700&quot;&gt;
        &lt;div class=&quot;flex&quot;&gt;
          &lt;button class=&quot;px-4 py-2 bg-gray-800 text-white font-semibold rounded-t-md focus:outline-none language-tab active&quot; data-lang=&quot;javascript&quot; onclick=&quot;switchLanguage(&#39;javascript&#39;, &#39;code-div-5&#39;)&quot;&gt;
            Python
          &lt;/button&gt;
        &lt;/div&gt;
        &lt;button class=&quot;px-4 py-2 text-gray-400 hover:text-white focus:outline-none&quot; onclick=&quot;toggleCollapse(&#39;code-div-7&#39;)&quot;&gt;
          Expand
        &lt;/button&gt;
      &lt;/div&gt;
      &lt;div class=&quot;mt-4 code-content hidden&quot;&gt;
        &lt;pre id=&quot;code-python&quot; class=&quot;language-python&quot;&gt;&lt;code&gt;
class BSTNode:
# record ID or file name
# e.g., metadata (record details)
def __init__(self, key, value):
  self.key = key       
  self.value = value    
  self.left = None      # Left child
  self.right = None     # Right child

class DatabaseIndex:
    def __init__(self):
        self.root = None
    
    def insert(self, key, value):
        &quot;&quot;&quot;Insert a key-value pair into the BST.&quot;&quot;&quot;
        if not self.root:
            self.root = BSTNode(key, value)
        else:
            self._insert_recursive(self.root, key, value)
    
    def _insert_recursive(self, node, key, value):
        &quot;&quot;&quot;Helper method for recursive insertion.&quot;&quot;&quot;
        if key &amp;lt; node.key:
            if node.left is None:
                node.left = BSTNode(key, value)
            else:
                self._insert_recursive(node.left, key, value)
        else:
            if node.right is None:
                node.right = BSTNode(key, value)
            else:
                self._insert_recursive(node.right, key, value)
    
    def inorder_retrieval(self):
        &quot;&quot;&quot;Retrieve all records in sorted order (inorder traversal).&quot;&quot;&quot;
        result = []
        self._inorder_recursive(self.root, result)
        return result
    
    def _inorder_recursive(self, node, result):
        &quot;&quot;&quot;Helper method for inorder traversal.&quot;&quot;&quot;
        if node:
            self._inorder_recursive(node.left, result)
            result.append((node.key, node.value))  # Store key-value pair
            self._inorder_recursive(node.right, result)

# Database indexing for ordered retrieval
db_index = DatabaseIndex()
# Insert records (e.g., file names or IDs with metadata)
db_index.insert(&quot;file1.pdf&quot;, {&quot;size&quot;: 100, &quot;path&quot;: &quot;/docs/file1.pdf&quot;})
db_index.insert(&quot;file3.pdf&quot;, {&quot;size&quot;: 300, &quot;path&quot;: &quot;/docs/file3.pdf&quot;})
db_index.insert(&quot;file2.pdf&quot;, {&quot;size&quot;: 200, &quot;path&quot;: &quot;/docs/file2.pdf&quot;})

# Retrieve records in sorted order (by key)
ordered_records = db_index.inorder_retrieval()
for key, value in ordered_records:
    print(f&quot;Key: {key}, Value: {value}&quot;)
# Output:
# Key: file1.pdf, Value: {&#39;size&#39;: 100, &#39;path&#39;: &#39;/docs/file1.pdf&#39;}
# Key: file2.pdf, Value: {&#39;size&#39;: 200, &#39;path&#39;: &#39;/docs/file2.pdf&#39;}
# Key: file3.pdf, Value: {&#39;size&#39;: 300, &#39;path&#39;: &#39;/docs/file3.pdf&#39;}
&lt;/code&gt;&lt;/pre&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;Graphs and algorithms need separate attention, so I am working on those blogs in my free time. If you urgently need those you can ping me or mention me on X(@Hi_Mrinal) will release it asap. Hope I was able to add few value to your todays learning :)) &lt;br&gt; Happy Learning Anon :)&lt;/p&gt;

    &lt;hr class=&quot;my-10&quot;&gt;
    

    &lt;!-- &lt;script&gt;
      // function switchLanguage(lang) {
      //     // Hide all code blocks
      //     document.querySelectorAll(&#39;pre[id^=&quot;code-&quot;]&#39;).forEach((pre) =&gt; {
      //       pre.classList.add(&#39;hidden&#39;);
      //     });
      //     // Show selected language
      //     document.getElementById(`code-${lang}`).classList.remove(&#39;hidden&#39;);
      //     // Update active tab
      //     document.querySelectorAll(&#39;.language-tab&#39;).forEach((tab) =&gt; {
      //       tab.classList.remove(&#39;active&#39;);
      //       tab.classList.add(&#39;text-gray-400&#39;);
      //       tab.classList.remove(&#39;text-white&#39;, &#39;bg-gray-800&#39;);
      //       tab.classList.add(&#39;bg-gray-900&#39;);
      //     });
      //     const activeTab = document.querySelector(`button[data-lang=&quot;${lang}&quot;]`);
      //     activeTab.classList.add(&#39;active&#39;, &#39;text-white&#39;, &#39;bg-gray-800&#39;);
      //     activeTab.classList.remove(&#39;text-gray-400&#39;, &#39;bg-gray-900&#39;);
      //   }

      //   function toggleCollapse(id) {
      //     const element = document.getElementById(id);
      //     if (element.classList.contains(&#39;hidden&#39;)) {
      //       element.classList.remove(&#39;hidden&#39;);
      //     } else {
      //       element.classList.add(&#39;hidden&#39;);
      //     }
      //   }

      function switchLanguage(lang, divId) {
        // Hide all code blocks within the specified div
        document
          .querySelectorAll(`#${divId} pre[id^=&quot;code-&quot;]`)
          .forEach((pre) =&gt; {
            pre.classList.add(&quot;hidden&quot;);
          });
        // Show selected language
        document
          .getElementById(`code-${lang}-${divId}`)
          .classList.remove(&quot;hidden&quot;);
        // Update active tab
        document.querySelectorAll(`#${divId} .language-tab`).forEach((tab) =&gt; {
          tab.classList.remove(&quot;active&quot;);
          tab.classList.add(&quot;text-gray-400&quot;);
          tab.classList.remove(&quot;text-white&quot;, &quot;bg-gray-800&quot;);
          tab.classList.add(&quot;bg-gray-900&quot;);
        });
        const activeTab = document.querySelector(
          `#${divId} button[data-lang=&quot;${lang}&quot;]`
        );
        activeTab.classList.add(&quot;active&quot;, &quot;text-white&quot;, &quot;bg-gray-800&quot;);
        activeTab.classList.remove(&quot;text-gray-400&quot;, &quot;bg-gray-900&quot;);
      }

      function toggleCollapse(divId) {
        const element = document.querySelector(`#${divId} .code-content`);
        const button = document.querySelector(
          `#${divId} button[onclick^=&quot;toggleCollapse&quot;]`
        );
        if (element.classList.contains(&quot;hidden&quot;)) {
          element.classList.remove(&quot;hidden&quot;);
          button.textContent = &quot;Collapse&quot;;
        } else {
          element.classList.add(&quot;hidden&quot;);
          button.textContent = &quot;Expand&quot;;
        }
      }
    &lt;/script&gt;
     --&gt;

    
  




</description><link>https://mrinalxdev.github.io/mrinalxblogs/blogs/dsa-practical.html</link><guid isPermaLink="false">https://mrinalxdev.github.io/mrinalxblogs/blogs/dsa-practical.html</guid><pubDate>Invalid Date</pubDate><author>Mrinal</author></item><item><title>How to Read Research Papers</title><description>&lt;hr class=&quot;mt-3&quot;&gt;

    &lt;h1 class=&quot;text-4xl mt-[57px] mb-3 font-serif&quot;&gt;
      Reading Research Papers 101
    &lt;/h1&gt;
    &lt;span class=&quot;text-sm text-gray-500&quot;&gt;18th May, 2025&lt;/span&gt;

    &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;
      After reading white papers for a long peried, I have noticed that academic
      papers can hard to understand because of jargons and complex ideas, but
      they hold a lot of valuable information if we learn how to read to them.
    &lt;/p&gt;

    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/research-paper/banner.png&quot; class=&quot;size-[600px] mx-auto my-5 rounded-xl&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
    &lt;p class=&quot;text-sm text-gray-500 font-serif&quot;&gt;
      Two papers which I haven&#39;t read
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;
      I get it, there are lots of research papers related to ai, backend,
      infrastructure coming out weekly. People posting I have read this paper,
      learned X Y Z and sometimes people (me) post that they have mimic the
      benchmarks and logic of the paper to build something out of it as a
      project and sometimes these projects can stand out from others and create
      a big difference.
    &lt;/p&gt;

    &lt;p class=&quot;font-serif text-lg mt-3&quot;&gt;
      But now you are excited, searched for papers from perplexity, it showed a
      arivx paper, you installed the pdf of the paper. NOW WHATT !! you go
      through the paper understand nil about the topic nor did you get the
      abstract :((
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-2&quot;&gt;
      I have nearly read 30 ~ 35 papers this year from papers having 5 pages to
      papers having 30+ pages, so thought to write a little bit on how to start
      reading :)) &lt;br&gt;
      Okkay first of all I want you to develop the ...
    &lt;/p&gt;
    &lt;h1 class=&quot;text-3xl font-serif mt-6&quot;&gt;&quot;Why am I reading this ?&quot; habbit&lt;/h1&gt;
    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      Always have this question before staring any paper. This may looks simple
      but it really matters on how are your learnings from this paper will go
      through. Defining the purpose sharpens our focus, saves time and esures we
      extract meaningful insights from the paper, whether it&#39;s 5 page or 100+
      page paper.
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-2&quot;&gt;
      Now you would have the question, How to even build this habbit ?? so here
      is my trick before opening the PDF, take 30 seconds to jot down your
      purpose. Be specific. Instead of “I want to learn AI,” try “I want to
      understand how this paper’s attention mechanism improves model efficiency
      for my chatbot project.” Revisit this why if you feel lost mid-paper, it’s
      our anchor.
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      You have your paper installed, you got your &quot;Why&quot; now what ?? ...
    &lt;/p&gt;

    &lt;h1 class=&quot;text-3xl font-serif mt-6&quot;&gt;The Helicopter View&lt;/h1&gt;

    &lt;p class=&quot;text-lg font-serif mt-2&quot;&gt;
      Okkay starting with the second step, you need to know if the paper is
      really falling under your category of learning or the paper should be just
      surfed around.
      &lt;span class=&quot;font-bold&quot;&gt;What does surfed around means ??&lt;/span&gt; for me I
      dont really read papers to gain core knowledge, sometimes I read different
      genre research papers to gain a general knowledge of different fields so
      that when time comes I can really brag about it in twitter spaces or
      meetups and gain some new friends who can really teach me more :))
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-2&quot;&gt;
      So comming back to our topic what is even
      &lt;span class=&quot;font-bold&quot;&gt;Helicopter View&lt;/span&gt; ?? .. its just skimming the
      whole paper or just the title and abstract and categorize the paper, for
      me I my categories are core learning (learning related to skillset I own
      for now), surfing(just to read and take small notes), time pass(nothing
      serious just reading it to make a habbit).
    &lt;/p&gt;
    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/research-paper/bird%20eye%20view.png&quot; class=&quot;my-4&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

    &lt;p class=&quot;text-lg font-serif mt-2&quot;&gt;
      This step helps me decide if I should go all in for paper and complete the
      paper in 1 ~ 2 weeks digging deep around the topics of the paper or just
      chill with the paper
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      You have gone through the title and the abstract, it&#39;s a paper that
      attracts your interest for learning and diving deep into the topic. Now
      what ?? .. Read it anon
    &lt;/p&gt;

    &lt;h1 class=&quot;mt-6 font-serif text-3xl&quot;&gt;Get the Hooks&lt;/h1&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      This is what I do with most of the papers I dig deep into, after skimming
      the paper once I note down these questions and try to answer it my self,
      &lt;span class=&quot;font-bold&quot;&gt;What are the main research question ?&lt;/span&gt;,
      &lt;span class=&quot;font-bold&quot;&gt;What methods did they use ?&lt;/span&gt;,
      &lt;span class=&quot;font-bold&quot;&gt;What are the main conclusions ?&lt;/span&gt; getting
      some of the core details help me to finish the paper with more
      understanding in least amount time spent on it.
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-2&quot;&gt;
      Why does this work ? Answering these questions forces me to engage with
      the paper’s big picture before I get bogged down in details. For example,
      identifying the main research question tells me what problem the authors
      are tackling maybe it’s improving neural network efficiency or optimizing
      database queries. Knowing the methods (e.g., a novel algorithm or a
      specific dataset) gives me a sense of how they approached it, which is
      critical if I&#39;m planning to replicate or build on their work. And the
      conclusions? They’re the payoff—what did the authors prove or discover?
      These hooks anchor my reading, so I&#39;m not just passively scanning pages.
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-2&quot;&gt;
      This step also helps me decide my commitment level. Let’s say the paper’s
      research question aligns perfectly with my project, and the methods are
      something I can experiment with. That’s my signal to go deep—maybe spend a
      week reading related papers or coding a small prototype. On the flip side,
      if the conclusions are interesting but not directly relevant, I can chill,
      extract the key takeaways, and move on. I’ve saved hours by using these
      hooks to avoid over-investing in papers that sound cool but don’t serve my
      goals.
    &lt;/p&gt;

    &lt;h1 class=&quot;text-3xl font-serif mt-6&quot;&gt;Eye to Eye with the paper&lt;/h1&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;
      Now, if I’ve decided to go all-in, it’s time to get eye to eye with the
      paper. When diving deep into the topics of research papers, I like to
      print a hard copy. There’s something about holding those pages that gives
      me a sense of responsibility to complete the paper. Replicating the system
      built by the authors give me a deeper knowledge of the methods and thier
      approach. I break the paper into sections and tackle them over a few days.
      For example, I’ll spend one session on the introduction and background to
      get the context, another on the methodology to understand the nuts and
      bolts, and a third on results and discussion to see what it all means.
      This paced approach prevents burnout and lets me absorb complex ideas. If
      the paper has code or datasets (check GitHub or the authors’ website!), I
      download them and start experimenting. Even a small replication like
      running their model on a toy dataset—can reveal insights that skimming
      never will.
    &lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;How do I even remember what I have read and implemented ?? ..&lt;/p&gt;

    &lt;h1 class=&quot;text-3xl font-serif mt-6&quot;&gt;Teach someone about the paper&lt;/h1&gt;

    &lt;p class=&quot;text-lg font-serif mt-2&quot;&gt;I tend to teach the learnings of my paper either to one of my best friend or record a video while explaining the paper deeply which also enhances my speaking part and expands my vocabulary&lt;/p&gt;

    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/research-paper/rubber.png&quot; class=&quot;mx-auto my-5 rounded-xl&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;Me explaining my best friend about the distributed system paper which I read. :))&lt;/p&gt;

    &lt;h1 class=&quot;text-xl font-serif mt-4&quot;&gt;Something to note&lt;/h1&gt;
    &lt;p class=&quot;text-lg font-serif mt-2&quot;&gt;Often times the writing structure of the paper is bad becuase sometimes English is the second language for the author. There maybe some grammatical mistakes or punctuation mistakes but the most important thing should be the outcome or the message from the paper. &lt;br&gt;
    after finishing the paper, I always drop my notes as a cold email to the authors gmail and send a thank you message from my side just as a token of appreciation :))&lt;/p&gt;


    &lt;p class=&quot;text-lg mt-3 font-serif&quot;&gt;Hope I was able to add value to your today&#39;s learning goal !! Happy Learning ..&lt;/p&gt;
    &lt;hr class=&quot;my-10&quot;&gt;
    
  

</description><link>https://mrinalxdev.github.io/mrinalxblogs/blogs/researchpaper.html</link><guid isPermaLink="false">https://mrinalxdev.github.io/mrinalxblogs/blogs/researchpaper.html</guid><pubDate>Invalid Date</pubDate><author>Mrinal</author></item><item><title>Concurrency from a Beginners POV</title><description>&lt;hr class=&quot;mt-3&quot;&gt;

    
    &lt;h1 class=&quot;text-4xl mt-[57px] mb-3 font-serif&quot;&gt;Concurrency 101 : From a Beginners POV&lt;/h1&gt;
    &lt;span class=&quot;text-sm text-gray-500&quot;&gt;10th May, 2025&lt;/span&gt;

    &lt;p class=&quot;text-lg font-serif mt-2&quot;&gt;Concurrency has always been a difficult topic for me to wrap my head around, eiter be it in golang, javascript or python. Python and JavaScript approach concurrency in different ways because of their runtime environments. In this blog I want to deep dive into theory of concurrency because if we understand the engineering behind these topics we can easily code out it any language, thats what I believe. &lt;/p&gt;

    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/concurrency/banner.png&quot; class=&quot;w-[450px] mx-auto my-4&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

    &lt;p class=&quot;text-lg font-serif mt-2&quot;&gt;Concurrency is not about doing many things at once, but about managing multiple tasks in a way that makes progress on all of them, even if they take turns, in todays time it helps to build faster, more reponsive, and scalable applications.&lt;/p&gt;

    &lt;h1 class=&quot;text-3xl font-serif mt-8&quot;&gt;What is Concurrency ??&lt;/h1&gt;
    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;It is the ability of a program to manage multiple tasks at the same time. Concurrency dosen&#39;t necessarily mean these tasks are happening simultaneously ( like in parallel processing), it means they&#39;re interleaved or coordinated to make progress together. In programming, concurrency lets our app respond to user clicks while downloading data or processing a file.&lt;/p&gt;

    &lt;p class=&quot;text-lg mt-3 font-serif&quot;&gt;it makes our program faster, more responsive, and efficient. Without it, our app might freeze while waiting for a slow database query which will make the users frustate and leave our app.&lt;/p&gt;

    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;You might get a question if concurrency is about managing multiple tasks, how does a program actually switch between them without causing chaos ??

     &lt;br&gt; So moving to our next topic
    &lt;/p&gt;

    &lt;h1 class=&quot;text-3xl font-serif mt-8&quot;&gt;Switching between tasks in Concurrency &lt;/h1&gt;
    &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;Programs switch tasks using mechanisms like threads, processes, or event loops, managed by the operating system or the runtime. The CPU can only do one thing at a time, but by rapidly switching, it feels like multitasking&lt;/p&gt;

    &lt;ul class=&quot;list-disc ml-4 text-lg font-serif mt-5&quot;&gt;
        &lt;li class=&quot;&quot;&gt;&lt;span class=&quot;underline underline-offset-4&quot;&gt;Process&lt;/span&gt; : Independent execution units with their own memory space, managed by the operating system. Each process has its own address space, stack and resources. For example, running two python scripts spawns two process. Processes communicate via inter-process communication (IPC) mechanisms like pipes, sockets, or shared files. They are heavyweight due to memory isolation but sage since they don&#39;t share data directly.&lt;/li&gt;

        &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/concurrency/process.png&quot; class=&quot;my-4&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
        &lt;p&gt;this is what process looks like under the hood, every other process has its own sets of code memory space and stack resource &lt;/p&gt;

        &lt;li class=&quot;&quot;&gt;&lt;span class=&quot;underline underline-offset-4&quot;&gt;Threads&lt;/span&gt; : its lightweight execution units within a process, sharing same memory space. They are managed by the OS and are cheaper to create than processes ( less memory overhead ), however shared memoery introduces risks like race conditions.&lt;/li&gt;

        &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/concurrency/multi-threaded.png&quot; class=&quot;my-4&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

        &lt;p&gt; this is what shared memory space looks like :))&lt;/p&gt;

        &lt;li&gt;&lt;span class=&quot;underline underline-offset-4&quot;&gt;Event Loops&lt;/span&gt; : A single threaded mechanism that multiplexes tasks by processing a queue of events (eg. user clicks, I/O completions). The event loop checks for pending events, runs their handlers, and yields control when tasks wait (eg. a for a network reponse). Its like a waiter taking orders one at a time but moving fast keep tables happy. &lt;/li&gt;

        &lt;p&gt;the operating system&#39;s scheduler decides which task runs when, using context switching (saving and restoring task state), and for threads and processes, the scheduler uses preemption (pausing a task to run another) which are based on priorities and time slices.&lt;/p&gt;

      &lt;/ul&gt;
      &lt;p class=&quot;italic my-3 font-serif&quot;&gt;Here is note from my side, context switching for processes is costlier than for threads due to memory management (e.g., updating page tables). Event loops minimize switching overhead by staying single-threaded, but they require tasks to be non-blocking. Example: In C, pthread_create spawns a thread with low overhead (~10µs), while fork() for a process takes ~100µs due to memory copying.&lt;/p&gt;

      &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;Okkay now after all this you might have a question if threads share memory, how do we prevent chaos when they access the same data simultaneously ?? &lt;/p&gt;
        
    &lt;div class=&quot;font-serif&quot;&gt;
      &lt;h1 class=&quot;text-3xl mt-8&quot;&gt;Preventing chaos when threads access shared data&lt;/h1&gt;
      &lt;p class=&quot;mt-4 text-lg&quot;&gt;Shared memory threads risks race conditions, where the outcome depends on unpredictable execution order. Lets take two threads incrementing a shared variable &lt;span class=&quot;italic&quot;&gt;counter = counter + 1&lt;/span&gt;. The operation involves three steps : read &lt;span class=&quot;italic&quot;&gt;counter&lt;/span&gt;, increment, write back. If both threads readd &lt;span class=&quot;italic&quot;&gt;counter&lt;/span&gt; as 10, increment to 11, and write, the final value is 11 instead of 12 due to overwriting.&lt;/p&gt;

      &lt;ul class=&quot;ml-4 mt-4 text-lg list-disc&quot;&gt;
        &lt;li class=&quot;&quot;&gt;&lt;span class=&quot;underline underline-offset-4&quot;&gt;Locks (Mutexes) &lt;/span&gt;: Ensure only one thread access shared data at a time. It acts like a key, if a thread locks the mutex, no other thread can enter the protected section until the original thread unlocks it. This prevents race conditions when multiple threads try to read or modify the same data simultaneously.&lt;/li&gt;

        &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/concurrency/locks.png&quot; class=&quot;my-5 w-[550px] mx-auto&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
        &lt;p class=&quot;text-lg font-serifmb-3&quot;&gt;Internal workings of locks in a unit of execution&lt;/p&gt;
        &lt;li class=&quot;mt-3&quot;&gt;&lt;span class=&quot;underline underline-offset-4&quot;&gt;Semaphore&lt;/span&gt; : A semaphore is a more flexible synchronization mechanism than a mutex. It maintains an internal counter representing the number of available resources. Threads can wait on the semaphore (decrementing the counter), and if the counter becomes negative, the thread blocks until another thread signals (increments the counter)&lt;/li&gt;
        &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/concurrency/semaphores.png&quot; class=&quot;my-5 w-[400px] mx-auto&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
        &lt;p class=&quot;text-lg font-serif&quot;&gt;Internal working of sempahores in a unit of execution &lt;/p&gt;
      &lt;/ul&gt;

      &lt;p class=&quot;text-lg mt-3 &quot;&gt;These primitives are implemente using OS-level constructs or hardware instructions. However, they introduce overhead and risks like priority inversion, where a low priority thread holding a lock delays a high-priority one.&lt;/p&gt;

      &lt;p class=&quot;text-lg mt-3&quot;&gt;So now what is overhead, and if locks add overhead and complexity, what to do if threads get stuck waiting for each other ?? But before this we need to know ..&lt;/p&gt;

      &lt;h1 class=&quot;text-3xl mt-5&quot;&gt;What happens when threads get stuck waiting for locks ??&lt;/h1&gt;

      &lt;p class=&quot;mt-3 text-lg&quot;&gt;Lock, like mutexes or semaphores are essential for preventing race conditions when threads access shared data, but they introduce challenges like deadlocks, livelocks and performance overhead, but first &lt;span class=&quot;font-bold&quot;&gt;what is overhead ?&lt;/span&gt;, it refers to the extra computational cost or resources consume by a system, process or operation which is not directly linked to the main task.&lt;/p&gt;

      &lt;ul class=&quot;ml-4 list-disc mt-4 text-lg&quot;&gt;
        &lt;li&gt;&lt;span class=&quot;underline underline-offset-4&quot;&gt;Deadlocks&lt;/span&gt; : This occurs when two or more threads are stuck, each waiting for a resource another holdds, forming a cicular dependency. Its like Chef A has the knife and needs the cutting board, while cheg B has the cutting board and needs the knife, neither can proceed. In code, this happens when threads acquire locks in different orders. If thread1 locks lock1 and thread2 locks lock2 simultaneously, they deadlock waiting for each other’s lock.&lt;/li&gt;


        &lt;li class=&quot;mt-3&quot;&gt;&lt;span class=&quot;underline underline-offset-4&quot;&gt;Livelock&lt;/span&gt; : Threads are active but make no progress because they keep responding to each other&#39;s actions. Taking examples my friends, (i dont have any) we both stepping aside and thinking one will pass but in reality nothing happens. In code, livelocks occur in algorithms where threads retry operations in a loop without resolving conflicts.&lt;/li&gt;

        &lt;li class=&quot;mt-3&quot;&gt;&lt;span class=&quot;underline underline-offset-4&quot;&gt;Starvation&lt;/span&gt; : A thread is denied access to a resource because other threads keep acquiring the lock. This often happens with unfair lock implementation or when high-priority threads dominate.&lt;/li&gt;
      &lt;/ul&gt;

      &lt;p class=&quot;text-lg mt-3&quot;&gt;But now raises the question how do we prevent all these locks from happening ?&lt;/p&gt;

      &lt;ul class=&quot;list-disc text-lg mt-4 ml-4&quot;&gt;
        &lt;li&gt;Always acquire locks in a consistent order to prevent deadlocks, this requires careful design for your program execution and from my experience the best you can do is use comments in code to serialize your locks :)). This strategy is known as &lt;span class=&quot;font-bold&quot;&gt;Lock Ordering&lt;/span&gt;&lt;/li&gt;

        &lt;li class=&quot;mt-3&quot;&gt;Use non-blocking lock attempts to avoid waiting idefinitely or use logic which returns immediately if the lock is unavailable.&lt;/li&gt;
        &lt;li class=&quot;mt-3&quot;&gt;We can use timeouts which sets a deadline for lock acquisition, releases if the lock isn&#39;t acquired in time&lt;/li&gt;
      &lt;/ul&gt;

      &lt;p class=&quot;mt-3 text-lg&quot;&gt;If using lock is soo much hectic, can we coordinate tasks without using them at all ??&lt;/p&gt;

      &lt;h1 class=&quot;text-3xl mt-5&quot;&gt;Cordinating tasks without Locks&lt;/h1&gt;

      &lt;p class=&quot;text-lg mt-3&quot;&gt;There are two methods by which we can avoid locks that are &lt;span class=&quot;font-bold&quot;&gt;lock-free programming&lt;/span&gt; and &lt;span class=&quot;font-bold&quot;&gt;message passing&lt;/span&gt;.&lt;/p&gt;

      &lt;ul class=&quot;text-lg ml-4 list-disc&quot;&gt;
        &lt;li&gt;&lt;span class=&quot;underline underline-offset-4&quot;&gt;Lock Free Programming&lt;/span&gt; this uses atomic operations, which are hardware-supported instructions that complete in a single, uninterruptible step. These operations avoid locks by ensuring sage updates to shared data. there are some common atomic operations which includes : &lt;/li&gt;
        &lt;ul class=&quot;list-disc ml-8 text-lg&quot;&gt;
          &lt;li class=&quot;mt-3&quot;&gt;Compare and Swap : Checks if a variable has an expected value and updates it if so, atomically.&lt;/li&gt;
          &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/concurrency/lockfree.png&quot; class=&quot;my-4&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
          &lt;li class=&quot;mt-3&quot;&gt;Fetch and Add : increments a variable and returns its old value.&lt;/li&gt;
          &lt;li class=&quot;mt-3&quot;&gt;Test and Set : sets a flag and returns its previous state&lt;/li&gt;
          &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/concurrency/testandset.png&quot; class=&quot;w-[500px] mx-auto my-4&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
        &lt;/ul&gt;

        &lt;p class=&quot;text-lg mt-3&quot;&gt; Lock-free algorithms are used in data structures like queues or counters, but they’re complex to design due to issues like the ABA problem (where a value changes from A to B and back to A, confusing the algorithm).&lt;/p&gt;

        &lt;li class=&quot;mt-3&quot;&gt;&lt;span class=&quot;underline underline-offset-4&quot;&gt;Message Passing&lt;/span&gt; : Message passing avoids shared memory entirely by having tasks communicate via messages. Each task (or “actor” in the Actor Model) has its own state and processes messages from a queue, eliminating race conditions. This is common in systems like Go’s concurrency model.&lt;/li&gt;

        &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/concurrency/message.png&quot; class=&quot;my-5&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

        &lt;p class=&quot;text-lg mt-4&quot;&gt;Actor Model what are these ?? its is a way to build computer programs that can do many things at once, without getting confused. Instead of sharing data or working on the same memory like in traditional programming, everything in the Actor Model is made up of small, independent units called actors . Each actor can receive messages, make decisions, send messages to other actors, and even create new actors all on their own. &lt;/p&gt;

      &lt;/ul&gt;
      &lt;p class=&quot;text-lg mt-4&quot;&gt;We saw the problem with Locks and also solved it with Lock-free programming, now the question is with scalability for thousands of tasks&lt;/p&gt;

      &lt;h1 class=&quot;text-3xl mt-6&quot;&gt;Scaling our concurrent program for many tasks&lt;/h1&gt;

      &lt;ul class=&quot;list-disc mt-4 text-lg ml-4&quot;&gt;
        &lt;li class=&quot;&quot;&gt;&lt;span class=&quot;underline underline-offset-4&quot;&gt;Processes&lt;/span&gt; : Scale by distributing tasks across cores or machines. Python’s multiprocessing.Pool creates a fixed number of processes (~10MB each), communicating via Queue. Distributed systems like Apache Spark use processes across nodes, coordinated via network messages. Processes are robust but memory-intensive, ideal for CPU-bound tasks like data analysis. &lt;/li&gt;

        &lt;li class=&quot;mt-3&quot;&gt;&lt;span class=&quot;underline underline-offset-4&quot;&gt;Threads&lt;/span&gt; : Scale using thread pools, which reuse threads (~1MB stack) to avoid creation overhead. Thread pools cap concurrency (e.g., 100 threads) to prevent exhaustion, using work-stealing algorithms for load balancing. Shared memory requires synchronization, limiting scalability under contention.&lt;/li&gt;
      &lt;/ul&gt;

      &lt;p class=&quot;text-lg mt-3&quot;&gt; Event loops scale via OS multiplexing (epoll handles ~1M events), while thread pools optimize via work-stealing. Processes leverage distributed logs (e.g., Spark’s RDDs) for massive scale. Performance depends on workload: Input/Output-bound favors event loops, CPU-bound favors processes/threads.&lt;/p&gt;

    &lt;/div&gt;

    &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/concurrency/free.png&quot; class=&quot;w-[350px] mx-auto my-7&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;


   
      &lt;p class=&quot;text-lg font-serif mt-3&quot;&gt;Hope I was able to add value to your today&#39;s learning goal !! Happy Learning ..&lt;/p&gt;

    


    &lt;hr class=&quot;my-10&quot;&gt;
    


    
    

</description><link>https://mrinalxdev.github.io/mrinalxblogs/blogs/concurrency.html</link><guid isPermaLink="false">https://mrinalxdev.github.io/mrinalxblogs/blogs/concurrency.html</guid><pubDate>Invalid Date</pubDate><author>Mrinal</author></item><item><title>System Design from a Beginners POV</title><description>&lt;hr class=&quot;mt-3&quot;&gt;

    
    &lt;h1 class=&quot;text-4xl mt-[57px] mb-3 font-serif&quot;&gt;System Design 101 : From a Beginners POV&lt;/h1&gt;
    &lt;span class=&quot;text-sm text-gray-500&quot;&gt;28th April, 2025&lt;/span&gt;
    &lt;p class=&quot;font-serif mt-5 text-lg&quot;&gt;I really like to talk about system with people who are either really great at designing it or with peeps who are just getting started with this topic. For me System is very much vast topic to learn and be mastery off, as in tech there will always be something new to explore and learn.  &lt;/p&gt;
    &lt;p class=&quot;font-serif mt-5 text-lg&quot;&gt;System Design is not about writing the code, its about figuring out how everything fits together. Its the process defining the architecture, components, modules, interfaces and data flow of a system to meet specefic requirements&lt;/p&gt;

    &lt;div class=&quot;my-5&quot;&gt;
      &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/system-design/banner.png&quot; class=&quot;rounded-xl&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
      &lt;p class=&quot;text-md text-gray-500 font-serif&quot;&gt;Small Components of Chat Application&lt;/p&gt;
    &lt;/div&gt;

    &lt;section class=&quot;mt-4 font-serif&quot;&gt;
      &lt;h1 class=&quot;mt-8 font-serif text-3xl&quot;&gt;Introduction&lt;/h1&gt;
      &lt;p class=&quot;mt-4 font-serif text-lg&quot;&gt;I am building a platform which is LeetSys, a small app running on a single server. When a user &lt;span class=&quot;font-bold&quot;&gt;[client]&lt;/span&gt; wants to see questions, thier browser sends a request to our server. The server process this request, which then fetches posts from a database. The database sends back a response with the question data.&lt;/p&gt;

      &lt;img class=&quot;rounded-xl mx-auto my-6&quot; src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/system-design/csr.png&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

      &lt;p class=&quot;mt-2 font-serif text-lg&quot;&gt;This client-server model is the foundation of web interactions. Requests and responses are typically sent over &lt;span class=&quot;font-bold&quot;&gt;HTTP&lt;/span&gt;(HyperText Transfer Protocol), a stateless protocol that governs how clients and server should communicate.

      But soon LeetSys started to gain attraction among the users and gained a lot of virality, more and more users joined. So we need to scale our small app to millions of requests which can&#39;t be handled by our single CS[Client =&amp;gt; Server] model&lt;/p&gt;

      &lt;h1 class=&quot;mt-8 font-serif text-3xl&quot;&gt;Scaling our platform&lt;/h1&gt;

      &lt;p class=&quot;mt-2 font-serif text-lg&quot;&gt;Our server is overwhelmed, and load times are sky rocketting. So what to do now ? We can do two things either opt for&lt;/p&gt;

      &lt;p class=&quot;mt-2 font-serif text-lg&quot;&gt; &lt;span class=&quot;mt-2 font-serif text-xl underline underline-offset-4&quot;&gt;Vertical Scaling&lt;/span&gt; : Which means we have to upgrade our server with more CPU, RAM and storage, this will boost performance temporarily, but there&#39;s a ceiling to how powerful a single server can get, and will cost us wayyyy to much !!&lt;/p&gt;

      &lt;p class=&quot;mt-2 font-serif text-lg&quot;&gt;Or we can opt for&lt;/p&gt;
      
      &lt;p class=&quot;mt-2 font-serif text-lg&quot;&gt; &lt;span class=&quot;mt-2 font-serif text-xl  underline underline-offset-4&quot;&gt;Horizontal Scaling&lt;/span&gt; : Instead of one bigg server, we deploy multiple smaller servers, each handling a subset of requests. This is more cost-effecient and effective, but introduces way more complexity to our systems.&lt;/p&gt;

      &lt;p class=&quot;text-lg&quot;&gt;How do we distribute incoming requests across these servers ? LoadBalancer ?? HELL YEAHHH !!!&lt;/p&gt;

      &lt;h1 class=&quot;mt-8 font-serif text-3xl&quot;&gt;Load Balancers&lt;/h1&gt;

      &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/system-design/load.png&quot; class=&quot;mx-auto&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

      &lt;p class=&quot;mt-2 font-serif text-lg&quot;&gt;So you choose horizontal scaling and there are many servers to which 100&#39;s of requests can be passed on . But what if a server ends up recieving more requests than others ? &lt;/p&gt;

      &lt;p class=&quot;mt-2 text-lg&quot;&gt;To manage the request we use load balancers to distribute requests among the servers so that no signle server can get huge number of requests. If any of the server is down load balancer will only redirect traffic to healthy servers&lt;/p&gt;

      &lt;p class=&quot;mt-2 text-lg&quot;&gt;
        &lt;span class=&quot;mt-2 font-serif text-xl  underline underline-offset-4&quot;&gt;Load Balancer Algorithms &lt;/span&gt; : there are several algorithms to distribute the traffic to the healthy servers.

        &lt;/p&gt;&lt;ul class=&quot;list-disc ml-5 mt-6&quot;&gt;
            &lt;li class=&quot;text-lg&quot;&gt;
              &lt;span class=&quot;mt-2 font-serif text-xl  underline underline-offset-4&quot;&gt;Least Connection&lt;/span&gt; : Sends request to server with the fewest active connections. By continuously monitoring the number of active connections on each server, this algorithm adapts in real-time to
              shifting traffic patterns and workloads, making it particularly effective when handling sessions or tasks that require
              varying processing times.
            &lt;/li&gt;
            &lt;li class=&quot;text-lg mt-3&quot;&gt;
              &lt;span class=&quot;mt-2 font-serif text-xl  underline underline-offset-4&quot;&gt;Round Robin&lt;/span&gt; :
              This algorithm cycles through a list server sequentially, each server is assigned a request in turn, ensuring an equal distribution of traffic over time. While this algorithm
              does not take into account the current load or capacity of individual servers, it works well in scenarios where all
              servers have similar processing capabilities and are equally equipped to handle requests.
            &lt;/li&gt;
        &lt;/ul&gt;
      &lt;p&gt;&lt;/p&gt;

      &lt;p class=&quot;mt-2 text-lg&quot;&gt;There are many more interesting topics related to Load Balancing for example, &lt;span class=&quot;font-bold&quot;&gt;What is IP Hashing technique ?&lt;/span&gt;, &lt;span class=&quot;font-bold&quot;&gt;What is StandBy Load Balancers ?&lt;/span&gt; all these will be covered in the blog &lt;span class=&quot;underline underline-offset-4&quot;&gt;Do you know Load Balancers well ??&lt;/span&gt;&lt;/p&gt;

      &lt;p class=&quot;mt-4 text-lg mt-4&quot;&gt;Everything is going fine we have a large user base, a load balancer which can redirect traffic . But we get to notice there are request for the same data from our database. Can we optimize it ?? Can we do something to make client not wait much for response from our db ?? HELL YEAHHH !!&lt;/p&gt;


      &lt;h1 class=&quot;mt-8 font-serif text-3xl&quot;&gt;Caching&lt;/h1&gt;
      &lt;p class=&quot;text-lg mt-2&quot;&gt;For a general context caching is like keeping frequently used items on your desk instead of fetching them from a storage room. Caching stores frequently accessed data in a temporary, high-speed storage layer, reducing latency and improving performance by minimizing redundant computations
      or database queries. It enhances scalability and user experience, it reduces database load and speeds up responses.&lt;/p&gt;

      &lt;p class=&quot;text-lg&quot;&gt;But with caching comes a problem of maintaining the data consistency of cache and the database, we should not source the data from cache if its not up-to-date with the database. What to do now ?? How are we going to update both the source of data and the cache ??&lt;/p&gt;

      &lt;ul class=&quot;list-disc ml-4 mt-6&quot;&gt;
        &lt;li class=&quot;text-lg&quot;&gt;&lt;span class=&quot;mt-2 font-serif text-xl  underline underline-offset-4&quot;&gt;Time Based Expiration&lt;/span&gt; : Cache entries are invalidated after a set time period (Time-to-Live), ensuring data is refreshed periodically&lt;/li&gt;


        &lt;li class=&quot;text-lg mt-3&quot;&gt;&lt;span class=&quot;mt-2 font-serif text-xl  underline underline-offset-4&quot;&gt;Write Through&lt;/span&gt; : Data is written to the cache and backend simultaneously, ensuring consistency but with higher write latency.&lt;/li&gt;

        &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/system-design/cache-writethrough.png&quot; alt=&quot;&quot; class=&quot;mx-auto my-4&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
      &lt;/ul&gt;

      &lt;p class=&quot;text-lg mt-3&quot;&gt;We also have many interesting topics to cover for more about Caching invalidation strategies and Cache Eviction Policies which we will cover in upcoming blogs !!&lt;/p&gt;

      &lt;p class=&quot;text-lg mt-4&quot;&gt;Now, LeetSys&#39;s users are spreading across the globe, and those in distant regions experience latency because our server are in the data center, we need to bring content closer to users.&lt;/p&gt;


      &lt;h1 class=&quot;mt-8 font-serif text-3xl&quot;&gt;Content Delivery Networks (CDNs)&lt;/h1&gt;

      &lt;div class=&quot;my-6&quot;&gt;
        &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/system-design/low-latency.png&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
        &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/system-design/high-latency.png&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
      &lt;/div&gt;

      &lt;p class=&quot;text-lg&quot;&gt;To reduce latency, we integrate a Content Delivery Network (CDN). CDNs are networks of geographically distributed
      servers (edge servers) that cache static content like images, videos, and CSS files closer to users. When a user in
      Tokyo accesses LeetSys, the CDN’s Tokyo edge server delivers cached content, reducing the round-trip time to our main servers in the India CDNs rely heavily on &lt;span class=&quot;font-bold&quot;&gt;caching&lt;/span&gt;
      &lt;/p&gt;

      &lt;p class=&quot;mt-3 text-lg&quot;&gt;For now this is what our system has been evolved too, from a single client server request&lt;/p&gt;

      &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/system-design/afterUpdate.png&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

      &lt;p class=&quot;text-lg mt-3&quot;&gt;Time to focus on our Database, becuase there are many things to store now !! There are often questions asked when to choose SQL databases and when to choose NoSQL database ?? But first lets get through each of them to know in-depth&lt;/p&gt;

      &lt;h1 class=&quot;mt-8 font-serif text-3xl&quot;&gt;Structured Query Language (SQL)&lt;/h1&gt;
      &lt;p class=&quot;text-lg mt-3&quot;&gt;SQL databases like PostgreSQL, Oracle, MySQL, which organizes data into tables with defined schemas, these database excel at structured data and complex queries. SQL databases scale vertically which means we need to upgrade our machine power to scale databases like this. If you had to change or add a new column the changes need to be applied to all the records in the table.&lt;/p&gt;

      &lt;p&gt;SQL has Rigid schema which will struggle with massive, unstructured data like user activity logs. For this lets explore NoSQL databases&lt;/p&gt;


      &lt;h1 class=&quot;mt-8 font-serif text-3xl&quot;&gt;NoSQL&lt;/h1&gt;
      &lt;p class=&quot;text-lg mt-3&quot;&gt;NoSQL databases like MongoDB are schema-less, allowing flexible storage for documents, JSON-like for our user activity logs. They scale horizontally better than SQL but sacrifice some ACID rules for better availabiity and performance.&lt;/p&gt;
      &lt;p class=&quot;text-lg mt-3&quot;&gt;There are majorly 4 types of NoSQL databases&lt;/p&gt;
      &lt;ul class=&quot;list-disc ml-4 mt-5&quot;&gt;
        &lt;li class=&quot;text-lg&quot;&gt;&lt;span class=&quot;underline underline-offset-4&quot;&gt;Key Value Stores&lt;/span&gt; : These databases store data as key-value pairs, making them highly efficient for simple lookups and caching ex : Redis, DynamoDB&lt;/li&gt;
        &lt;li class=&quot;text-lg mt-3&quot;&gt;&lt;span class=&quot;underline underline-offset-4&quot;&gt;Document Stores&lt;/span&gt; : These database store data as documents (often in JSON or BSON format), allowing for flexible schemas and nested structures. Ex : MongoDB, Firebase Firestore&lt;/li&gt;
        &lt;li class=&quot;text-lg mt-3&quot;&gt;&lt;span class=&quot;underline underline-offset-4&quot;&gt;Column Family Stores&lt;/span&gt; : These database organize data into columns rather than rows, optimized for large scale data and high write/read performance. ex : Apache Cassandra&lt;/li&gt;
      &lt;/ul&gt;

      &lt;h1 class=&quot;mt-4 font-serif text-3xl&quot;&gt;What to choose and when to choose ??&lt;/h1&gt;
      &lt;p class=&quot;text-lg mt-4&quot;&gt;If you want strong consistency, reliability with highly structured data and consistent schema go for &lt;span class=&quot;font-bold&quot;&gt;SQL&lt;/span&gt; like PostgreSQL, Oracle Database&lt;/p&gt;

      &lt;p class=&quot;text-lg my-4&quot;&gt;but&lt;/p&gt;

      &lt;p class=&quot;text-lg mt-4&quot;&gt;If your data semi-structured, unstructured or has a dynamic schema also you want high performance with simple queries which also horizontally scales to handle massive amounts of data and high traffic you can go for &lt;span class=&quot;font-bold&quot;&gt;NoSQL&lt;/span&gt; like Cassandra or Neo4j&lt;/p&gt;

      &lt;p class=&quot;text-lg mt-4&quot;&gt;As our user base grows we can notice a slow query performance from our backend, What to do in this situation ??&lt;/p&gt;

      &lt;h1 class=&quot;mt-4 font-serif text-3xl&quot;&gt;Database Indexing&lt;/h1&gt;
      &lt;p class=&quot;text-lg mt-3&quot;&gt;Whenever there is a query our algorithm is consistently looking up from the whole database content which is making our response slow, for this we introduce &lt;span class=&quot;font-bold&quot;&gt;Database Indexing&lt;/span&gt; all the primary key, or username can be indexed at a place which will help speeding up our database lookups pointing the actual location of the data.&lt;/p&gt;



      &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/system-design/dbIndexing.png&quot; alt=&quot;&quot; class=&quot;my-5&quot; referrerpolicy=&quot;no-referrer&quot;&gt;


      &lt;p class=&quot;mt-4 text-lg&quot;&gt;There&#39;s a point to which we can scale our database but after that threshold point, how we will be scaling our database to meet the requirements for our growing user base ??&lt;/p&gt;

      &lt;h1 class=&quot;mt-3 font-serif text-3xl&quot;&gt;Data Partioning&lt;/h1&gt;
      &lt;p class=&quot;text-lg mt-3&quot;&gt;When the database can no longer scale vertically then we perform data partitioning which is a technique to breakdown large databases into smaller components which enhances the performance, availabiity and load balancing as our application grows&lt;/p&gt;

      &lt;p class=&quot;text-lg my-2&quot;&gt;There are mainly 4 major ways of breaking down a large database&lt;/p&gt;
      &lt;ul class=&quot;ml-4 mt-3 list-disc&quot;&gt;
        &lt;li class=&quot;text-lg&quot;&gt;&lt;span class=&quot;underline underline-offset-4&quot;&gt;Horizontal Partitioning&lt;/span&gt; : Also known as Sharding in this the data is divided by rows, meaning each partition contains a subset of rows from the dataset. Its ideal for large datasets where different subsets of rows can be stored on separate nodes&lt;/li&gt;
        &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/system-design/partitioning.png&quot; alt=&quot;&quot; class=&quot;my-4&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

        &lt;li class=&quot;text-lg&quot;&gt;
          &lt;span class=&quot;underline underline-offset-4&quot;&gt;Vertical Partitioning&lt;/span&gt; :
          Data is is divided by columns, meaning each partition contains a subset of columns from the dataset, its useful when certain columns are accessed more frequently than others, allowing us to separate &quot;Hot&quot; (frequently accessed) and &quot;Cold&quot; (less frequently accessed) data. Vertical partitioning also simplifies schema design by grouping related attributes.
        &lt;/li&gt;
      &lt;/ul&gt;

      &lt;p class=&quot;text-lg mt-3&quot;&gt;So these are the to begin our journey with system design, more often you practise questions you get to know more and more topics differenc between HLD [High Level Design] and LLD [Low Level Design]also you will get to know topics like micro services, distributed systems and more. I may write blogs on topics like this but I am leaving it to the future decesions.&lt;/p&gt;

      &lt;p class=&quot;text-lg mt-3&quot;&gt;This is what are system has evolved into with large user base, load balancers, cache to our web servers and database with partitioning&lt;/p&gt;

      &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/system-design/afterUpdate2.png&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

      &lt;p class=&quot;text-lg mt-3&quot;&gt;Hope I was able to add value to your today&#39;s learning goal !! Happy Learning ..&lt;/p&gt;

    &lt;/section&gt;


    &lt;hr class=&quot;my-10&quot;&gt;
    


    
    

</description><link>https://mrinalxdev.github.io/mrinalxblogs/blogs/system-design.html</link><guid isPermaLink="false">https://mrinalxdev.github.io/mrinalxblogs/blogs/system-design.html</guid><pubDate>Invalid Date</pubDate><author>Mrinal</author></item><item><title>Flash Attention from a Beginners POV</title><description>&lt;hr class=&quot;mt-3&quot;&gt;

      &lt;div class=&quot;my-5 border rounded-xl p-4&quot;&gt;
        &lt;h1 class=&quot;text-xl font-serif mb-6&quot;&gt;Pre-Requisites to know &lt;span class=&quot;text-sm text-gray-500&quot;&gt;[Click on the topic header of these below to make it collapse or expand]&lt;/span&gt;&lt;/h1&gt;
  
        &lt;div class=&quot;ml-4&quot;&gt;
          &lt;ul class=&quot;list-disc ml-4&quot;&gt;
            &lt;li class=&quot;cursor-pointer font-serif &quot; onclick=&quot;toggleCollapse(&#39;item1&#39;)&quot;&gt;
              Attention : &lt;a href=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/attention.html&quot;&gt;[Link]&lt;/a&gt;
              &lt;ul id=&quot;item1&quot; class=&quot; pl-4 mt-1 space-y-1 transition-all duration-300 hidden ease-in-out&quot;&gt;
                &lt;li&gt;Complete the attention blog to get an idea why even Multi-Head is needed. Its like a homework you can do to understand better about the topic of this blog. &lt;/li&gt;
              &lt;/ul&gt;
             &lt;/li&gt;
            
             &lt;li class=&quot;cursor-pointer font-serif &quot; onclick=&quot;toggleCollapse(&#39;item2&#39;)&quot;&gt;
                Articles you should go through once : &lt;a href=&quot;https://www.hopsworks.ai/dictionary/flash-attention&quot;&gt;[Link]&lt;/a&gt;
                &lt;ul id=&quot;item2&quot; class=&quot; pl-4 mt-1 space-y-1  transition-all hidden duration-300 ease-in-out&quot;&gt;
                  &lt;li&gt;Go through these articles after or before reading this blog, its up to you anon !! &lt;/li&gt;
                &lt;/ul&gt;
               &lt;/li&gt;
               &lt;li class=&quot;cursor-pointer font-serif &quot; onclick=&quot;toggleCollapse(&#39;item3&#39;)&quot;&gt;
                Tile Matrix Multiplication : &lt;a href=&quot;https://alvinwan.com/how-to-tile-matrix-multiplication/&quot;&gt;[Link]&lt;/a&gt;
                &lt;ul id=&quot;item3&quot; class=&quot; pl-4 mt-1 space-y-1 hidden transition-all duration-300 ease-in-out&quot;&gt;
                  &lt;li&gt;Study Anon !!&lt;/li&gt;
                &lt;/ul&gt;
               &lt;/li&gt;
          &lt;/ul&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class=&quot;mt-3&quot;&gt;
        &lt;h1 class=&quot;text-4xl mt-[57px] mb-3 font-serif&quot;&gt;
          Flash Attention from a Beginner&#39;s Point of View
        &lt;/h1&gt;
        &lt;span class=&quot;text-sm text-gray-500&quot;&gt;23rd March, 2025&lt;/span&gt;
        &lt;p class=&quot;mt-4 font-serif text-lg&quot;&gt;
          Transformers are amazing, right? Their attention mechanisms like self-attention and multi-head attention make them super powerful for understanding context in text, translations, and more. But there’s a catch: traditional attention can be a memory hog and slowpoke, especially when dealing with long sequences. Enter &lt;span class=&quot;font-bold font-serif&quot;&gt;Flash Attention&lt;/span&gt;, a clever optimization that makes attention faster and more efficient without sacrificing accuracy. Let’s dive in!
        &lt;/p&gt;

        &lt;p class=&quot;my-4 text-lg font-serif&quot;&gt;This is just merely part I of what Flash attention is in upcoming parts of Flash attention we will be diving deeper into flash attention internals and implementation in pytorch&lt;/p&gt;
      
        &lt;h1 class=&quot;mt-8 font-serif text-3xl&quot;&gt;What is Flash Attention and Why is it Needed?&lt;/h1&gt;
        &lt;p class=&quot;mt-4 font-serif text-lg&quot;&gt;
          Attention, as we know, computes a weighted sum of values (V) based on how relevant each key (K) is to a query (Q). The problem? For a sequence of length N, the attention mechanism needs to create an N × N attention score matrix. That’s a lot of memory! For example, if N = 10,000 (think a long document), you’re storing 100 million numbers just for that matrix. GPUs, which power these models, choke on this because they have limited memory, and moving data back and forth slows everything down.
        &lt;/p&gt;
        &lt;p class=&quot;mt-4 font-serif text-lg&quot;&gt;
          Flash Attention is a way to compute attention without ever fully building that giant N × N matrix in memory. Instead, it processes the data in smaller chunks (or &quot;tiles&quot;) and does the math on-the-fly. It’s like solving a puzzle piece by piece instead of laying out the whole picture at once. This saves memory, speeds things up, and lets Transformers handle much longer sequences—like entire books—without crashing.
        &lt;/p&gt;
      
        &lt;h1 class=&quot;text-2xl underline underline-offset-4 font-serif mt-6&quot;&gt;Why is it Needed?&lt;/h1&gt;
        &lt;ul class=&quot;list-disc mt-4 ml-5&quot;&gt;
          &lt;li class=&quot;my-4&quot;&gt;
            &lt;p class=&quot;mt-4 text-lg font-serif&quot;&gt;&lt;span class=&quot;font-bold&quot;&gt;Memory Efficiency:&lt;/span&gt; Traditional attention’s memory usage grows quadratically (N²), while Flash Attention scales linearly (N).&lt;/p&gt;
          &lt;/li&gt;
          &lt;li class=&quot;my-4&quot;&gt;
            &lt;p class=&quot;mt-4 text-lg font-serif&quot;&gt;&lt;span class=&quot;font-bold&quot;&gt;Speed:&lt;/span&gt; It reduces redundant data movement between GPU memory layers.&lt;/p&gt;
          &lt;/li&gt;
          &lt;li class=&quot;my-4&quot;&gt;
            &lt;p class=&quot;mt-4 text-lg font-serif&quot;&gt;&lt;span class=&quot;font-bold&quot;&gt;Scalability:&lt;/span&gt; It unlocks Transformers for super-long sequences (e.g., 64k tokens instead of 512).&lt;/p&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      
        &lt;h1 class=&quot;mt-8 font-serif text-3xl&quot;&gt;How Does Flash Attention Work?&lt;/h1&gt;

        &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/flash-atten/flash-banner.png&quot; class=&quot;rounded-xl my-5&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
        &lt;p class=&quot;mt-4 font-serif text-lg&quot;&gt;
          Let’s break it down :
        &lt;/p&gt;
        &lt;ul class=&quot;list-disc mt-4 ml-5&quot;&gt;
          &lt;li class=&quot;my-4&quot;&gt;
            &lt;p class=&quot;mt-4 text-lg font-serif&quot;&gt;Compute the dot product of Q and K to get the attention scores (N × N matrix).&lt;/p&gt;
          &lt;/li&gt;
          &lt;li class=&quot;my-4&quot;&gt;
            &lt;p class=&quot;mt-4 text-lg font-serif&quot;&gt;Scale and apply softmax to turn scores into weights.&lt;/p&gt;
          &lt;/li&gt;
          &lt;li class=&quot;my-4&quot;&gt;
            &lt;p class=&quot;mt-4 text-lg font-serif&quot;&gt;Multiply those weights by V to get the output.&lt;/p&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
        &lt;p class=&quot;mt-4 font-serif text-lg&quot;&gt;
          Flash Attention says, “Why store that huge score matrix?” Instead, it:
        &lt;/p&gt;
        &lt;ul class=&quot;list-disc mt-4 ml-5&quot;&gt;
          &lt;li class=&quot;my-4&quot;&gt;
            &lt;p class=&quot;mt-4 text-lg font-serif&quot;&gt;Splits Q, K, and V into smaller blocks (like cutting a big cake into slices).&lt;/p&gt;
          &lt;/li&gt;
          &lt;li class=&quot;my-4&quot;&gt;
            &lt;p class=&quot;mt-4 text-lg font-serif&quot;&gt;Computes attention for one block at a time, using a technique called tiling.&lt;/p&gt;
          &lt;/li&gt;
          &lt;li class=&quot;my-4&quot;&gt;
            &lt;p class=&quot;mt-4 text-lg font-serif&quot;&gt;Updates the output incrementally, keeping only what’s needed in memory.&lt;/p&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
        &lt;p class=&quot;mt-4 font-serif text-lg&quot;&gt;
          Here’s the trick: it avoids storing the full attention score matrix by recomputing intermediate results when necessary and using clever math to keep the softmax accurate across blocks. This happens entirely on the GPU’s fast memory (SRAM), skipping the slower main memory (HBM).
        &lt;/p&gt;
      
        &lt;h1 class=&quot;text-2xl underline underline-offset-4 font-serif mt-6&quot;&gt;Step-by-Step:&lt;/h1&gt;
        &lt;ol class=&quot;list-decimal mt-4 ml-5&quot;&gt;
          &lt;li class=&quot;my-4&quot;&gt;
            &lt;p class=&quot;mt-4 text-lg font-serif&quot;&gt;&lt;span class=&quot;font-bold&quot;&gt;Input:&lt;/span&gt; Q, K, and V matrices (say, each is N × d, where d is the embedding size).&lt;/p&gt;
          &lt;/li&gt;
          &lt;li class=&quot;my-4&quot;&gt;
            &lt;p class=&quot;mt-4 text-lg font-serif&quot;&gt;&lt;span class=&quot;font-bold&quot;&gt;Tiling:&lt;/span&gt; Break them into smaller chunks (e.g., blocks of size B × d, where B &amp;lt;&amp;lt; N).&lt;/p&gt;
          &lt;/li&gt;
          &lt;li class=&quot;my-4&quot;&gt;
            &lt;p class=&quot;mt-4 text-lg font-serif&quot;&gt;&lt;span class=&quot;font-bold&quot;&gt;Inner Loop:&lt;/span&gt; For each block of Q, compute attention with all blocks of K and V, but only store tiny temporary results.&lt;/p&gt;
          &lt;/li&gt;
          &lt;li class=&quot;my-4&quot;&gt;
            &lt;p class=&quot;mt-4 text-lg font-serif&quot;&gt;&lt;span class=&quot;font-bold&quot;&gt;Softmax Trick:&lt;/span&gt; Use a running normalization to combine results across blocks without ever needing the full matrix.&lt;/p&gt;
          &lt;/li&gt;
          &lt;li class=&quot;my-4&quot;&gt;
            &lt;p class=&quot;mt-4 text-lg font-serif&quot;&gt;&lt;span class=&quot;font-bold&quot;&gt;Output:&lt;/span&gt; Build the final attention output block-by-block.&lt;/p&gt;
          &lt;/li&gt;
        &lt;/ol&gt;
        &lt;p class=&quot;mt-4 font-serif text-lg&quot;&gt;
          The result? Same output as regular attention, but way less memory and faster computation.
        &lt;/p&gt;
      
        &lt;h1 class=&quot;mt-8 font-serif text-3xl&quot;&gt;Mathematical Representation&lt;/h1&gt;
        &lt;p class=&quot;mt-4 font-serif text-lg&quot;&gt;
          Let’s keep it simple but precise. Regular attention computes:
        &lt;/p&gt;
        &lt;p class=&quot;mt-4 font-serif text-lg text-center&quot;&gt;
          &lt;span class=&quot;italic&quot;&gt;Attention(Q, K, V) = softmax(&lt;/span&gt;&lt;span class=&quot;frac&quot;&gt;&lt;sup&gt;QK&lt;sup&gt;T&lt;/sup&gt;&lt;/sup&gt;&lt;sub&gt;√d&lt;sub&gt;k&lt;/sub&gt;&lt;/sub&gt;&lt;/span&gt;&lt;span class=&quot;italic&quot;&gt;)V&lt;/span&gt;
        &lt;/p&gt;
        &lt;p class=&quot;mt-4 font-serif text-lg&quot;&gt;
          Where:
        &lt;/p&gt;
        &lt;ul class=&quot;list-disc mt-4 ml-5&quot;&gt;
          &lt;li class=&quot;my-4&quot;&gt;
            &lt;p class=&quot;mt-4 text-lg font-serif&quot;&gt;\( Q, K, V \in \mathbb{R}^{N \times d} \) (N = sequence length, d = dimension).&lt;/p&gt;
          &lt;/li&gt;
          &lt;li class=&quot;my-4&quot;&gt;
            &lt;p class=&quot;mt-4 text-lg font-serif&quot;&gt;\( QK^T \in \mathbb{R}^{N \times N} \) (the big, problematic score matrix).&lt;/p&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
        &lt;p class=&quot;mt-4 font-serif text-lg&quot;&gt;
          Flash Attention avoids materializing \( QK^T \) fully. Instead:
        &lt;/p&gt;
        &lt;ul class=&quot;list-disc mt-4 ml-5&quot;&gt;
          &lt;li class=&quot;my-4&quot;&gt;
            &lt;p class=&quot;mt-4 text-lg font-serif&quot;&gt;Split \( Q \) into blocks \( Q_1, Q_2, ..., Q_m \) (each \( B \times d \)).&lt;/p&gt;
          &lt;/li&gt;
          &lt;li class=&quot;my-4&quot;&gt;
            &lt;p class=&quot;mt-4 text-lg font-serif&quot;&gt;Split \( K \) and \( V \) similarly into \( K_1, K_2, ..., K_m \) and \( V_1, V_2, ..., V_m \).&lt;/p&gt;
          &lt;/li&gt;
          &lt;li class=&quot;my-4&quot;&gt;
            &lt;p class=&quot;mt-4 text-lg font-serif&quot;&gt;For each block \( Q_i \):&lt;/p&gt;
            &lt;ul class=&quot;list-disc ml-8&quot;&gt;
              &lt;li class=&quot;my-4 text-lg font-serif&quot;&gt;Compute \( S_i = Q_i K^T \) (small \( B \times N \) matrix).&lt;/li&gt;
              &lt;li class=&quot;my-4 text-lg font-serif&quot;&gt;Scale: \( S_i / \sqrt{d_k} \).&lt;/li&gt;
              &lt;li class=&quot;my-4 text-lg font-serif&quot;&gt;Apply softmax incrementally, tracking running sums and normalization constants.&lt;/li&gt;
              &lt;li class=&quot;my-4 text-lg font-serif&quot;&gt;Compute \( O_i = \text{softmax}(S_i)V \) and add to the output.&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
        &lt;p class=&quot;mt-4 font-serif text-lg&quot;&gt;
          The magic is in the incremental softmax, which uses two extra variables (a max and a sum) to stitch everything together accurately without the full matrix.
        &lt;/p&gt;
      
        &lt;p class=&quot;mt-4 font-serif text-lg&quot;&gt;
          With Flash Attention, the operator is smarter. They only look at one section of the stage at a time (a block), figure out who’s important in that moment, and adjust the spotlight right away. They keep a tiny notepad (fast GPU memory) with just enough info to move to the next section. The play (computation) goes on smoothly, and the audience (model) still sees the full story—no one notices the operator’s trick!
        &lt;/p&gt;
      
        &lt;h1 class=&quot;mt-8 font-serif text-3xl&quot;&gt;Flash Attention in the Transformer Architecture&lt;/h1&gt;
        &lt;p class=&quot;mt-4 font-serif text-lg&quot;&gt;
          Flash Attention fits right into the Transformer’s attention layers:
        &lt;/p&gt;
        &lt;ul class=&quot;list-disc mt-4 ml-5&quot;&gt;
          &lt;li class=&quot;my-4&quot;&gt;
            &lt;p class=&quot;mt-4 text-lg font-serif&quot;&gt;&lt;span class=&quot;font-bold&quot;&gt;Encoder:&lt;/span&gt; Replaces self-attention with Flash Attention to process input sequences efficiently.&lt;/p&gt;
          &lt;/li&gt;
          &lt;li class=&quot;my-4&quot;&gt;
            &lt;p class=&quot;mt-4 text-lg font-serif&quot;&gt;&lt;span class=&quot;font-bold&quot;&gt;Decoder:&lt;/span&gt; Handles masked self-attention (for previous tokens only) and cross-attention (connecting to the encoder) with the same block-wise trick.&lt;/p&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
        &lt;p class=&quot;mt-4 font-serif text-lg&quot;&gt;
          It’s plug-and-play: same Transformer, just faster and leaner.
        &lt;/p&gt;
      
        &lt;h1 class=&quot;mt-8 font-serif text-3xl&quot;&gt;Why Is Flash Attention a Big Deal?&lt;/h1&gt;
        &lt;ul class=&quot;list-disc mt-4 ml-5&quot;&gt;
          &lt;li class=&quot;my-4&quot;&gt;
            &lt;p class=&quot;mt-4 text-lg font-serif&quot;&gt;&lt;span class=&quot;font-bold&quot;&gt;Longer Sequences:&lt;/span&gt; Models can now process tens of thousands of tokens (e.g., 64k) instead of hitting a wall at 512 or 1024.&lt;/p&gt;
          &lt;/li&gt;
          &lt;li class=&quot;my-4&quot;&gt;
            &lt;p class=&quot;mt-4 text-lg font-serif&quot;&gt;&lt;span class=&quot;font-bold&quot;&gt;Energy Savings:&lt;/span&gt; Less memory movement = less power, which matters for big AI training runs.&lt;/p&gt;
          &lt;/li&gt;
        &lt;/ul&gt;

        &lt;h1 class=&quot;mt-8 font-serif text-3xl&quot;&gt;Intuition: Flash Attention as a Spotlight&lt;/h1&gt;
        &lt;p class=&quot;mt-4 font-serif text-lg&quot;&gt;
          Remember our theater analogy? In regular attention, the spotlight operator (Attention) scans the entire stage (all tokens) at once, writing down a huge list of who’s important (the N × N matrix) before deciding where to shine the light. With a big stage, that list gets unwieldy, and the operator runs out of paper (memory).
            &lt;br&gt;
          With Flash Attention, the operator is smarter. They only look at one section of the stage at a time (a block), figure out who’s important in that moment, and adjust the spotlight right away. They keep a tiny notepad (fast GPU memory) with just enough info to move to the next section. The play (computation) goes on smoothly, and the audience (model) still sees the full story—no one notices the operator’s trick!
        &lt;/p&gt;
      &lt;/div&gt;


      &lt;hr class=&quot;my-10&quot;&gt;
    

    
    

</description><link>https://mrinalxdev.github.io/mrinalxblogs/blogs/flash-atten.html</link><guid isPermaLink="false">https://mrinalxdev.github.io/mrinalxblogs/blogs/flash-atten.html</guid><pubDate>Invalid Date</pubDate><author>Mrinal</author></item><item><title>Multi-Head Attention from a Beginners POV</title><description>&lt;hr class=&quot;mt-3&quot;&gt;

    &lt;div class=&quot;my-5 border rounded-xl p-4&quot;&gt;
      &lt;h1 class=&quot;text-xl font-serif mb-6&quot;&gt;Pre-Requisites to know&lt;/h1&gt;

      &lt;div class=&quot;ml-4&quot;&gt;
        &lt;ul class=&quot;list-disc ml-4&quot;&gt;
          &lt;li class=&quot;cursor-pointer font-serif &quot; onclick=&quot;toggleCollapse(&#39;item1&#39;)&quot;&gt;
            Attention : &lt;a href=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/attention.html&quot;&gt;[Link]&lt;/a&gt;
            &lt;ul id=&quot;item1&quot; class=&quot; pl-4 mt-1 space-y-1 hidden transition-all duration-300 ease-in-out&quot;&gt;
              &lt;li&gt;Complete the attention blog to get an idea why even Multi-Head is needed. Its like a homework you can do to understand better about the topic of this blog. &lt;/li&gt;
            &lt;/ul&gt;
           &lt;/li&gt;
          &lt;li class=&quot;cursor-pointer font-serif &quot; onclick=&quot;toggleCollapse(&#39;item2&#39;)&quot;&gt;
           Dot Product Attention
            &lt;ul id=&quot;item2&quot; class=&quot; pl-4 mt-1 space-y-1 hidden transition-all duration-300 ease-in-out&quot;&gt;
              &lt;li&gt;&amp;gt; Dot Product attention is a specific type of attention mechanism that computes attention scores using the dot product between vectors.&lt;/li&gt;
              &lt;li&gt;&amp;gt; Computing the dot product between each query vector \(\text{Q}\) and each key vector \(\text{K}\). This gives a raw measure of similarity between the query and the keys. \[\text{Raw Scores} = \text{Q} \cdot K^T\]&lt;/li&gt;

              &lt;span class=&quot;text-xs text-gray-500 font-serif&quot;&gt;The result is a matrix where each entry represents the similarity between a query and a key&lt;/span&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
          &lt;li class=&quot;cursor-pointer font-serif &quot; onclick=&quot;toggleCollapse(&#39;item5&#39;)&quot;&gt;
            Emeddings
             &lt;ul id=&quot;item5&quot; class=&quot; pl-4 mt-1 space-y-1 hidden transition-all duration-300 ease-in-out&quot;&gt;
               &lt;li&gt;&amp;gt; Embeddings are a way to transform raw input data—like words, tokens, or symbols—into dense, continuous vectors of numbers that a machine learning model can understand and process. Here embeddings are crucial because they provide the starting point for computing Queries (Q), Keys (K), and Values (V), which drive how the model focuses on different parts of the input.
               &lt;/li&gt;
             &lt;/ul&gt;
           &lt;/li&gt;
           &lt;li class=&quot;cursor-pointer font-serif &quot; onclick=&quot;toggleCollapse(&#39;item3&#39;)&quot;&gt;
            Dimensionality
             &lt;ul id=&quot;item3&quot; class=&quot; pl-4 mt-1 space-y-1 hidden transition-all duration-300 ease-in-out&quot;&gt;
               &lt;li&gt;&amp;gt; It refers to the number of features, attributes, or components used to represent data in a mathematical space. In simpler terms, it describes how many &quot;dimensions&quot; or variables are present in a dataset or a vector for a machine to learn.&lt;/li&gt;
             &lt;/ul&gt;
           &lt;/li&gt;

           &lt;li class=&quot;cursor-pointer font-serif &quot; onclick=&quot;toggleCollapse(&#39;item4&#39;)&quot;&gt;
            Softmax Function
             &lt;ul id=&quot;item4&quot; class=&quot; pl-4 mt-1 space-y-1 hidden transition-all duration-300 ease-in-out&quot;&gt;
               &lt;li&gt;&amp;gt; Softmax is a mathematical function which converts a vector of real-valued numbers into a probability distribution, where the values are non-negative and sum to 1. This makes it ideal for scenarios where you need to assign probablities to multiple classes to options.&lt;/li&gt;
             &lt;/ul&gt;
           &lt;/li&gt;
           
        &lt;/ul&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;mt-3&quot;&gt;
      &lt;h1 class=&quot;text-4xl mt-[57px] mb-3 font-serif&quot;&gt;
        Multi-Head Attention from Beginners POV
      &lt;/h1&gt;

      &lt;p class=&quot;font-serif mt-5 text-lg&quot;&gt;In Transformers, Multi-Head Attention takes the same Query (Q), Key (K), and Value (V) inputs as single-head attention but splits the work across multiple “heads.” Each head focuses on different aspects of the input—like grammar, meaning, or context—and together, they give the model a more nuanced understanding. It&#39;s the secret sauce behind why Transformers are so good at everything from translation to generating text like this!&lt;/p&gt;
      
      &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/multi/banner-multi.png&quot; class=&quot;rounded-xl my-4&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

      &lt;p class=&quot;mt-4 font-serif text-lg&quot;&gt;This is how Multi-Head Attention works inside, we will discuss everything about this diagram later in this blog. For now lets cover a main topic which is&lt;/p&gt;

      &lt;h1 class=&quot;font-serif text-3xl mt-[57px] mb-3&quot;&gt;Why &quot;Scale&quot; the Dot Product ?&lt;/h1&gt;
      &lt;p class=&quot;font-serif text-lg mt-4&quot;&gt;In the original &lt;span class=&quot;font-bold&quot;&gt;dot-product attention&lt;/span&gt;, the raw scores can become very large if the dimensionality of the query and key vectors \(
        (d_k)\) is high. This can cause the softmax function to produce extremely small gradients, leading to numerical instability during training.&lt;/p&gt;

        &lt;p class=&quot;text-lg font-serif&quot;&gt;To address this issue, the scaled dot-product attention introduces a scalling factor&lt;/p&gt;

        &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;
          \[\text{Attention{Q, K, V}} = \text{softmax} \left(\frac{Q \cdot K^T}{\sqrt{d_k}}\right) \cdot V\]
        &lt;/p&gt;

        &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;Here, \(
          (d_k)\), is the dimensionality of the key vectors. Dividing by \(\sqrt{d_k}\) ensures that the dot product are scaled appropriately, preventing the softmax function from saturing&lt;/p&gt;
    &lt;/div&gt;

    &lt;p class=&quot;font-serif text-lg mt-4&quot;&gt;After all this you might get up with a question&lt;/p&gt;

    &lt;div class=&quot;mt-8&quot;&gt;
      &lt;h1 class=&quot;text-3xl font-serif&quot;&gt;Why Multi-Head Attention ?&lt;/h1&gt;
      &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;Single head attention is great, but it&#39;s limited. It computes one set of attention weights and mixes all the information into single output. That&#39;s like trying to hear every instrument in symphony with one ear it works, but you miss the layers. Multi-Head Attention says, &quot;Why settle for one prespective?&quot; By running attention multiple times in parallel. each with its own lens (or &quot;head&quot;), the model captures diverse relationships in the data-like how &quot; it&quot; refers to &quot;cat&quot; in one head, while another head notices the verb tense.&lt;/p&gt;

      &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;Plus, its still parallelizable (unlike RNN&#39;s), so its fast. More heads = more insights, without slowing things down. Genius, right ?&lt;/p&gt;
    &lt;/div&gt;

    &lt;p class=&quot;mt-6 font-serif text-lg&quot;&gt;Now one would wonder if Multi Head Attention helps so much, how does it work under the hood ? So lets start with our second most important topic which is&lt;/p&gt;

    &lt;div class=&quot;mt-8&quot;&gt;
      &lt;h1 class=&quot;font-serif text-3xl mt-5&quot;&gt;How Does Multi-Head Attention Work ?&lt;/h1&gt;
      &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/multi/workings.png&quot; class=&quot;my-5 mx-auto rounded-xl&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
      &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;Let’s get into the nitty-gritty. Here’s the step-by-step breakdown, with all the crazy details:&lt;/p&gt;

      &lt;ul class=&quot;ml-4 list-decimal text-lg font-serif&quot;&gt;
        &lt;li class=&quot;font-bold my-3&quot;&gt;Start with Q, K, V&lt;/li&gt;
        &lt;ul class=&quot;ml-8 list-disc font-serif&quot;&gt;
          &lt;li class=&quot;my-3&quot;&gt;We&#39;ve got your input sequence turned into embeddings (say a matrix (X) of shape \(\text{batch_size} \times \text{sequence_length} \times d_{\text{model}}\))&lt;/li&gt;
          &lt;li class=&quot;my-3&quot;&gt;From (X), we can compute \[Q = X \cdot W_Q \] \[K = X \cdot W_K\] \[V = X \cdot W_V \]&lt;/li&gt;
          &lt;li class=&quot;my-3&quot;&gt;Here, \(d_{\text{model}}\) is the embedding size (e.g., 512 in the original Transformer). Each (W) is a learned weight matrix&lt;/li&gt;
        &lt;/ul&gt;
        &lt;li class=&quot;font-bold my-3&quot;&gt;Split Into Heads&lt;/li&gt;
        &lt;ul class=&quot;ml-8 list-disc font-serif&quot;&gt;
          &lt;li class=&quot;my-3&quot;&gt;Instead of using the full \(d_{\text{model}}\) dimensional vectors, split them into (h) heads (e.g h=8)&lt;/li&gt;
          &lt;li class=&quot;my-3&quot;&gt;Each Head gets a smaller chunk of the dimensions: \(d_k = d_v = d_{\text{model}} / h\) (e.g., 512 / 8 = 64)&lt;/li&gt;
          &lt;li class=&quot;my-3&quot;&gt;For each head (i): 
            &lt;br&gt;\[Q_i = X \cdot W_Q^i\] (shape: \(\text{batch_size} \times \text{sequence_length} \times d_k\))
            &lt;br&gt;\[K_i = X \cdot W_K^i\] (shape: \(\text{batch_size} \times \text{sequence_length} \times d_k\))
            &lt;br&gt;\[V_i = X \cdot W_V^i\] (shape: \(\text{batch_size} \times \text{sequence_length} \times d_v\))
          &lt;/li&gt;
          &lt;li class=&quot;my-3&quot;&gt;Each \(W_Q^i, W_K^i, W_V^i\) is a slice of the original weight matrices, tailored to that head&lt;/li&gt;
        &lt;/ul&gt;
        &lt;li class=&quot;font-bold my-3&quot;&gt;Run Attention per Head&lt;/li&gt;
        &lt;ul class=&quot;ml-8 list-disc font-serif&quot;&gt;
          &lt;li class=&quot;my-3&quot;&gt;For each head (i), compute Scaled Dot-Product Attention:&lt;/li&gt;
          &lt;li class=&quot;my-3&quot;&gt;\[\text{head}_i = \text{Attention}(Q_i, K_i, V_i) = \text{softmax}\left(\frac{Q_i \cdot K_i^T}{\sqrt{d_k}}\right) \cdot V_i\]&lt;/li&gt;
          &lt;li class=&quot;my-3&quot;&gt;Each head produces an output of shape \(\text{batch_size} \times \text{sequence_length} \times d_v\)&lt;/li&gt;
          &lt;li class=&quot;my-3&quot;&gt;So, with (h) heads, you get (h) different outputs, each capturing a unique perspective&lt;/li&gt;
        &lt;/ul&gt;
        &lt;li class=&quot;font-bold my-3&quot;&gt;Concatenate the Heads&lt;/li&gt;
        &lt;ul class=&quot;ml-8 list-disc font-serif&quot;&gt;
          &lt;li class=&quot;my-3&quot;&gt;Stack all the head outputs side-by-side:&lt;/li&gt;
          &lt;li class=&quot;my-3&quot;&gt;\[\text{MultiHead}(Q, K, V) = \text{Concat}(\text{head}_1, \text{head}_2, ..., \text{head}_h)\]&lt;/li&gt;
          &lt;li class=&quot;my-3&quot;&gt;Shape becomes \(\text{batch_size} \times \text{sequence_length} \times (h \cdot d_v)\), which matches the original \(d_{\text{model}}\) (e.g., \(8 \cdot 64 = 512\))&lt;/li&gt;
        &lt;/ul&gt;
        &lt;li class=&quot;font-bold my-3&quot;&gt;Final Linear Transformation&lt;/li&gt;
        &lt;ul class=&quot;ml-8 list-disc font-serif&quot;&gt;
          &lt;li class=&quot;my-3&quot;&gt;Run the concatenated output through a learned linear layer to mix the heads’ insights:&lt;/li&gt;
          &lt;li class=&quot;my-3&quot;&gt;\[\text{Output} = \text{MultiHead}(Q, K, V) \cdot W_O\]&lt;/li&gt;
          &lt;li class=&quot;my-3&quot;&gt;\(W_O\) (shape: \(h \cdot d_v \times d_{\text{model}}\)) ensures the output shape is \(\text{batch_size} \times \text{sequence_length} \times d_{\text{model}}\), ready for the next layer&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/ul&gt;
    &lt;/div&gt;

    &lt;div class=&quot;mt-10&quot;&gt;
      &lt;h1 class=&quot;font-serif text-3xl mt-5&quot;&gt;The Math, Condensed&lt;/h1&gt;
      &lt;p class=&quot;text-lg font-serif mt-4&quot;&gt;Here’s the full formula:&lt;/p&gt;
      &lt;p class=&quot;text-lg font-serif my-3&quot;&gt;\[\text{MultiHead}(Q, K, V) = \text{Concat}(\text{head}_1, ..., \text{head}_h) \cdot W_O\]&lt;/p&gt;
      
      &lt;p class=&quot;text-lg font-serif my-3&quot;&gt;where:&lt;/p&gt;
      &lt;p class=&quot;text-lg font-serif my-3&quot;&gt;\[\text{head}_i = \text{softmax}\left(\frac{(X \cdot W_Q^i) \cdot (X \cdot W_K^i)^T}{\sqrt{d_k}}\right) \cdot (X \cdot W_V^i)\]&lt;/p&gt;
      
      &lt;ul class=&quot;ml-4 list-disc text-lg font-serif&quot;&gt;
        &lt;li class=&quot;my-3&quot;&gt;For self-attention, (Q, K, V) all come from the same (X)&lt;/li&gt;
        &lt;li class=&quot;my-3&quot;&gt;For cross-attention (e.g., in the decoder), (Q) might come from the decoder, and (K, V) from the encoder&lt;/li&gt;
      &lt;/ul&gt;
    &lt;/div&gt;

    &lt;p class=&quot;text-lg font-serif my-4&quot;&gt;Okkay now we are heading to the part which everyone liked in the previous blog. Yupp the &lt;span class=&quot;font-bold&quot;&gt;INTUITION&lt;/span&gt;. Sorry if I cannot carry up the hype, but I will try my best &amp;lt;3&lt;/p&gt;


    &lt;div class=&quot;mt-8&quot;&gt;
      &lt;h1 class=&quot;text-3xl font-serif&quot;&gt;Intuition : (Heist Edition)&lt;/h1&gt;
      &lt;img src=&quot;https://mrinalxdev.github.io/mrinalxblogs/blogs/assets/multi/image.jpg&quot; class=&quot;my-4 rounded-xl&quot; alt=&quot;&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
      &lt;p class=&quot;font-serif text-lg mt-4&quot;&gt;Your are a Detective | 刑事 &lt;/p&gt;
      &lt;p class=&quot;font-serif text-lg mt-4&quot;&gt;There has been a recent Bank Heist in your nearby bank and you are piecing together the details of the heist : &lt;span class=&quot;font-bold&quot;&gt;The thief escaped after the guard dozed off&lt;/span&gt;. With single-head attention, you are like one detective with a flashlight, sweeping the crime scene and connecting clus. You might lock onto &quot;thief&quot; and &quot;escaped&quot; but miss how  &quot;guard&quot; and &quot;dozed off&quot; set the stage for the getaway !!&lt;/p&gt;

      &lt;p class=&quot;font-serif text-lg mt-4&quot;&gt;Now &lt;span class=&quot;font-bold&quot;&gt;Multi Head attention&lt;/span&gt; steps in like a team of detectives, each with their own flashlight and intelligence&lt;/p&gt;

      &lt;ul class=&quot;font-serif ml-4 mt-4 list-disc&quot;&gt;
        &lt;li class=&quot;my-3&quot;&gt;Detective 1 :  Focuses on the players (“thief” → “guard”). Who’s involved? They spot the key characters in this drama.

        &lt;/li&gt;

        &lt;li class=&quot;my-3&quot;&gt;Detective 2: Tracks the action and timing (“escaped” → “dozed off”). When did it happen? They link the verbs to figure out the sequence.

        &lt;/li&gt;

        &lt;li class=&quot;my-3&quot;&gt;Detective 3: Sniffs out the cause-and-effect (“after” ties it all together). Why did it work? They catch the sneaky logic of the heist.

        &lt;/li&gt;
      &lt;/ul&gt;

      &lt;p class=&quot;text-lg font-serif&quot;&gt;The result? A richer, multi-layered picture of the heist—way more detailed than what one lone detective could crack on their own.&lt;/p&gt;
    &lt;/div&gt;


    &lt;hr class=&quot;my-10&quot;&gt;
    

    
  

</description><link>https://mrinalxdev.github.io/mrinalxblogs/blogs/multihead-atten.html</link><guid isPermaLink="false">https://mrinalxdev.github.io/mrinalxblogs/blogs/multihead-atten.html</guid><pubDate>Invalid Date</pubDate><author>Mrinal</author></item></channel></rss>