<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Chris Bao&#39;s Blog</title>
  
  
  <link href="https://baoqger.github.io/atom.xml" rel="self"/>
  
  <link href="https://baoqger.github.io/"/>
  <updated>2024-08-30T08:05:03.289Z</updated>
  <id>https://baoqger.github.io/</id>
  
  <author>
    <name>Chris Bao</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>Diagnose Memory Leaks in .NET Applications with WinDbg: A Hands-on Approach</title>
    <link href="https://baoqger.github.io/2024/05/01/dotnet-gc-memory-leak-windbg/"/>
    <id>https://baoqger.github.io/2024/05/01/dotnet-gc-memory-leak-windbg/</id>
    <published>2024-05-01T02:43:54.000Z</published>
    <updated>2024-08-30T08:05:03.289Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Introduction"><a href="#Introduction" class="headerlink" title="Introduction"></a>Introduction</h3><p>In this article, I will share what I learned about <code>.NET memory management</code> by troubleshooting a memory leak issue for a .NET service running in a real production environment. After reading this post, you can understand more about the following items:</p><ul><li><code>.NET Memory Management</code> and <code>.NET Garbage Collection</code></li><li>Diagnose memory usage with <code>WinDbg</code></li></ul><p>Previously I once published <a href="https://organicprogrammer.com/2022/08/05/userland-memory-allocation-one/">articles</a> about memory allocation of native applications written in C on Linux systems. I highly recommend you read both articles and compare what’s the difference, this can deepen your understanding of memory-related techniques.  </p><h3 id="Background"><a href="#Background" class="headerlink" title="Background"></a>Background</h3><p>Firstly, let me explain the background: the problematic .NET service is running on the <a href="https://learn.microsoft.com/en-us/azure/service-fabric/service-fabric-azure-clusters-overview"><code>Azure Service Fabric</code></a>, which consists of a cluster of <a href="https://en.wikipedia.org/wiki/Windows_Server">Windows Server</a>. If you are not familiar with Service Fabric, please refer to my <a href="https://organicprogrammer.com/2023/03/20/guide-to-service-fabric-architecture/">previous article</a>, which explains how to develop microservices based on it. The problem is that the memory usage of this .NET service reaches roughly <code>1.5GB</code>, which is 4 times higher than the average usage. Generally speaking, on the cloud more resource usage means higher cost. Next, let’s diagnose what is happening here. But before we roll up our sleeves to debug this issue, let’s first review how .NET memory works at a theoretical level.</p><h3 id="NET-Memory-Management"><a href="#NET-Memory-Management" class="headerlink" title=".NET Memory Management"></a>.NET Memory Management</h3><h5 id="NET-Runtime"><a href="#NET-Runtime" class="headerlink" title=".NET Runtime"></a>.NET Runtime</h5><p>Unlike native software written directly to the operating system’s APIs, programs written with <code>.NET</code> are called <code>managed</code> applications because they depend on a runtime and framework that manages many of their vital tasks and ensures a basic safe operating environment. In <code>.NET</code>, runtime refers to the <code>Common Language Runtime(CLR)</code> and the framework is <code>.NET Framework</code> or <code>.NET Core</code>. And the .NET application is built on top of them. </p><img src="/images/CLR.png" title=".NET and CLR" width="600px" height="400px"><p><code>CLR</code> works as a virtual execution engine for .NET applications, and it is a very complex topic that is out of the scope of this article, so we can’t dive into the details. But one of the crucial functionalities it provides is just: <code>memory management</code>. </p><h5 id="NET-GC"><a href="#NET-GC" class="headerlink" title=".NET GC"></a>.NET GC</h5><p>When you’re working on system programming with C or C++, you need to manage the memory by calling standard library’s APIs like <code>malloc</code> and <code>free</code> to allocate and release the memory. But on the .NET framework, your life will be easier since the .NET memory manager does this task for you. When the program creates a new object, the memory manager will allocate the memory for you. Easy, right? But that’s only a trivial part of the memory manager, the complicated task is how and when the memory manager can decide to collect the memory. Because of this, the .NET memory manager has another name: <code>.NET Garbage Collector</code>. </p><p>The .NET GC uses two Win32 functions <code>VirtualAlloc</code> and <code>VirtualFree</code> for allocating a segment of memory and releasing segments back to the operating system respectively. The entire process can be divided into the following three phases: </p><img src="/images/gcphases.png" title=".NET and CLR" width="600px" height="400px"><ul><li><strong>Marking Phase</strong>: A list of <code>live</code> objects is created during the marking phase. This is done by starting from a set of references called the <code>GC roots</code>. GC marks these root objects as <code>live</code> and then looks at any object that they reference and marks these as being <code>live</code> too. And the GC continues the search iteratively. This process is also called <code>reachability analysis</code>. All of the objects that are not on the reachable list are potentially released from the memory. </li></ul><img src="/images/reachability.png" title="GC roots" width="600px" height="400px"><ul><li><p><strong>Relocating Phase</strong>: The references of all the reachable objects are updated so that they point to the new location. The purpose of the relocating phase is to optimize memory usage by compacting the live objects closer together. This helps reduce <code>memory fragmentation</code> and improves memory allocation efficiency. </p></li><li><p><strong>Compacting Phase</strong>: The memory space occupied by the dead objects is released and the live objects are moved to the new location. </p></li></ul><p>GC algorithm is a complex topic, the above description only touches the surface of it. You can explore <a href="https://www.red-gate.com/simple-talk/development/dotnet-development/understanding-garbage-collection-in-net/">more</a> by yourself. In the following sections, I will add extra information when necessary. </p><h3 id="WinDbg"><a href="#WinDbg" class="headerlink" title="WinDbg"></a>WinDbg</h3><p>To diagnose .NET applications’ memory issues, there are many modern tools, like <a href="https://www.jetbrains.com/dotmemory/"><code>dotMemory</code></a>. But in this article, I will show you a low-level tool: <a href="https://en.wikipedia.org/wiki/WinDbg"><code>WinDbg</code></a>. <code>WinDbg</code> is a multipurpose debugger for the Windows OS, which can be used to debug both user mode and kernel mode. Originally WinDbg was used to debug the native applications, but WinDbg allows the loading of extensions which can augment the debugger’s supported commands. For example, to debug .NET applications running on CLR, we need the <a href="https://learn.microsoft.com/en-us/dotnet/framework/tools/sos-dll-sos-debugging-extension?redirectedfrom=MSDN"><code>SOS</code> extension</a>.  </p><p>Now that we have a powerful debugger in hand, the next question is how to use it. Generally speaking, you can attach the debugger to the problematic service, but since the target service is running in the production environment, we can’t do that easily. So we need to troubleshoot this issue in the offline style as follows:</p><img src="/images/procdump-windbg.png" title="GC roots" width="600px" height="400px"><p>We need to use <a href="https://learn.microsoft.com/en-us/sysinternals/downloads/procdump"><code>ProcDump</code></a> to dump the memory information into a file, called <code>dump file</code>. Then use <code>WinDbg</code> to analyze the dump file. I will not cover the usage of <code>ProcDump</code> in this article and leave it to you. </p><p>Next, let’s play with the dump file, all right? Let’s go! </p><h3 id="Diagnose-the-memory-leak"><a href="#Diagnose-the-memory-leak" class="headerlink" title="Diagnose the memory leak"></a>Diagnose the memory leak</h3><p>First, let’s use the WinDbg <code>!address</code> extension to display information about the memory that the target process or target computer uses as follows:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">0:000&gt; !address -summary</span><br><span class="line"></span><br><span class="line">--- Usage Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal</span><br><span class="line">Free                                    338     7ffe`d06bb000 ( 127.995 TB)          100.00%</span><br><span class="line">&lt;unknown&gt;                              4715        0`feb0f000 (   3.980 GB)  83.90%    0.00%</span><br><span class="line">Stack                                   276        0`16880000 ( 360.500 MB)   7.42%    0.00%</span><br><span class="line">Image                                  1241        0`0e989000 ( 233.535 MB)   4.81%    0.00%</span><br><span class="line">Heap                                    519        0`0b997000 ( 185.590 MB)   3.82%    0.00%</span><br><span class="line">Other                                    15        0`001cd000 (   1.801 MB)   0.04%    0.00%</span><br><span class="line">TEB                                      92        0`000b8000 ( 736.000 kB)   0.01%    0.00%</span><br><span class="line">PEB                                       1        0`00001000 (   4.000 kB)   0.00%    0.00%</span><br><span class="line"></span><br><span class="line">--- Type Summary (for busy) ------ RgnCount ----------- Total Size -------- %ofBusy %ofTotal</span><br><span class="line">MEM_PRIVATE                            5051        1`1e9d4000 (   4.478 GB)  94.41%    0.00%</span><br><span class="line">MEM_IMAGE                              1753        0`1013b000 ( 257.230 MB)   5.30%    0.00%</span><br><span class="line">MEM_MAPPED                               55        0`00e26000 (  14.148 MB)   0.29%    0.00%</span><br><span class="line"></span><br><span class="line">--- State Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal</span><br><span class="line">MEM_FREE                                338     7ffe`d06bb000 ( 127.995 TB)          100.00%</span><br><span class="line">MEM_RESERVE                            2503        0`cdc3c000 (   3.215 GB)  67.78%    0.00%</span><br><span class="line">MEM_COMMIT                             4356        0`61cf9000 (   1.528 GB)  32.22%    0.00%</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>Let’s examine the output, which provides so much information!</p><p>The <em>first</em> section shows the memory <code>Usage Summary</code>: </p><ul><li><strong>Free</strong>: is the entire <code>virtual memory</code> that can potentially be claimed from the operating system. This may include <code>swap space</code>, not only physical RAM. For a 64-bit process,  the virtual memory is <code>128TB</code>. </li><li><strong>Heap</strong>: what you see as <code>Heap</code> is the memory that was allocated through the <code>Windows Heap Manager</code>, we generally call it the <code>native heap</code>. </li><li><strong>Unknown</strong>: any other heap managers will implement their own memory management. Basically, they all work similarly: they get large blocks of memory from <code>VirtualAlloc</code> and then try to do a better management of the small block within that large block. Since WinDbg doesn’t know any of these memory managers, that memory is declared as <code>Unknown</code>. It includes but is not limited to the managed heap of <code>.NET</code>. In my case, the value is <code>3.98GB</code> which is much bigger than the <code>1.5GB</code> memory usage reported by the monitor tool. I will explain why it goes like this in the following sections. </li><li><strong>Image</strong>: is the memory space allocated for the binary assemblies. </li><li><strong>Stack</strong>: is straightforward. If you don’t know, please refer to my previous <a href="https://organicprogrammer.com/2020/08/19/stack-frame/">article</a>.</li></ul><p>The <em>second</em> section shows the usage by memory <code>Type</code>: <code>MEM_PRIVATE</code>, <code>MEM_IMAGE</code> and <code>MEM_MAPPED</code>. <code>MEM_PRIVATE</code> is private to one process and <code>MEM_IMAGE</code> and <code>MEM_MAPPED</code> can be shared among multiple processes. </p><p>The <em>third</em> section shows the usage by memory <code>State</code>.</p><ul><li><strong>MEM_COMMIT</strong>: committed memory refers to the portion of the virtual address space that has been allocated and backed by physical memory or the paging file. Committed memory is actively used and accessible by the process. It includes memory regions that have been allocated and are in use, such as code, data, and heap allocations. </li><li><strong>MEM_RESERVE</strong>: corresponds to reserved memory. Reserved memory refers to memory that has been reserved in the virtual address space but has not yet been committed. When memory is reserved, the address space is allocated, but physical memory or paging file resources are not immediately allocated. The process reserves the address space to ensure that it will be available when needed. Reserved memory can later be committed to make it usable by the process. </li><li><strong>MEM_FREE</strong>: represents free memory. This category includes all memory that has not been reserved or committed. </li></ul><p>In my case, the committed memory is <code>1.528GB</code>, which exactly matches the monitored memory usage. This can perfectly explain the confusing point mentioned about the <code>3.98GB</code> <code>unknown</code> memory segment. It turns out the majority of these memories are only reserved. So next step is to get the actual committed memory usage for various types. How to achieve that? </p><p>Thanks for the powerful <code>address</code> extension, I can do that by adding some filters like this:</p> <figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">!address -f:MEM_COMMIT -c:&quot;.echo %1 %3 %5 %7&quot;</span><br></pre></td></tr></table></figure><p> This command will output all the committed memory regions, and for each region prints its base address(%1), region size(%3), state(%5) and type(%7). The output goes as follows:</p> <figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">0x5f3a0000 0x1000 MEM_COMMIT Image</span><br><span class="line">0x5f3a1000 0x2ab000 MEM_COMMIT Image</span><br><span class="line">0x5f64c000 0xb000 MEM_COMMIT Image</span><br><span class="line">0x5f657000 0x1b000 MEM_COMMIT Image</span><br><span class="line">0x5f672000 0x2000 MEM_COMMIT Image</span><br><span class="line">0x5f674000 0x2d000 MEM_COMMIT Image</span><br><span class="line">0x7ffe0000 0x1000 MEM_COMMIT Other</span><br><span class="line">0x4580ca7000 0x5000 MEM_COMMIT Stack</span><br><span class="line">...thousands of lines omitted...</span><br></pre></td></tr></table></figure><p>I wrote a simple script to parse the above output and finally got the following result: </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">Memory by Type:</span><br><span class="line">type Image:  233.52344MB</span><br><span class="line">type Other:  1.8007812MB</span><br><span class="line">type Stack:  3.796875MB</span><br><span class="line">type TEB  :  0.71875MB</span><br><span class="line">type PEB  :  0.00390625MB</span><br><span class="line">type Heap :  84.88281MB</span><br><span class="line">type &lt;unknown&gt; :  1240.2461MB</span><br></pre></td></tr></table></figure><p>Based on this result, you can see the majority comes from the <code>unknown</code> segment. I suspect that the memory leak issue occurs in this problematic service. Various WinDbg <a href="https://www.tessferrandez.com/blog/2005/11/25/dumpheap-stat-explained.html">commands</a> can diagnose the memory leak problem. And in this specific case, I find the command <code>!finalizequeue</code> is super helpful!</p><p>Before I show you the output of the command, let’s examine what the <code>finalizer queue</code> is. In <code>C#</code>, the <code>finalizer</code>(also referred to as <code>destructor</code>)  is used to perform any necessary final clean-up when a class instance is being collected by the GC. </p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title">Car</span></span><br><span class="line">&#123;</span><br><span class="line">    ~Car()  <span class="comment">// finalizer</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="comment">// cleanup statements...</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>When your application encapsulates <code>unmanaged resources</code>, such as windows, files and network connections, you should use the <code>finalizer</code> to free those resources. </p><p>Objects of classes with finalizers can’t be removed immediately: they instead go to the <code>finalizer queue</code> and are removed from memory once the finalizer has been run. </p><p>Based on this, let’s examine the output of command <code>!finalizequeue</code>:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">0:000&gt; !FinalizeQueue</span><br><span class="line">SyncBlocks to be cleaned up: 0</span><br><span class="line">Free-Threaded Interfaces to be released: 0</span><br><span class="line">MTA Interfaces to be released: 0</span><br><span class="line">STA Interfaces to be released: 0</span><br><span class="line">----------------------------------</span><br><span class="line">generation 0 has 66 finalizable objects (0000021c729c47b0-&gt;0000021c729c49c0)</span><br><span class="line">generation 1 has 4 finalizable objects (0000021c729c4790-&gt;0000021c729c47b0)</span><br><span class="line">generation 2 has 4372 finalizable objects (0000021c729bbef0-&gt;0000021c729c4790)</span><br><span class="line">Ready for finalization 0 objects (0000021c729c49c0-&gt;0000021c729c49c0)</span><br><span class="line">Statistics for all finalizable objects (including all objects ready for finalization):</span><br><span class="line">              MT    Count    TotalSize Class Name</span><br><span class="line">00007ffcde443f78        1           32 Microsoft.Win32.SafeHandles.SafePEFileHandle</span><br><span class="line">00007ffcde4407f8        1           32 System.Security.Cryptography.X509Certificates.SafeCertContextHandle</span><br><span class="line"></span><br><span class="line">--- many lines of output omitted ---</span><br><span class="line"></span><br><span class="line">00007ffcde447db0       97         3104 Microsoft.Win32.SafeHandles.SafeWaitHandle</span><br><span class="line">00007ffcdd272468       28         4928 System.Diagnostics.PerformanceCounter</span><br><span class="line">00007ffcde45d6a8       64         6144 System.Threading.Thread</span><br><span class="line">00007ffcde4297c0     3639       262008 System.Reflection.Emit.DynamicResolver</span><br><span class="line">Total 4442 objects</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>You can notice that there are <code>3639</code> objects of type <code>System.Reflection.Emit.DynamicResolver</code>. As we know, the objects in the <code>finalizer queue</code> can’t be removed until the finalizer runs. This also means that any object they reference and any object referenced by those, and so on has to be kept in memory.</p><p>This is the potential reason for the memory leak problem. <a href="https://learn.microsoft.com/en-us/dotnet/api/system.reflection.emit?view=net-8.0"><code>System.Reflection.Emit</code></a> is a low-level library used to generate the Microsoft Intermediate Language (MSIL) dynamically, my application does not rely on it. Finally, it turns out the issue is from the Service Fabric SDK and upgrading to new versions can fix it. </p><h3 id="Summary"><a href="#Summary" class="headerlink" title="Summary"></a>Summary</h3><p>In this article, we examined how .NET GC works and how to diagnose the memory leak issue with WinDbg. </p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;Introduction&quot;&gt;&lt;a href=&quot;#Introduction&quot; class=&quot;headerlink&quot; title=&quot;Introduction&quot;&gt;&lt;/a&gt;Introduction&lt;/h3&gt;&lt;p&gt;In this article, I will share </summary>
      
    
    
    
    
    <category term="dotnet, GC, memory leak, WinDbg" scheme="https://baoqger.github.io/tags/dotnet-GC-memory-leak-WinDbg/"/>
    
  </entry>
  
  <entry>
    <title>Linux Foundation Scholarship</title>
    <link href="https://baoqger.github.io/2023/06/09/lift-scholarship-program/"/>
    <id>https://baoqger.github.io/2023/06/09/lift-scholarship-program/</id>
    <published>2023-06-09T02:19:04.000Z</published>
    <updated>2023-06-19T06:07:31.535Z</updated>
    
    <content type="html"><![CDATA[<p>After graduating from campus 10 years ago, I didn’t expect that I would still be eligible for a scholarship, especially considering that I wasn’t a high-achieving student at that time. But recently, I joined one program from Linux Foundation: <a href="https://www.linuxfoundation.org/about/lift-scholarships"><code>The Shubhra Kar Linux Foundation Training (LiFT) Scholarship Program</code></a>. And very luckily, get awarded. </p><img src="/images/lift-scholarship.png" title="lift" width="800px" height="600px"><p>I plan and hope to set up a bright new career in the open-source software field, that’s the motivation to join the program! </p><p>Thanks to the award from Linux Foundation, I got the opportunity to select one training course and certification exam freely. Big thanks. </p><p>And the one I choose is <a href="https://training.linuxfoundation.org/certification/certified-kubernetes-application-developer-ckad/"><code>CKAD (Certified Kubernetes Application Developer)</code></a>, stay tuned, I will update the status later. </p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;After graduating from campus 10 years ago, I didn’t expect that I would still be eligible for a scholarship, especially considering that </summary>
      
    
    
    
    
    <category term="Linux Foundation, Scholarship, LIFT" scheme="https://baoqger.github.io/tags/Linux-Foundation-Scholarship-LIFT/"/>
    
  </entry>
  
  <entry>
    <title>Scalability Lessons Learned from Amazon Return to The Monolith</title>
    <link href="https://baoqger.github.io/2023/04/09/understand-more-aws-service-by-negative-cases/"/>
    <id>https://baoqger.github.io/2023/04/09/understand-more-aws-service-by-negative-cases/</id>
    <published>2023-04-09T09:25:40.000Z</published>
    <updated>2023-06-19T06:08:32.209Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Background"><a href="#Background" class="headerlink" title="Background"></a>Background</h3><p>Recently, the engineering team at Amazon Prime Video posted an article that becomes super popular in the software community. Many discussions arose concerning <code>how to design a scalable application in the modern cloud computing era</code>.  </p><p><code>Scalability</code> is one critical metric for designing and developing an online application. Technically it is a challenging task, but the cloud made it easy; because the public cloud services providers like AWS and Azure do the job for you. <a href="https://www.cloudflare.com/learning/cloud/what-is-a-virtual-machine/"><code>Virtual machine</code></a>, <a href="https://en.wikipedia.org/wiki/Container"><code>Container</code></a> , and <a href="https://en.wikipedia.org/wiki/Serverless_computing"><code>Serverless</code></a>, you have so many powerful technologies to scale your application and business.  </p><p>But the problem is you need to choose the one suitable for your application. So in this article, let’s examine the details of why Aamzon refactors the application and how they do it.</p><p>Since Amazon doesn’t expose the code implementation of this project, our analysis is based on the <a href="https://www.primevideotech.com/video-streaming/scaling-up-the-prime-video-audio-video-monitoring-service-and-reducing-costs-by-90">original post</a> and the technical understanding of AWS. All right? </p><h3 id="Case-study"><a href="#Case-study" class="headerlink" title="Case study"></a>Case study</h3><p>The product refactored is called Amazon Prime Video Monitoring Service, which monitors the quality of thousands of live video streams. This monitoring tool runs the real-time analysis of the streams and detects quality issues. The entire process consists of 3 steps: <code>media converter</code>, <code>defect detector</code> and <code>real-time notification</code>. </p><ul><li><code>media converter</code>:  converting input audio/video streams to frames. </li><li><code>defect detector</code>:  executing machine learning algorithms that analyze frames to detect defects. </li><li><code>real-time notification</code>:  sending real-time notifications whenever a defect is found. </li></ul><p>The old architecture goes as follows: </p><img src="/images/prime-01.png" title="serverless architecture" width="600px" height="800px"><p>In this <code>microservices</code> architecture, each step was implemented by <code>AWS Lambda</code> <code>serverless</code> service (I assume you already know what is <code>serverless</code>; if not, please refer to other <a href="https://en.wikipedia.org/wiki/Serverless_computing">online documents</a>). And the entire workflow was orchestrated by <code>AWS Step Functions</code>, which is a serverless orchestration service.</p><h5 id="AWS-Step-Functions-State-Transition"><a href="#AWS-Step-Functions-State-Transition" class="headerlink" title="AWS Step Functions State Transition"></a>AWS Step Functions State Transition</h5><p>The first bottleneck is just coming from AWS Step Functions. But before discussing the issues of this architecture, we need to understand what is <code>AWS Step Functions</code> and how it works basically. This knowledge is very critical to understand the performance bottlenecks later. </p><p><code>AWS Step Functions</code> is a <code>serverless</code> service that allows you to coordinate and orchestrate multiple AWS serverless functions using a <code>state machine</code>. You can define the workflow of serverless applications as a state machine, which represents the different <code>states</code> and <code>transitions</code> of the application’s execution.</p><p>The <code>State machine</code> can be thought of as a <code>directed graph</code>, where each node represents a state, and each edge represents a transition between states, which is used to model complex systems. The topic of state machine isn’t in the scope of this article, I will write a post about it in the future. So far, you only need to know each state in the state machine represents a specific step in the workflow, while transitions represent the events that trigger the transition from one step to another. You can find many examples of <code>AWS Step Functions</code> in this <a href="https://github.com/aws-samples/aws-stepfunctions-examples/tree/main">repo</a>, please take a look at what problems you can solve with it. </p><p>In theory, this serverless-based microservices architecture can scale out easily. However, as the <a href="https://www.primevideotech.com/video-streaming/scaling-up-the-prime-video-audio-video-monitoring-service-and-reducing-costs-by-90">original post</a> mentioned it “<strong>hit a hard scaling limit at around 5% of the expected load. Also, the overall cost of all the building blocks was too high to accept the solution at a large scale.</strong>“ </p><p>So the bottleneck is the <code>cost</code>! Because AWS Step Functions <code>charges users per state transition</code>, and in this monitoring service case, it performed multiple state transitions for every second of the video stream, it quickly hit the account limits!</p><p>As a software engineer working in a team, maybe you can just focus on writing great codes, but when you need to select the tech stack, you have to consider the <code>cost</code>, especially when your application is running on the cloud. </p><h5 id="AWS-S3-Buckets-Tier-1-requests"><a href="#AWS-S3-Buckets-Tier-1-requests" class="headerlink" title="AWS S3 Buckets Tier-1 requests"></a>AWS S3 Buckets Tier-1 requests</h5><p>As mentioned above, the <code>media converter</code> service splits videos into frames, and the <code>defect detector</code> service loads and analyzes the frames later. So in the original architect, the frame images are stored in the Amazon S3 bucket. As the <a href="https://www.primevideotech.com/video-streaming/scaling-up-the-prime-video-audio-video-monitoring-service-and-reducing-costs-by-90">original post</a> mentioned “Defect detectors then download images and processed them concurrently using AWS Lambda. However, <strong>the high number of Tier-1 calls</strong> to the S3 bucket was expensive.”</p><p>So the second bottleneck is also a cost issue. But what is a <code>Tier-1 call</code> or request in the context of AWS S3? </p><p>A <code>Tier-1 request</code> refers to an API request that retrieves or lists objects in an S3 bucket, and is charged at a higher rate than other types of API requests. AWS S3 API requests are classified into two categories: <code>standard requests</code> and <code>Tier-1 requests</code>. </p><ul><li><code>standard requests</code>:  including API requests such as PUT, COPY, DELETE and HEAD requests. </li><li><code>Tier-1 requests</code>:  including API requests such as GET and LIST requests. </li></ul><p><code>Tier-1 requests</code> are expensive because they involve retrieving and listing objects in an AWS S3 bucket, which is more resource-intensive.  Because when you retrieve or list objects, S3 needs to scan through the entire bucket to find the targets. Additionally, S3 needs to transfer the data for each retrieved object over the network. So basically, it consumes more <code>storage</code> and <code>network</code> resources on the cloud. </p><h5 id="Monolith-Architecture"><a href="#Monolith-Architecture" class="headerlink" title="Monolith Architecture"></a>Monolith Architecture</h5><p>Based on these two bottlenecks, they refactored this monitoring tool and returned to the monolith architecture as follows: </p><img src="/images/prime-2.png" title="serverless architecture" width="600px" height="800px"><p>In the new design, everything is running inside a single process host in <code>Amazon Elastic Container Service(ECS)</code>. In this monolith architecture, the frames are stored in the memory instead of S3 buckets. It doesn’t need serverless orchestration service either. </p><p>How does this new architecture run at a high scale? They directly scale out and partition the <code>Amazon ECS</code> cluster. In this way, they get a scalable monitoring application with a 90% cost reduction. </p><h3 id="Summary"><a href="#Summary" class="headerlink" title="Summary"></a>Summary</h3><p>There is no perfect application architecture that can fit all cases. In the cloud computing era, you need to understand the service you used better than before and make a wise decision. </p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;Background&quot;&gt;&lt;a href=&quot;#Background&quot; class=&quot;headerlink&quot; title=&quot;Background&quot;&gt;&lt;/a&gt;Background&lt;/h3&gt;&lt;p&gt;Recently, the engineering team at Amaz</summary>
      
    
    
    
    
    <category term="Scalability, AWS" scheme="https://baoqger.github.io/tags/Scalability-AWS/"/>
    
  </entry>
  
  <entry>
    <title>Build Microservices with Service Fabric: A Hands-on Approach</title>
    <link href="https://baoqger.github.io/2023/03/20/guide-to-service-fabric-architecture/"/>
    <id>https://baoqger.github.io/2023/03/20/guide-to-service-fabric-architecture/</id>
    <published>2023-03-20T10:18:32.000Z</published>
    <updated>2024-05-02T07:40:45.593Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Background"><a href="#Background" class="headerlink" title="Background"></a>Background</h3><p>In this article, I want to introduce a distributed systems platform: <a href="https://learn.microsoft.com/en-us/azure/service-fabric/service-fabric-overview"><code>Service Fabric</code></a>, that is used to build microservices. </p><p>First things first, what is <code>Service Fabric</code>? In the software world, <code>Service Fabric</code> is in the scope of the <code>orchestrator</code>. So it is the competitor of <a href="https://kubernetes.io/"><code>Kubernetes</code></a>, <a href="https://docs.docker.com/engine/swarm/"><code>Docker Swarm</code></a>, etc. </p><p>I know what you’re thinking about, at the time of writing, <code>Kubernetes</code> already won the competition. Why am I still writing about <code>Service Fabric</code>? My motivation to write this post is as follows:</p><ul><li>Firstly, I once used <code>Service Fabric</code> to build microservices and learned something valuable about it. I want to summarize all my learnings and share them with you here! </li><li>Secondly, we can (simply) examine both <code>Service Fabric</code> and <code>Kubernetes</code> to understand why the cloud-native solution is better and what problems it can solve. </li><li>Finally, <code>Service Fabric</code> is still widely used in some enterprise applications, in detail, you can refer <a href="https://learn.microsoft.com/en-us/azure/service-fabric/service-fabric-application-scenarios">here</a>. So the skills you learned about service fabric are valuable. </li></ul><h3 id="Hands-on-Project"><a href="#Hands-on-Project" class="headerlink" title="Hands-on Project"></a>Hands-on Project</h3><p>To learn the <code>Service Fabric</code> platform, we will examine an open-source project: <a href="https://github.com/baoqger/service-fabric-dotnet-data-aggregation">HealthMetrics</a>. This project is originally developed by Microsoft itself to demonstrate the power of service fabric and I added some enhancements to it, in detail please refer to this <a href="https://github.com/baoqger/service-fabric-dotnet-data-aggregation">GitHub repo</a>.</p><p>At the business requirement level, this application goes like this: each <code>patient</code> keeps reporting the heart rate data to the <code>doctor</code> via the wearable device(the <code>band</code> in this case). And the <code>doctor</code> aggregates the collected health data and reports to the <code>county</code> service. Each <code>county</code> service instance runs some statistics on doctors’ data and sends the report to the <code>country</code> service. Finally, you can get something as follows: </p><img src="/images/health-metrics-ui.png" title="health metrics" width="800px" height="600px"><p>Before we explore the detailed implementation, you can pause here for a few minutes. How will you design the architecture if this application is assigned to you? How to make it both <code>reliable</code> and <code>scalable</code>?  </p><h3 id="Service-Fabric-Programming-Model"><a href="#Service-Fabric-Programming-Model" class="headerlink" title="Service Fabric Programming Model"></a>Service Fabric Programming Model</h3><p><code>Service Fabric</code> provides multiple ways to write and manage your services: </p><ul><li>Reliable Services: is the most popular choice in the context of service fabric, we’ll examine much more about it later. </li><li>Containers: service fabric can also deploy services in containers. But if you choose to use containers, why not directly use <code>Kubernetes</code>? I’ll not cover it in this post. </li><li>Guest executables: You can run any type of code or script like Node.js as guest executables in the service fabric. Note that the service fabric platform doesn’t include the runtime for the guest executables, instead, the operating system hosting the service fabric must provide the corresponding runtime for the given language. It provides a flexible way to run legacy applications within microservices. If you have an interest in it, please refer to this <a href="https://learn.microsoft.com/en-us/azure/service-fabric/service-fabric-guest-executables-introduction">article</a>, I will not examine the details in this post.</li></ul><p>Next, let’s examine what are <code>Reliable Services</code>.</p><h3 id="Reliable-Services"><a href="#Reliable-Services" class="headerlink" title="Reliable Services"></a>Reliable Services</h3><p>As I mentioned above, <code>service fabric</code> is an <code>orchestrator</code> which provides infrastructure-level functionalities like <code>cluster management</code>, <code>service discovery</code>, and <code>scaling</code> as <code>Kubernetes</code> does. But <code>service fabric</code> goes further by also providing a <code>reliable services</code> model to guide the development on the application level, this’s a special point compared to <code>Kubernetes</code>. Simply speaking, the application code can call the <code>service fabric</code> runtime APIs to query the system for building reliable applications. In the following sections, I’ll show you what that means with some code blocks. </p><p><code>Reliable Services</code> can be classified into two types as follows: </p><ul><li>Stateless service: when we mentioned stateless service in the context of service fabric, we are not saying that the service doesn’t have any state to store, but it means that the service doesn’t store the data inside the cluster of service fabric. Indeed, the stateless service can store states in the external database. The naming of stateless is relative to the cluster. </li><li>Stateful service: similarly, the stateful service keeps its state locally in the service fabric cluster, which means the data and service are in the same virtual or physical machine. And this is called <code>Reliable Collections</code>. Compared with external data storage, <code>Reliable Collections</code> implies low latency and high performance. In the following section, I will introduce more about <code>Reliable Collections</code>, which is a very interesting topic. Please hold on!</li></ul><img src="/images/reliable-services.png" title="reliable services" width="600px" height="400px"><p>Besides stateless and stateful services listed above, there is the third type of service provided by Service Fabric: <code>Actor Service</code>. </p><ul><li>Actor Service: is a special type of stateful service, which applies the <code>actor model</code> theory. The <a href="https://en.wikipedia.org/wiki/Actor_model"><code>actor model</code></a> is a general computer science theory handling <code>concurrent computation</code>. It is a very big topic worthy of a separate article. I’ll not cover the details in this post, instead, let’s go through this model in the context of service fabric. </li></ul><p>The <code>actor model</code> is proposed many years ago in 1973 to simplify the process of writing concurrent programs with the following several advantages: </p><ul><li>Encapsulation: in the actor model, each actor is a self-contained unit that encapsulates its own state and behavior. And each actor runs <code>only one thread</code>, so you don’t have to worry about complex multi-threading programming issues. But how does it support high concurrency? Just allocate <code>more actor instances</code> as the load goes up.   </li><li>Message passing: different from the traditional multi-threading programming techniques, actors do not <code>share memories</code>, instead, they communicate with async message-passing communication, which can reduce the complexity of concurrent programs. </li><li>Location transparency: as a self-contained computation unit, each actor can be located on different machines, which makes it the perfect solution for building distributed applications as service fabric does. </li></ul><p>In the future, I will write an article on the actor model to examine more details about it. Next, let’s take a look at the demo app: <a href="https://github.com/baoqger/service-fabric-dotnet-data-aggregation">HealthMetrics</a> and analyze how it was built based on the programming models we discussed above. </p><img src="/images/actor-model.png" title="actor model" width="400px" height="300px">  <h3 id="Architecture-of-HealthMetrics"><a href="#Architecture-of-HealthMetrics" class="headerlink" title="Architecture of HealthMetrics"></a>Architecture of HealthMetrics</h3><img src="/images/healthmetrics-architecture.png" title="architecture" width="800px" height="600px"><p>There are several services included in this <code>HealthMetrics</code> demo application. They are: </p><ul><li>BandCreationService: this <code>stateless</code> service read the input CSV file and creates the individual <code>band actors</code> and <code>doctor actors</code>. For example, as the above snapshot shows, the application creates roughly 300 band actors and doctor actors.  </li><li>BandActor: this <code>actor</code> service is the host for the band actors. Each BandActor represents an individual wearable device, which generates heart rate data and then sends it to the designated DoctorActor every 5 seconds. </li><li>DoctorActor: the doctor <code>actor</code> service aggregates all of the data it receives from each band actor and generates an overall view for that doctor and then pushes it into the CountyService every 5 seconds.</li><li>CountyService: this <code>stateful</code> service aggregates the information provided by the doctor actor further and also pushes the data into the NationalService. </li><li>NationalService: this <code>stateful</code> service maintains the total aggerated data for the entire county and is used to serve data requested by WebService. </li><li>WebService: this <code>stateless</code> service just hosts a simple web API to query information from NationalService and render the data on the web UI. </li></ul><p>As you can see, this demo application consists of all three types of services provided by service fabric, which is a perfect case to learn <code>service fabric</code>, right? </p><p>In the next sections, let’s examine what kinds of techniques of service fabric are applied to build this highly <code>scalable</code> and <code>available</code> microservices application. </p><h3 id="Naming-Perspective"><a href="#Naming-Perspective" class="headerlink" title="Naming Perspective"></a>Naming Perspective</h3><p><code>Naming</code> plays an important role in the <code>distributed system</code>. They are used to share resources, to uniquely identify entities, to refer to locations, and so on. In the <code>distributed system</code>, each name should be resolved to the entity it refers to. To resolve names, it is necessary to implement a <code>naming system</code>.</p><p>In <code>Service Fabric</code>, <code>naming</code> is used to identify and locate <code>services</code> and <code>actors</code> within a cluster. And <code>Service Fabric</code> uses a <code>structured naming</code> system, where services and actors are identified using a <code>hierarchical</code> naming scheme. The naming system is based on the concept of a <code>namespace</code>. A namespace is a logical grouping of related <code>applications</code> and <code>services</code>. In the <code>Service Fabric</code> namespace, the first level is the <code>application</code>, which represents a logical grouping of services, and the second level is the <code>service</code>, which represents a specific unit of functionality that is part of the application. And the default namespace is <code>fabric:/</code>, so the service <a href="https://en.wikipedia.org/wiki/Uniform_Resource_Identifier">URI</a> in the <code>Service Fabric</code> cluster is in the following format: </p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">fabric:/applicationName/ServiceName</span><br></pre></td></tr></table></figure><p>And in our <code>HealthMetrics</code> demo app, the URL will be something like <code>fabric:/HealthMetrics/HealthMetrics.BandActor</code> or <code>fabric:/HealthMetrics/HealthMetrics.CountyService</code>(the application name is <code>HealthMetrics</code> and the service name is <code>HealthMetrics.BandActor</code> or <code>HealthMetrics.CountyService</code>). </p><p>In this demo app, we build a helper class <code>ServiceUriBuilder</code> to generate URI as follows: </p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> Uri <span class="title">ToUri</span>()</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="built_in">string</span> applicationInstance = <span class="keyword">this</span>.ApplicationInstance;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (String.IsNullOrEmpty(applicationInstance))</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">try</span></span><br><span class="line">        &#123;</span><br><span class="line">            <span class="comment">// the ApplicationName property here automatically prepends &quot;fabric:/&quot; for us</span></span><br><span class="line">            applicationInstance = FabricRuntime.GetActivationContext().ApplicationName.Replace(<span class="string">&quot;fabric:/&quot;</span>, String.Empty);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">catch</span> (InvalidOperationException)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="comment">// FabricRuntime is not available. </span></span><br><span class="line">            <span class="comment">// This indicates that this is being called from somewhere outside the Service Fabric cluster.</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> Uri(<span class="string">&quot;fabric:/&quot;</span> + applicationInstance + <span class="string">&quot;/&quot;</span> + <span class="keyword">this</span>.ServiceInstance);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>For detail, please refer to this source code <a href="https://github.com/baoqger/service-fabric-dotnet-data-aggregation/blob/master/HealthMetrics.Common/ServiceUriBuilder.cs">file</a>.</p><p>Since the behavior of the name resolver is quite similar to the internet domain name resolver, the <code>Service Fabric Name Service</code> can be regarded as an internal <a href="https://en.wikipedia.org/wiki/Domain_Name_System"><code>DNS</code></a> service. This type of internal <code>DNS</code> service is a common requirement for all distributed systems, including <code>Kubernetes</code>. In the modern <code>cloud-native</code> ecosystem, the popular choice is <a href="https://coredns.io/"><code>CoreDNS</code></a>, which runs inside K8S. In the future, I will write an article about DNS. Please keep watching my blog’s update.</p><p>Besides this default <code>DNS</code> solution mentioned above, you can use other <code>service registry</code> and <code>service discovery</code> solutions. For example, in my <a href="https://organicprogrammer.com/2020/11/16/golang-service-discovery-consul/">previous article</a>, I once examined how to do this based on <a href="https://www.consul.io/"><code>Consul</code></a>. Imagine your large-scale application consists of hundreds of microservices, with the default DNS solutions you have to hardcode so many names in each service. That’s just where <code>Consul</code> can help. In detail, I’ll not repeat it here, please refer to my previous article!</p><p>Now that we understand how the naming system works, let’s examine how to do inter-service communication based on that. </p><h3 id="Communication-Perspective"><a href="#Communication-Perspective" class="headerlink" title="Communication Perspective"></a>Communication Perspective</h3><p>Inter-service communication is at the heart of all distributed systems. For nondistributed platforms, communication between processes can be done by <code>sharing memories</code>. But the communication between processes on different machines has always been based on the low-level message passing as offered by the underlying <code>network</code>. There are two widely used models for communications in distributed systems: <code>Remote Procedure Call(RPC)</code> and <code>Message-Oriented Middleware(MOM)</code>. </p><ul><li><p><code>Remote Procedure Call(RPC)</code>: is ideal for <code>client-server</code> applications and aims at hiding message-passing details from the client. The <code>HTTP</code> protocol is a typical <code>client-server</code> model, so <code>HTTP</code> requests can be thought of as a type of <code>RPC</code>.  In the <code>client-server</code> model, the client and server <code>must be online at the same time</code> to <code>exchange</code> information, so it’s often called <code>synchronous communication</code>.  </p></li><li><p><code>Message-Oriented Middleware(MOM)</code>: is suitable for distributed applications, where the communication does not follow the strict pattern of a client-server model. In this model, there are three parties involved: the <code>message producer</code>, the <code>message consumer</code>, and the <code>message broker</code>. In this case, when the <code>message producer</code> publishes the message, the <code>message consumer</code> doesn’t have to be online, the <code>message broker</code> will store the message until the consumer becomes available to receive it, so this model is also called <code>asynchronous communication</code>.</p></li></ul><p>The <code>Service Fabric</code> supports <code>RPC</code> out of the box. In our <code>HealthMetrics</code> demo app, you can find the <code>RPC</code> calls and HTTP requests easily. For example, when the <code>BandActor</code> and the <code>DoctorActor</code> are created, the <code>RPC</code> call is used in the <a href="https://github.com/baoqger/service-fabric-dotnet-data-aggregation/blob/master/HealthMetrics.BandCreationService/Service.cs#L86"><code>BandCreationService</code></a> as follows: </p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">async</span> Task <span class="title">CreateBandActorTask</span>(<span class="params">BandActorGenerator bag, CancellationToken cancellationToken</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="comment">// omit some code for simplicity</span></span><br><span class="line">    ActorId bandActorId;</span><br><span class="line">    ActorId doctorActorId;</span><br><span class="line">    bandActorId = <span class="keyword">new</span> ActorId(Guid.NewGuid()); </span><br><span class="line">    doctorActorId = <span class="keyword">new</span> ActorId(bandActorInfo.DoctorId);</span><br><span class="line">    IDoctorActor docActor = ActorProxy.Create&lt;IDoctorActor&gt;(doctorActorId, <span class="keyword">this</span>.DoctorServiceUri);</span><br><span class="line">    <span class="keyword">await</span> docActor.NewAsync(doctorName, randomCountyRecord);</span><br><span class="line">    IBandActor bandActor = ActorProxy.Create&lt;IBandActor&gt;(bandActorId, <span class="keyword">this</span>.ActorServiceUri);</span><br><span class="line">    <span class="keyword">await</span> bandActor.NewAsync(bandActorInfo);</span><br><span class="line">    <span class="comment">// omit some code for simplicity</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>You can see the <code>ActorProxy</code> instance is created as the <code>RPC</code> client, and the <code>NewAsync</code> method of <code>BandActor</code> and <code>DoctorActor</code> service is called. For example, the <a href="https://github.com/baoqger/service-fabric-dotnet-data-aggregation/blob/master/HealthMetrics.BandActor/BandActor.cs#L78"><code>NewAsync</code></a> method of <code>BandActor</code> goes like this: </p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">async</span> Task <span class="title">NewAsync</span>(<span class="params">BandInfo info</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">await</span> <span class="keyword">this</span>.StateManager.SetStateAsync&lt;CountyRecord&gt;(<span class="string">&quot;CountyInfo&quot;</span>, info.CountyInfo);</span><br><span class="line">    <span class="keyword">await</span> <span class="keyword">this</span>.StateManager.SetStateAsync&lt;Guid&gt;(<span class="string">&quot;DoctorId&quot;</span>, info.DoctorId);</span><br><span class="line">    <span class="keyword">await</span> <span class="keyword">this</span>.StateManager.SetStateAsync&lt;HealthIndex&gt;(<span class="string">&quot;HealthIndex&quot;</span>, info.HealthIndex);</span><br><span class="line">    <span class="keyword">await</span> <span class="keyword">this</span>.StateManager.SetStateAsync&lt;<span class="built_in">string</span>&gt;(<span class="string">&quot;PatientName&quot;</span>, info.PersonName);</span><br><span class="line">    <span class="keyword">await</span> <span class="keyword">this</span>.StateManager.SetStateAsync&lt;List&lt;HeartRateRecord&gt;&gt;(<span class="string">&quot;HeartRateRecords&quot;</span>, <span class="keyword">new</span> List&lt;HeartRateRecord&gt;()); <span class="comment">// initially the heart rate records are empty list</span></span><br><span class="line">    <span class="keyword">await</span> <span class="keyword">this</span>.RegisterReminders();</span><br><span class="line"></span><br><span class="line">    ActorEventSource.Current.ActorMessage(<span class="keyword">this</span>, <span class="string">&quot;Band created. ID: &#123;0&#125;, Name: &#123;1&#125;, Doctor ID: &#123;2&#125;&quot;</span>, <span class="keyword">this</span>.Id, info.PersonName, info.DoctorId);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>You can ignore the detailed content of this method for now, I will explain in a later section.</p><p>And when the <code>DoctorActor</code> service reports its status, it calls the <code>CountyService</code> endpoint with HTTP requests: </p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">async</span> Task <span class="title">SendHealthReportToCountyAsync</span>()</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="comment">// omit some code</span></span><br><span class="line">    <span class="keyword">await</span> servicePartitionClient.InvokeWithRetryAsync(</span><br><span class="line">        client =&gt;</span><br><span class="line">        &#123;</span><br><span class="line">            Uri serviceAddress = <span class="keyword">new</span> Uri(</span><br><span class="line">                client.BaseAddress,</span><br><span class="line">                <span class="built_in">string</span>.Format(</span><br><span class="line">                    <span class="string">&quot;county/health/&#123;0&#125;/&#123;1&#125;&quot;</span>,</span><br><span class="line">                    partitionKey.Value.ToString(),</span><br><span class="line">                    id));</span><br><span class="line"></span><br><span class="line">            HttpWebRequest request = WebRequest.CreateHttp(serviceAddress);</span><br><span class="line">            request.Method = <span class="string">&quot;POST&quot;</span>;</span><br><span class="line">            request.ContentType = <span class="string">&quot;application/json&quot;</span>;</span><br><span class="line">            request.KeepAlive = <span class="literal">false</span>;</span><br><span class="line">            request.Timeout = (<span class="built_in">int</span>) client.OperationTimeout.TotalMilliseconds;</span><br><span class="line">            request.ReadWriteTimeout = (<span class="built_in">int</span>) client.ReadWriteTimeout.TotalMilliseconds;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">using</span> (Stream requestStream = request.GetRequestStream())</span><br><span class="line">            &#123;</span><br><span class="line">                <span class="keyword">using</span> (BufferedStream buffer = <span class="keyword">new</span> BufferedStream(requestStream))</span><br><span class="line">                &#123;</span><br><span class="line">                    <span class="keyword">using</span> (StreamWriter writer = <span class="keyword">new</span> StreamWriter(buffer))</span><br><span class="line">                    &#123;</span><br><span class="line">                        JsonSerializer serializer = <span class="keyword">new</span> JsonSerializer();</span><br><span class="line">                        serializer.Serialize(writer, payload);</span><br><span class="line">                        buffer.Flush();</span><br><span class="line">                    &#125;</span><br><span class="line"></span><br><span class="line">                    <span class="keyword">using</span> (HttpWebResponse response = (HttpWebResponse) request.GetResponse())</span><br><span class="line">                    &#123;</span><br><span class="line">                        ActorEventSource.Current.Message(<span class="string">&quot;Doctor Sent Data to County: &#123;0&#125;&quot;</span>, serviceAddress);</span><br><span class="line">                        <span class="keyword">return</span> Task.FromResult(<span class="literal">true</span>);</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    );</span><br><span class="line">    <span class="comment">// omit some code</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>In the demo app, no <code>asynchronous communication</code> is used. But you can easily integrate the <code>message broker</code> middleware with the <code>Service Fabric</code>. This kind of microservice design is called <code>Event-Driven Architecture</code>. In the future, I will write another article about it, please keep watching my blog!</p><h3 id="Scalability-Perspective"><a href="#Scalability-Perspective" class="headerlink" title="Scalability Perspective"></a>Scalability Perspective</h3><p><code>Scalability</code> has become one of the most important design goals for developers of distributed systems. A system can be scalable, meaning that we can easily add more users and resources to the system without any noticeable loss of performance. In most cases, scalability problems in distributed systems appear as performance problems caused by the limited capacity of servers and networks. </p><p>Simply speaking, there are two types of scaling techniques: <code>scaling up</code> and <code>scaling out</code>: </p><ul><li>scaling up: is the process by which a machine is equipped with more and often more powerful resources(e.g., by increasing memory, upgrading CPUs, or replacing network modules) so that it can better accommodate performance-demanding applications. However, there are limits to how much you can scale up a single machine, and at some point, it may become more cost-effective to scale out. </li><li>scaling out: is all about extending a networked computer system with more computers and subsequently distributing workloads across the extended set of computers. There are basically only three techniques we can apply: <code>asynchronous communication</code>, <code>replication</code> and <code>Partitioning</code>. </li></ul><p>We already examined asynchronous communication in the last section. Next, let’s take a deep look at the other two: </p><ul><li><p><code>Replication</code>:  is a technique, which <code>replicates</code> more components or resources, etc., across a distributed system. <code>Replication</code> not only increases <code>availability</code>; but also helps to balance the load between components, leading to <code>better performance</code>. In Service Fabric, no matter whether it is a stateless or stateful service, you can replicate the service across multiple nodes. As the workload of your application increases, Service Fabric will automatically distribute the load. But <code>replication</code> can only boost performance for <code>read</code> requests (which don’t change data); if you need to optimize the performance for <code>write</code> requests (which change data), you need <code>Partitioning</code>. </p></li><li><p><code>Partitioning</code>:  is an important scaling technique, which involves taking a component or other resource, splitting it into <code>smaller parts</code>, and subsequently spreading those parts across the system. Each partition only contains a subset of the entire dataset. This can help reduce the amount of data that needs to be processed and accessed by each partition,  which can lead to faster processing times and improved performance. In addition to reducing the size of the data set, partitioning can also improve concurrency and reduce contention.</p></li></ul><p>In Service Fabric, each <code>partition</code> consists of a <code>replica set</code> with a single <code>primary</code> replica and multiple active <code>secondary</code> replicas. Service Fabric makes sure to distribute replicas of partitions across nodes so that secondary replicas of a partition do not end up on the same node as the primary replica, which can increase the <code>availability</code>. </p><img src="/images/partition-replication.png" title="partition and replicas" width="600px" height="400px"> <p>The difference between a <code>primary</code> replica and a <code>secondary</code> replica is that the <code>primary</code> replica can handle both <code>read and write</code> requests, while the <code>secondary</code> replica can only handle <code>read</code> requests. Moreover, by default, the read requests are only handled by the <code>primary</code> replica, if you want to balance the read requests among all the <code>secondary</code> replicas, you need to set <a href="https://learn.microsoft.com/en-us/azure/service-fabric/service-fabric-reliable-services-lifecycle"><code>ListenOnSecondary</code></a> at the application code level. You can set the number of replicas with <a href="https://github.com/baoqger/service-fabric-dotnet-data-aggregation/blob/master/HealthMetricsApplication/Scripts/HealthMetricsDeployment.ps1#L155"><code>MinReplicaSetSize</code></a> and <a href="https://github.com/baoqger/service-fabric-dotnet-data-aggregation/blob/master/HealthMetricsApplication/Scripts/HealthMetricsDeployment.ps1#L158"><code>TargetReplicaSetSize</code></a></p><p>And when the client needs to call the service with multiple partitions, the client needs to generate a <code>ServicePartitionKey</code>; and send requests to the service with this partition key. For example, the <code>DoctorActor</code> sends the health report to the county service with multiple partitions as follows: </p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">async</span> Task <span class="title">SendHealthReportToCountyAsync</span>()</span> &#123;</span><br><span class="line">    <span class="comment">// omit some code </span></span><br><span class="line">    ServicePartitionKey partitionKey = <span class="keyword">new</span> ServicePartitionKey(countyRecord.CountyId);</span><br><span class="line">    ServicePartitionClient&lt;HttpCommunicationClient&gt; servicePartitionClient =</span><br><span class="line">    <span class="keyword">new</span> ServicePartitionClient&lt;HttpCommunicationClient&gt;(</span><br><span class="line">        <span class="keyword">this</span>.clientFactory,</span><br><span class="line">        <span class="keyword">this</span>.countyServiceInstanceUri,</span><br><span class="line">        partitionKey);</span><br><span class="line">    <span class="keyword">await</span> servicePartitionClient.InvokeWithRetryAsync();</span><br><span class="line">    <span class="comment">// omit some code</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>You can see the partition key is generated based on the county id field. Service Fabric provides several different <a href="https://learn.microsoft.com/en-us/azure/service-fabric/service-fabric-concepts-partitioning">partition schemas</a>. In this case, <code>ranged partitioning</code> is used, where the partition key is an <code>integer</code>. </p><p>The county service specifies an integer range by a <a href="https://github.com/baoqger/service-fabric-dotnet-data-aggregation/blob/master/HealthMetricsApplication/Scripts/HealthMetricsDeployment.ps1#L34"><code>Low Key</code></a> ( set to 0) and <a href="https://github.com/baoqger/service-fabric-dotnet-data-aggregation/blob/master/HealthMetricsApplication/Scripts/HealthMetricsDeployment.ps1#L35"><code>High Key</code></a> (set to 57000). It also defines the number of partitions as <a href="https://github.com/baoqger/service-fabric-dotnet-data-aggregation/blob/master/HealthMetricsApplication/Scripts/HealthMetricsDeployment.ps1#L61"><code>PartitionCount</code></a> (set to 3). All the integer keys are evenly distributed among the partitions. So the partitions of the county service go as follows: </p><img src="/images/partition-key.png" title="partition key" width="400px" height="300px"> <p>As I mentioned above, the county id is unique, we could then generate a hash code based on the id field, then modulus the key range, to finally get the partition key. Service Fabric runtime will direct the requests to the target node based on that partition key. </p><h3 id="Summary"><a href="#Summary" class="headerlink" title="Summary"></a>Summary</h3><p>In this post, we quickly examined some interesting topics about Service Fabric. I have to admit that Service Fabric is a big project, what I examined here only covers a small portion of the entire system. Feel free to explore more!</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;Background&quot;&gt;&lt;a href=&quot;#Background&quot; class=&quot;headerlink&quot; title=&quot;Background&quot;&gt;&lt;/a&gt;Background&lt;/h3&gt;&lt;p&gt;In this article, I want to introduce a</summary>
      
    
    
    
    
    <category term="Service Fabric, stateless, stateful, actor model, scalability, reliability,  partition" scheme="https://baoqger.github.io/tags/Service-Fabric-stateless-stateful-actor-model-scalability-reliability-partition/"/>
    
  </entry>
  
  <entry>
    <title>Understand Red Black Tree: part one - background</title>
    <link href="https://baoqger.github.io/2023/02/13/note-on-red-black-tree/"/>
    <id>https://baoqger.github.io/2023/02/13/note-on-red-black-tree/</id>
    <published>2023-02-12T23:51:56.000Z</published>
    <updated>2023-05-09T05:33:38.735Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Introduction"><a href="#Introduction" class="headerlink" title="Introduction"></a>Introduction</h3><p>In this series of articles, I want to examine an important data structure: the <a href="https://en.wikipedia.org/wiki/Red%E2%80%93black_tree">red-black tree</a>. The <code>red-black tree</code> is an advanced data structure that is difficult to fully understand. Maybe you have some wonders and confusion about it as follows:</p><ul><li>What is the meaning of <code>red</code> and <code>black</code> here?</li><li>The <code>red-black tree</code> is known as a self-balancing binary search tree. But what’s the difference between it and others? </li><li>Where is it used or applied?  </li></ul><p>If you want to know the answer to the above questions, then this article is just for you. I will cover the following topics:</p><ul><li>Why do we need the red-black tree and what is its advantage? </li><li>How does a red-black tree work?</li><li>How to write a red-black tree from scratch? </li></ul><h3 id="Background-of-Red-Black-Tree"><a href="#Background-of-Red-Black-Tree" class="headerlink" title="Background of Red-Black Tree"></a>Background of Red-Black Tree</h3><p>In this section, let’s review the history of the red-black tree. During this process, I will show you why it was invented and what kind of advantages it can provide compared with other tree data structures. </p><p>First thing first, let’s define the red-black tree as follows: </p><ul><li>Red-Black Tree is a <code>self-balancing</code> <code>binary</code> <code>search</code> <code>tree</code>. </li></ul><p>Let’s analyze this definition step by step: </p><ul><li><p>Tree: A tree is a <code>nonlinear</code> data structure, compared to <code>arrays</code>, <code>linked lists</code>, <code>stacks</code> and <code>queues</code> which are <code>linear</code> data structures. A tree is a data structure consisting of one node called the <code>root</code> and zero or one or more <code>subtrees</code>. One disadvantage of <code>linear</code> data structures is the time required to search a <code>linear</code> list is proportional to the size of the data set, which means that the time complexity is <code>O(n)</code>. That’s why more efficient data structures like trees are invented to <code>store</code> and <code>search</code> data. </p></li><li><p>General Tree: A general tree is a tree where each node may have zero or more children. </p></li><li><p>Binary Tree: A binary tree is a specialized case of a general tree, where each node can have no more than <code>two</code> children. </p></li><li><p>Binary Search Tree: A binary tree satisfying the <code>binary search</code> property is called a <code>binary search tree(BST)</code>. To build a BST, the node with a key greater than any particular node is stored on the <code>right</code> sub-trees and the one equal to or less than is stored on the <code>left</code> sub-tree. </p></li></ul><p>The <code>average</code> search time complexity of BST is <code>O(logN)</code>, but in the <code>worst case</code>, it will be degraded to <code>O(N)</code>. It happens when we insert the nodes one by one in order. For example, if we insert the elements in array <code>[1, 2, 3, 4, 5, 6]</code> into RST in order, what we get is as follows: </p><img src="/images/bst-degraded.png" title="arp spoofing detection" width="200px" height="200px"><p>This kind of <code>unbalanced BST</code> is degraded to a single linked list. So the BST needs to keep balanced during the insert and delete of the node.  That’s where the <code>self-balancing</code> binary search tree comes from. </p><ul><li>Self-Balancing Binary Search Tree: it’s a binary search tree that automatically keeps its height small in the face of arbitrary item insertions and deletions. And the red-black tree is just one type of it. </li></ul><h3 id="Summary"><a href="#Summary" class="headerlink" title="Summary"></a>Summary</h3><p>As the first post of this series, I examined the background of the red-black tree bit by bit. I hope you can understand what’s self-balancing binary search tree and why we need it. In the next post, I will start to examine the behavior and property of the red-black tree. </p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;Introduction&quot;&gt;&lt;a href=&quot;#Introduction&quot; class=&quot;headerlink&quot; title=&quot;Introduction&quot;&gt;&lt;/a&gt;Introduction&lt;/h3&gt;&lt;p&gt;In this series of articles, I </summary>
      
    
    
    
    
    <category term="Algorithm, Data structure, Tree, Red Black Tree" scheme="https://baoqger.github.io/tags/Algorithm-Data-structure-Tree-Red-Black-Tree/"/>
    
  </entry>
  
  <entry>
    <title>Deletion operation in Binary Search Tree: successor or predecessor</title>
    <link href="https://baoqger.github.io/2023/01/01/bst-deletion-issue/"/>
    <id>https://baoqger.github.io/2023/01/01/bst-deletion-issue/</id>
    <published>2023-01-01T04:10:04.000Z</published>
    <updated>2024-08-30T08:45:00.682Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Introduction"><a href="#Introduction" class="headerlink" title="Introduction"></a>Introduction</h3><p>Today, in this article I want to examine one concrete topic: how to delete a node from a <code>binary search tree</code>. This question is important for understanding other tree data structures, like the <a href="https://en.wikipedia.org/wiki/AVL_tree">AVL tree</a>, and the <a href="https://en.wikipedia.org/wiki/Red%E2%80%93black_tree">Red-Black tree</a>. </p><p>As is common with many data structures, <code>deletion</code> is always the hardest operation. For example, to delete a specific element from the <a href="https://en.wikipedia.org/wiki/Array">array</a>, we need to shift all the elements after it by one index. And to delete one node from the <a href="https://en.wikipedia.org/wiki/Linked_list">linked list</a>, we need to reset the pointer of the previous node (if it’s a doubled linked list, we need to reset more points, which is a more complex case). This is the same for the binary search tree as well. Let’s see in the following section. </p><p>Note: the idea of this article is inspired by the book <strong><em>Data Structures and Algorithm Analysis in C</em></strong> written by <a href="http://users.cs.fiu.edu/~weiss/">Mark Allen Weiss</a>. The demo code shown in the following section is from this book. And I made some changes based on it. I highly recommend this great book to readers.  </p><h3 id="Deletion-of-the-binary-search-tree"><a href="#Deletion-of-the-binary-search-tree" class="headerlink" title="Deletion of the binary search tree"></a>Deletion of the binary search tree</h3><p>Before we can examine the deletion operation in depth, let’s quickly review the concept of the binary search tree as follows:</p><ul><li>Binary search tree: is a binary tree holding the following property that for every node, X, in the tree, the values of all the keys in its left subtree are smaller than the key value in X, and the values of all the keys in its right subtree are larger than the key value in X. </li></ul><p>Simply speaking, the binary search tree is a binary tree satisfying the <code>binary search</code> property. So each node of a binary search tree can have two children subtrees at most. When we need to delete one node from the binary search tree, then it’s necessary to consider the following 3 cases. </p><p>If the node is a <code>leaf</code>, then it can be deleted immediately. For example, to delete node <code>1</code> from the following binary search tree: </p><img src="/images/left-node-deletion.png" title="Delete leaf node from binary search tree" width="400px" height="500px"><p>I will show you how to implement it at the code level later, which summarizes all the cases. </p><p>If the node has only <code>one child subtree</code>, the node can be deleted after we reset its parent’s pointer to bypass the node and point to its child node. For example, to delete node <code>4</code> as follows: </p><img src="/images/onechild-node-deletion.png" title="Delete leaf node from binary search tree" width="400px" height="500px"><p>In the above example, node <code>4</code> has only one left child node <code>3</code>. Let’s consider the symmetric scenario, imagine what will happen when it has only one right child node. The answer is it doesn’t influence how we handle the deleted node here and the result is the same. I will not draw the diagram here and leave it for you to explore. </p><p>The complicated case is how to deal with a node with <code>two children</code>. Before we introduce the solution, let’s clarify one concept about the binary search tree: <code>successor</code>: </p><ul><li>Successor: is the node with the <code>minimum</code> value in the <code>right</code> subtree of any node.</li></ul><img src="/images/twochildren-delete-origin.png" title="Delete leaf node from binary search tree" width="200px" height="300px"><p>Let’s take node <code>16</code> in the above binary search tree as an example, the <code>successor</code> is node <code>17</code>. All right! Based on this concept, the solution to delete a node with two children is straightforward:</p><ul><li>Replace the data of the deleted node with the value of the <code>successor</code> and recursively delete the <code>successor</code> from the <code>right</code> subtree. </li></ul><p>Let’s try to analyze this solution. Firstly, replacing the data of the node with the value of the <code>successor</code> can keep the <code>binary search</code> property after the deletion operation. Secondly, since the <code>successor</code> has the minimum value of the subtree, which means it cannot have a left child. So the <code>successor</code> is either a leaf node without any child node or a node with only one right child node. So recursively deleting the <code>successor</code> can be resolved by the two simple cases we discussed above, it’s perfect, right?  For instance, the deletion of node <code>16</code> goes as follows: </p><img src="/images/twochildren-delete-after.png" title="Delete leaf node from binary search tree" width="500px" height="600px"><p>As we mentioned above, node <code>16</code>‘s <code>successor</code> is node <code>17</code>. So replace the value with 17 and delete node <code>17</code> from the right subtree, where node <code>17</code> is just a leaf node. Next, let’s implement the node deletion operation. </p><h3 id="Code-implementation"><a href="#Code-implementation" class="headerlink" title="Code implementation"></a>Code implementation</h3><p>In this article, I will only show the codes related to the deletion operation rather than the complete implementation of a binary search tree. If you want to know how to write a BST from scratch, please refer to this GitHub <a href="https://github.com/baoqger/data-structures-and-algorithm-analysis-in-c-practice/tree/main/trees/BinarySearchTree">repo</a>.</p><p>Firstly, let’s examine the header file, which contains the data type definitions and function declarations. </p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;utility.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> _BST_H</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> _BST_H</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="type">int</span> ET;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">TreeNode</span>;</span></span><br><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span> <span class="title">TreeNode</span> *<span class="title">Position</span>;</span></span><br><span class="line"><span class="keyword">typedef</span> Position BST;</span><br><span class="line"></span><br><span class="line">BST <span class="title function_">delete</span><span class="params">(ET, BST)</span>;</span><br><span class="line">Position <span class="title function_">findMinBST</span><span class="params">(BST)</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// code omitted here</span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br></pre></td></tr></table></figure><p>You can notice that besides the <code>delete</code> function, we also define a helper function <code>findMinBST</code> which is used to find the <code>successor</code> node. </p><p>Next, let’s examine the function definitions as follows: </p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line">BST</span><br><span class="line"><span class="title function_">delete</span><span class="params">(ET elem, BST T)</span></span><br><span class="line">&#123;</span><br><span class="line">    Position tmpCell;</span><br><span class="line">  </span><br><span class="line">    <span class="keyword">if</span> (T == <span class="literal">NULL</span>)</span><br><span class="line">        fatal(<span class="string">&quot;Element not found&quot;</span>);</span><br><span class="line">    <span class="keyword">else</span> <span class="keyword">if</span> (elem &lt; T-&gt;Element)</span><br><span class="line">        T-&gt;Left = delete(elem, T-&gt;Left);</span><br><span class="line">    <span class="keyword">else</span> <span class="keyword">if</span> (elem &gt; T-&gt;Element)</span><br><span class="line">        T-&gt;Right = delete(elem, T-&gt;Right);</span><br><span class="line">    <span class="keyword">else</span> <span class="comment">// we found the element to be deleted</span></span><br><span class="line">    <span class="keyword">if</span> (T-&gt;Left != <span class="literal">NULL</span> &amp;&amp; T-&gt;Right != <span class="literal">NULL</span>) <span class="comment">// two children</span></span><br><span class="line">    &#123;</span><br><span class="line">        tmpCell = findMinBST(T-&gt;Right);</span><br><span class="line">        T-&gt;Element = tmpCell-&gt;Element;</span><br><span class="line">        T-&gt;Right = delete(T-&gt;Element, T-&gt;Right);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">else</span> <span class="comment">// one or zero children, change the pointer T pointing to new address(NULl or the child node)</span></span><br><span class="line">    &#123;</span><br><span class="line">        tmpCell = T;</span><br><span class="line">        <span class="comment">// for leaf node, T will be reset to null</span></span><br><span class="line">        <span class="keyword">if</span> (T-&gt;Right == <span class="literal">NULL</span>)</span><br><span class="line">            T = T-&gt;Left;</span><br><span class="line">        <span class="keyword">else</span> <span class="keyword">if</span> (T-&gt;Left == <span class="literal">NULL</span>)</span><br><span class="line">            T = T-&gt;Right;</span><br><span class="line">        <span class="built_in">free</span>(tmpCell);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> T;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">Position</span><br><span class="line"><span class="title function_">findMinBST</span><span class="params">(BST T)</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="keyword">if</span> (T == <span class="literal">NULL</span>)</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line">  <span class="keyword">else</span> <span class="keyword">if</span> (T-&gt;Left == <span class="literal">NULL</span>)</span><br><span class="line">    <span class="keyword">return</span> T;</span><br><span class="line">  <span class="keyword">else</span></span><br><span class="line">    <span class="keyword">return</span> findMinBST(T-&gt;Left);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>I add some comments in the above code block which can help your understanding of this recursive algorithm. Please go ahead and think hard about it. </p><p>In the next section, we’ll have some open discussions about this solution. Let’s see whether there is any other solution. And what’re the potential issues of the current solution? </p><h3 id="Open-discussion"><a href="#Open-discussion" class="headerlink" title="Open discussion"></a>Open discussion</h3><h4 id="successor-vs-predecessor"><a href="#successor-vs-predecessor" class="headerlink" title="successor vs predecessor"></a>successor vs predecessor</h4><p>Firstly, in the above solution, we delete the node with two children based on the <code>successor</code>. And there is the other concept called <code>predecessor</code>: </p><ul><li>Predecessor: is the node with the <code>maximum</code> value in the left subtree of any node.</li></ul><p>So similarly, the alternative solution to delete the node with two children is: </p><ul><li>Replace the data of the deleted node with the value of the <code>predecessor</code> and recursively delete the <code>predecessor</code> from the <code>left</code> subtree.</li></ul><p>We can do this by writing another helper function <code>findMaxBST</code> as follows: </p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">Position</span><br><span class="line"><span class="title function_">findMaxBST</span><span class="params">(BST T)</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="keyword">if</span> (T != <span class="literal">NULL</span>)</span><br><span class="line">    <span class="keyword">while</span> (T-&gt;Right != <span class="literal">NULL</span>)</span><br><span class="line">      T = T-&gt;Right;</span><br><span class="line">  <span class="keyword">return</span> T;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Does it work? The answer is yes. But the performance of the solution based on the <code>predecessor</code> is worse than the one based on the <code>successor</code>. Because the <code>predecessor</code> has the maximum value of the left subtree, it means that the <code>predecessor</code> can have two children. Then when we delete the <code>predecessor</code> recursively, the worst-case time complexity can reach <code>O(logN)</code> while the solution based on the <code>successor</code> only requires constant(<code>O(1)</code>) time. That’s the difference. </p><h4 id="balanced-vs-unbalanced"><a href="#balanced-vs-unbalanced" class="headerlink" title="balanced vs unbalanced"></a>balanced vs unbalanced</h4><p>Although the above solution can work, it exposes a serious performance issue. The reason why people invent binary search tree data structures is that we can get <code>O(logN)</code> level performance for searching operations. But imagine what will happen if we keep inserting and deleting nodes in the binary search tree in the way we mentioned here. The depth of the tree will become <code>unbalanced</code>. The left subtree grows deeper than the right subtree because we are always replacing a deleted node with the <code>successor</code>(which is from the right subtree, right?) </p><p>The following image is borrowed from Mark’s great book I mentioned above, which clearly shows that the tree becomes <code>unbalanced</code> after many rounds of insertion and deletion. If you want to know about it in theory, please refer to the book.  </p><img src="/images/bst-unbalanced.png" title="Unbalanced binary search tree" width="800px" height="1000px"><p>For an unbalanced BST, the worst-case time complexity can be degraded to <code>O(n)</code>. To keep the desired performance, people invent a more advanced data structure <code>self-balancing binary search tree</code>, like the <code>AVL tree</code> and <code>Red-black tree</code>. I will share about them in the coming articles, please keep watching my blog. </p><h3 id="Summary"><a href="#Summary" class="headerlink" title="Summary"></a>Summary</h3><p>In this article, we examined various solutions to delete a node from the binary search tree and evaluated their performance. We also discussed some open questions about BST, which prove why we need more advanced data structures like the red-black tree. </p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;Introduction&quot;&gt;&lt;a href=&quot;#Introduction&quot; class=&quot;headerlink&quot; title=&quot;Introduction&quot;&gt;&lt;/a&gt;Introduction&lt;/h3&gt;&lt;p&gt;Today, in this article I want </summary>
      
    
    
    
    
    <category term="Binary Search Tree, delete, balanced, performance" scheme="https://baoqger.github.io/tags/Binary-Search-Tree-delete-balanced-performance/"/>
    
  </entry>
  
  <entry>
    <title>External Mergesort: part two</title>
    <link href="https://baoqger.github.io/2022/12/06/external-sorting-two/"/>
    <id>https://baoqger.github.io/2022/12/06/external-sorting-two/</id>
    <published>2022-12-06T03:11:06.000Z</published>
    <updated>2024-08-30T08:46:45.677Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Introduction"><a href="#Introduction" class="headerlink" title="Introduction"></a>Introduction</h3><p>In this last <a href="https://organicprogrammer.com/2022/11/02/external-sorting-one/">article</a>, we examined how <code>external mergesort</code> works in theory, let’s implement it now. </p><p>First, you can find all the source codes of this implementation in this Github <a href="https://github.com/baoqger/external-merge-sort">repo</a>. In this repo, I implemented both <code>two-way</code> and <code>multi-way</code> solutions, which are tracked in different branches, please be aware of this. But for the sake of simplicity, I will focus on the generalized <code>multi-way</code> mergesort solution in this article. </p><h3 id="Data-Preparation"><a href="#Data-Preparation" class="headerlink" title="Data Preparation"></a>Data Preparation</h3><p>Before diving into the code, let’s define the problem we need to solve here. I will generate an input file containing several millions of seven digits random numbers, from 1,000,000 to 9,999,999. The random numbers can be duplicated, and each number is stored in one new line of the input file. The input file can be prepared with the following Bash script which calls GNU <a href="https://en.wikipedia.org/wiki/Shuf">shuf</a> : </p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/usr/bin/bash </span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Author: Chris Bao</span></span><br><span class="line"><span class="comment"># Generate millions of seven digits random integers</span></span><br><span class="line"><span class="comment"># based on shuf utility</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">shuf</span> -i 1000000-9999999 -n 7777777 &gt; ./input.txt</span><br></pre></td></tr></table></figure><p>The generated input file is roughly <code>60 MB</code> in size. For modern computers, it can be loaded to memory easily. But since we are working external memory algorithm, so let’s assume we are running the algorithm on an old computer, which has only <code>100000 Byte</code> memory. Based on this assumed restriction, we need to sort the numbers in the input file and save the result in a new file. </p><h3 id="Implementation"><a href="#Implementation" class="headerlink" title="Implementation"></a>Implementation</h3><p>Let’s define some global constants in this algorithm:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">ifndef</span> CONSTANT_H</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> CONSTANT_H</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> MEMORY_LIMIT 100000</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> RECORD_SIZE 4</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> MULTI_WAY_NUMBER 2</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span> </span></span><br></pre></td></tr></table></figure><p><code>MEMORY_LIMIT</code> denotes the <code>100000 bytes</code> memory limit; In C, we can use the type <code>unsigned int</code> to store an integer in the range from 1,000,000 to 9,999,999. So <code>RECORD_SIZE</code> means each record(or integer) will take up 4 bytes of memory.</p><p>And by default, the algorithm will use the <code>two-way</code> merge, but the user can pass an argument to run a <code>multi-way</code> merge too. </p><h5 id="Sort-phase"><a href="#Sort-phase" class="headerlink" title="Sort phase"></a>Sort phase</h5><p>The sort phase is implemented inside the <code>separationSort</code> function as follows:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * Goes through a given file and separates that file into sorted 1MB files using (internal) mergeSort algorithm</span></span><br><span class="line"><span class="comment"> * */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">separationSort</span><span class="params">(FILE *input)</span> &#123;</span><br><span class="line">    FILE *fp;</span><br><span class="line">    <span class="type">unsigned</span> <span class="type">int</span> *buffer = <span class="built_in">malloc</span>(<span class="keyword">sizeof</span>(<span class="type">unsigned</span> <span class="type">int</span>)*(MEMORY_LIMIT/RECORD_SIZE));</span><br><span class="line">    <span class="type">char</span> *line = <span class="literal">NULL</span>;</span><br><span class="line">    <span class="type">size_t</span> len = <span class="number">0</span>;</span><br><span class="line">    <span class="type">ssize_t</span> nread;</span><br><span class="line">    <span class="type">int</span> count = <span class="number">0</span>;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;Sort phase start.\n&quot;</span>);</span><br><span class="line">    <span class="keyword">while</span>((nread = getline(&amp;line, &amp;len, input)) != <span class="number">-1</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (count &lt; MEMORY_LIMIT/RECORD_SIZE) &#123;</span><br><span class="line">            buffer[count++] = (<span class="type">unsigned</span> <span class="type">int</span>)strtoul(line, <span class="literal">NULL</span>, <span class="number">10</span>); </span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            mergeSort(buffer, count); <span class="comment">// sort records</span></span><br><span class="line">            </span><br><span class="line">            <span class="comment">// output sorted to file</span></span><br><span class="line">            <span class="keyword">if</span> (fileNum == <span class="number">1</span>) &#123; <span class="comment">// create the dir</span></span><br><span class="line">                <span class="type">int</span> status;</span><br><span class="line">                <span class="comment">// create tmp directory</span></span><br><span class="line">                <span class="keyword">if</span> ((status = mkdir(<span class="string">&quot;./tmp&quot;</span>, S_IRWXU | S_IRWXU | S_IROTH | S_IXOTH)) == <span class="number">-1</span>) &#123;</span><br><span class="line">                    <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;Failed to create tmp directory.\n&quot;</span>);</span><br><span class="line">                    <span class="built_in">exit</span>(EXIT_FAILURE);</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="comment">// create pass0 directory for sort phase</span></span><br><span class="line">                <span class="keyword">if</span> ((status = mkdir(<span class="string">&quot;./tmp/pass0&quot;</span>, S_IRWXU | S_IRWXU | S_IROTH | S_IXOTH)) == <span class="number">-1</span>) &#123;</span><br><span class="line">                    <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;Failed to create pass0 directory.\n&quot;</span>);</span><br><span class="line">                    <span class="built_in">exit</span>(EXIT_FAILURE);</span><br><span class="line">                &#125;</span><br><span class="line"> </span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="type">char</span> fileName[<span class="number">20</span>];</span><br><span class="line">            <span class="built_in">sprintf</span>(fileName, <span class="string">&quot;./tmp/pass0/%d.txt&quot;</span>, fileNum);</span><br><span class="line">            <span class="keyword">if</span> ((fp = fopen(fileName, <span class="string">&quot;w+&quot;</span>)) == <span class="literal">NULL</span>) &#123;</span><br><span class="line">                <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;Failed to create file: %s.\n&quot;</span>, fileName);</span><br><span class="line">                <span class="built_in">exit</span>(EXIT_FAILURE);</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            outputToFile(buffer, count, fp);</span><br><span class="line"></span><br><span class="line">            <span class="comment">// Reset memory buffer(zero-out the entire array)</span></span><br><span class="line">            <span class="built_in">memset</span>(buffer, <span class="number">0</span>, <span class="keyword">sizeof</span>(<span class="type">unsigned</span> <span class="type">int</span>)*(MEMORY_LIMIT/RECORD_SIZE));</span><br><span class="line">            count = <span class="number">0</span>;</span><br><span class="line">            fileNum++;</span><br><span class="line">            buffer[count++] = (<span class="type">unsigned</span> <span class="type">int</span>)strtoul(line, <span class="literal">NULL</span>, <span class="number">10</span>); <span class="comment">// add the current record into new buffer&#x27;s as first element</span></span><br><span class="line">            </span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// sort the last and final file</span></span><br><span class="line">    mergeSort(buffer, count);</span><br><span class="line">    <span class="type">char</span> fileName[<span class="number">20</span>];</span><br><span class="line">    <span class="built_in">sprintf</span>(fileName, <span class="string">&quot;./tmp/pass0/%d.txt&quot;</span>, fileNum);</span><br><span class="line">    <span class="keyword">if</span> ((fp = fopen(fileName, <span class="string">&quot;w+&quot;</span>)) == <span class="literal">NULL</span>) &#123;</span><br><span class="line">        <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;Failed to create file: %s.\n&quot;</span>, fileName);</span><br><span class="line">        <span class="built_in">exit</span>(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line">    outputToFile(buffer, count, fp);</span><br><span class="line">    </span><br><span class="line">    <span class="built_in">free</span>(buffer);</span><br><span class="line">    <span class="built_in">free</span>(line);</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;Sort phase done. %d tmp sorted files are produced.\n&quot;</span>, fileNum);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>The logic is not difficult. The function takes the input file descriptor as a parameter and reads each line(via the <code>getline</code> method) in a loop until reaches the end of the file. The numbers will be read into the memory buffer before hitting the memory limit. When the memory buffer is full(100000 bytes), the numbers are sorted with the function <code>mergeSort</code>. </p><p>The function <code>mergeSort</code> is defined inside the file <a href="https://github.com/baoqger/external-merge-sort/blob/multi-way-with-pass/internal_sort.c"><code>internal_sort.c</code></a>, which implements the classic internal <a href="https://en.wikipedia.org/wiki/Merge_sort"><code>merge sorting</code></a> algorithm. I will not cover it in this article, since you can find many documents about it online. If you don’t know about it, please spend some time learning about it. Of course, you can replace it with other sorting algorithms like <a href="https://en.wikipedia.org/wiki/Quicksort"><code>quick sort</code></a> too. I leave this for the readers. </p><p>After sorting, the numbers are saved in the temporary files in the directory of <code>./tmp/pass0</code>. The filename is just the run number. </p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * Output sorted record to given file(of)</span></span><br><span class="line"><span class="comment"> * */</span></span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">outputToFile</span><span class="params">(<span class="type">unsigned</span> <span class="type">int</span> *buffer, <span class="type">int</span> size, FILE *of)</span> &#123;</span><br><span class="line">    <span class="type">int</span> i;</span><br><span class="line">    <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; size; i++) &#123;</span><br><span class="line">        <span class="built_in">fprintf</span>(of, <span class="string">&quot;%u\n&quot;</span>, buffer[i]);</span><br><span class="line">    &#125;</span><br><span class="line">    fclose(of);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>We can verify the result of the sort phase as follows: </p><img src="/images/pass0.png" title="Random access machine model" width="600px" height="400px"><p>You can see each file contains up to <code>25000</code> (equal to <code>MEMORY_LIMIT/RECORD_SIZE</code>) numbers and 312 files are created in pass0. </p><p>Note that I will not examine the details about how to make a new directory and how to open a new file to read or write. You can learn such Linux file I/O concepts by yourself. </p><h5 id="Merge-phase"><a href="#Merge-phase" class="headerlink" title="Merge phase"></a>Merge phase</h5><p>The <code>exMerge</code> function controls the passes in the merge phase starting from <code>pass1</code>. </p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">void</span> <span class="title function_">exMerge</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="comment">/* some code omitted ... */</span></span><br><span class="line">    <span class="type">int</span> pass = <span class="number">1</span>;</span><br><span class="line">    <span class="keyword">while</span> (fileNum &gt; <span class="number">1</span>) &#123;</span><br><span class="line">        exMergeSort(pass, fileNum);</span><br><span class="line">        <span class="type">int</span> remainer = fileNum % ways;</span><br><span class="line">        fileNum = fileNum / ways;</span><br><span class="line">        <span class="keyword">if</span> (remainer &gt; <span class="number">0</span>) &#123;</span><br><span class="line">            fileNum++;</span><br><span class="line">        &#125; </span><br><span class="line">        pass++;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">/* some code omitted ... */</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>The variable <code>fileNum</code> stores the <code>run</code> number in each pass. And the variable <code>ways</code> denotes the number of multi-way. Thus, the <code>run</code> number of the next pass should be calculated as <code>fileNum / ways</code>.</p><p>The detailed merging logic is inside the function <code>exMergeSort</code>, which takes two parameters. <code>pass</code> means the current pass number(starting from 1), while <code>nums</code> means how many runs(or sub-files) in the last pass need to be merged. </p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">void</span> <span class="title function_">exMergeSort</span><span class="params">(<span class="type">int</span> pass, <span class="type">int</span> nums)</span> &#123;</span><br><span class="line">    <span class="comment">/* some code omitted ... */</span></span><br><span class="line">    <span class="type">int</span> inputFileNum = <span class="number">0</span>; </span><br><span class="line">    <span class="type">int</span> run = <span class="number">1</span>;</span><br><span class="line">    <span class="keyword">for</span> (; inputFileNum &lt; nums;) &#123; </span><br><span class="line">        </span><br><span class="line">        <span class="comment">// create the dir for current pass</span></span><br><span class="line">        <span class="keyword">if</span> (inputFileNum == <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="type">int</span> status;</span><br><span class="line">            <span class="type">char</span> dirName[<span class="number">20</span>];</span><br><span class="line">            <span class="built_in">sprintf</span>(dirName, <span class="string">&quot;./tmp/pass%d&quot;</span>, pass);</span><br><span class="line">            <span class="keyword">if</span> ((status = mkdir(dirName, S_IRWXU | S_IRWXU | S_IROTH | S_IXOTH)) == <span class="number">-1</span>) &#123;</span><br><span class="line">                <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;Failed to create tmp directory %s.\n&quot;</span>, dirName);</span><br><span class="line">                <span class="built_in">exit</span>(EXIT_FAILURE);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// open new file to merge in each run</span></span><br><span class="line">        FILE *fm; </span><br><span class="line">        <span class="type">char</span> mergedFileName[<span class="number">20</span>];</span><br><span class="line">        <span class="built_in">sprintf</span>(mergedFileName, <span class="string">&quot;./tmp/pass%d/%d.txt&quot;</span>, pass, run);</span><br><span class="line">        <span class="keyword">if</span> ((fm = fopen(mergedFileName, <span class="string">&quot;w+&quot;</span>)) == <span class="literal">NULL</span>) &#123;</span><br><span class="line">            <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;%s\n&quot;</span>, strerror(errno));</span><br><span class="line">            <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;merged file %s: can&#x27;t create or open.\n&quot;</span>, mergedFileName);</span><br><span class="line">        &#125;</span><br><span class="line">        run++;</span><br><span class="line">        <span class="comment">/* some code omitted ... */</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>The above code creates a temp directory for each pass and a temp file for each run. </p><p>Next, we create an array of the input files for each run. And the input file is inside the temp directory of the last pass. Each run merges multiple files in the <code>for</code> loop. The only trick logic here is that the remaining files in the last run may be less than the number of ways declared, we need to handle that properly (line 5 of the below code block).  </p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Rewind the sorted files in previous pass, each run merge way_numbers numbers of files</span></span><br><span class="line"><span class="comment">// Merge the sorted files with multi ways in N runs. </span></span><br><span class="line"><span class="comment">// In the first N - 1 runs, each run merge ways numbers of files</span></span><br><span class="line"><span class="comment">// In the last run, merge the remaining files. </span></span><br><span class="line"><span class="type">int</span> way_numbers = run * ways &lt;= nums ? ways : nums - inputFileNum;</span><br><span class="line">FILE *fiarr[way_numbers];</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; way_numbers; i++) &#123;</span><br><span class="line">   <span class="type">char</span> inputFileName[<span class="number">20</span>];</span><br><span class="line">   inputFileNum++; <span class="comment">// start from 0 to nums</span></span><br><span class="line">   <span class="built_in">sprintf</span>(inputFileName, <span class="string">&quot;./tmp/pass%d/%d.txt&quot;</span>, pass - <span class="number">1</span>, inputFileNum);</span><br><span class="line">   <span class="keyword">if</span> ((fiarr[i] = fopen(inputFileName, <span class="string">&quot;r&quot;</span>)) == <span class="literal">NULL</span>) &#123;</span><br><span class="line">        <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;%s\n&quot;</span>, strerror(errno));</span><br><span class="line">        <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;input file %s: can&#x27;t create or open.\n&quot;</span>, inputFileName);</span><br><span class="line">   &#125;</span><br><span class="line">   rewind(fiarr[i]);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Next, we need to read one number from every input file until only one file is not run out. Find the smallest one and save it in the temp output run file. And for the last remaining file, remember to put the rest numbers into the output file too.  </p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// get and compare records until files runs out of records</span></span><br><span class="line"><span class="type">char</span> *records[way_numbers]; </span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; way_numbers; i++) &#123;</span><br><span class="line">    records[i] = getRecord(fiarr[i]);</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// loop until only one file is not run-out</span></span><br><span class="line"><span class="keyword">while</span>(validateRecords(records, way_numbers )) &#123;</span><br><span class="line">    <span class="type">int</span> index = getMinRecordIndex(records, way_numbers);</span><br><span class="line">    <span class="built_in">fprintf</span>(fm, <span class="string">&quot;%s&quot;</span>, records[index]); <span class="comment">// print record to new merged file</span></span><br><span class="line">    <span class="built_in">free</span>(records[index]); <span class="comment">// free the memory allocated by getline in getRecord function</span></span><br><span class="line">    records[index] = getRecord(fiarr[index]); <span class="comment">// Get new record from the file</span></span><br><span class="line">&#125;</span><br><span class="line">       </span><br><span class="line"><span class="comment">// put the rest record in the last remaining file into new file </span></span><br><span class="line"><span class="type">int</span> lastIndex = getLastRemainRecordIndex(records, way_numbers);</span><br><span class="line"><span class="keyword">while</span>(records[lastIndex]) &#123;</span><br><span class="line">    <span class="built_in">fprintf</span>(fm, <span class="string">&quot;%s&quot;</span>, records[lastIndex]);</span><br><span class="line">    <span class="built_in">free</span>(records[lastIndex]);</span><br><span class="line">    records[lastIndex] = getRecord(fiarr[lastIndex]);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>The above code bock utilizes several methods like <code>getRecord</code>, <code>validateRecords</code>, <code>getMinRecordIndex</code> and <code>getLastRemainRecordIndex</code> as follows, and these functions are easy to understand. </p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * Returns a copy of the record</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * */</span></span><br><span class="line"><span class="type">char</span>* <span class="title function_">getRecord</span><span class="params">(FILE *ifp)</span> &#123;</span><br><span class="line">    <span class="type">char</span> *line = <span class="literal">NULL</span>;</span><br><span class="line">    <span class="type">size_t</span> len = <span class="number">0</span>;</span><br><span class="line">    <span class="type">ssize_t</span> nread;</span><br><span class="line">    <span class="keyword">while</span> ((nread = getline(&amp;line, &amp;len, ifp)) != <span class="number">-1</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> line;       </span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * Validate whether at least two records are non-zero</span></span><br><span class="line"><span class="comment"> * */</span></span><br><span class="line"><span class="type">bool</span> <span class="title function_">validateRecords</span><span class="params">(<span class="type">char</span> **records, <span class="type">int</span> size)</span> &#123;</span><br><span class="line">    <span class="type">int</span> count = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; size; i++) &#123;</span><br><span class="line">        <span class="keyword">if</span> (records[i] != <span class="literal">NULL</span>) &#123;</span><br><span class="line">            count++;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> count &gt;= <span class="number">2</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * Get the min valid record&#x27;s index</span></span><br><span class="line"><span class="comment"> * */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">getMinRecordIndex</span><span class="params">(<span class="type">char</span> **records, <span class="type">int</span> size)</span> &#123;</span><br><span class="line">    <span class="type">int</span> index = <span class="number">0</span>;</span><br><span class="line">    <span class="type">unsigned</span> <span class="type">int</span> min = (<span class="type">int</span>)INFINITY;</span><br><span class="line">    <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; size; i++) &#123;</span><br><span class="line">        <span class="keyword">if</span> (records[i] == <span class="literal">NULL</span>) &#123; <span class="comment">// pass invalid run-out record files</span></span><br><span class="line">            <span class="keyword">continue</span>;</span><br><span class="line">        &#125; </span><br><span class="line">        <span class="keyword">if</span> (strtoul(records[i], <span class="literal">NULL</span>, <span class="number">10</span>) &lt; min) &#123;</span><br><span class="line">            min = strtoul(records[i], <span class="literal">NULL</span>, <span class="number">10</span>);</span><br><span class="line">            index = i;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> index;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * Get the last remainer of the records</span></span><br><span class="line"><span class="comment"> * */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">getLastRemainRecordIndex</span><span class="params">(<span class="type">char</span> **records, <span class="type">int</span> size)</span> &#123;</span><br><span class="line">    <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; size; i++) &#123;</span><br><span class="line">        <span class="keyword">if</span> (records[i] != <span class="literal">NULL</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> i;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>In detail, you can refer to the source code of this <a href="https://github.com/baoqger/external-merge-sort/blob/multi-way-with-pass/main.c">github repo</a>. Next, let’s evaluate the performance of this algorithm by tuning the number of ways for merging. </p><h3 id="Performance-Evaluation"><a href="#Performance-Evaluation" class="headerlink" title="Performance Evaluation"></a>Performance Evaluation</h3><p>We’ll use the Linux <code>time</code> utility to measure the running time of this algorithm. </p><p>The result of two-way mergesort is: </p><img src="/images/two-way-merge.png" title="two way merge sort" width="600px" height="400px"><p>while six-way mergesort can complete with a shorter runtime. </p><img src="/images/multi-way-merge.png" title="two way merge sort" width="600px" height="400px">]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;Introduction&quot;&gt;&lt;a href=&quot;#Introduction&quot; class=&quot;headerlink&quot; title=&quot;Introduction&quot;&gt;&lt;/a&gt;Introduction&lt;/h3&gt;&lt;p&gt;In this last &lt;a href=&quot;https://</summary>
      
    
    
    
    
    <category term="algorithm, external, disk" scheme="https://baoqger.github.io/tags/algorithm-external-disk/"/>
    
  </entry>
  
  <entry>
    <title>External Mergesort: part one</title>
    <link href="https://baoqger.github.io/2022/11/02/external-sorting-one/"/>
    <id>https://baoqger.github.io/2022/11/02/external-sorting-one/</id>
    <published>2022-11-02T08:44:29.000Z</published>
    <updated>2024-08-30T08:46:20.311Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Introduction"><a href="#Introduction" class="headerlink" title="Introduction"></a>Introduction</h3><p>This article will examine one interesting question which I came across when reading the book <strong><em>Programming Pearls</em></strong>. This question simply goes like this: <code>How to sort a large disk file? The disk file has so much data that it cannot all fit into the main memory.</code> I considered this <code>algorithm</code> question for a while; but noticed that all the classic sorting algorithms, like <a href="https://en.wikipedia.org/wiki/Quicksort"><code>Quick sort</code></a> and <a href="https://en.wikipedia.org/wiki/Merge_sort"><code>merge sort</code></a>, can’t solve it easily. Then I did some research about it, and I will share what I learned in this article. I believe you can solve this problem as well, after reading this article.</p><h3 id="Background-of-External-Algorithm"><a href="#Background-of-External-Algorithm" class="headerlink" title="Background of External Algorithm"></a>Background of External Algorithm</h3><p>Traditionally, computer scientists analyze the running time of an algorithm by counting the number of executed instructions, which is usually expressed as a function of the input size n, like the well-known <a href="https://en.wikipedia.org/wiki/Big_O_notation"><code>Big O notation</code></a>. This kind of algorithm complexity analysis is based on the <code>Random access machine(RAM)</code> model, which defines the following assumptions:</p><ul><li>A machine with an unbounded amount of available memory;</li><li>Any desired memory location can be accessed in unit time;</li><li>Every instruction takes the same amount of time. </li></ul><img src="/images/RAM-Model.png" title="Random access machine model" width="300px" height="200px"><p>This model works well when the amount of memory that the algorithm needs to use is smaller than the amount of memory in the computer running the code. </p><p>But in the real world, some applications need to process data that are too large to fit into a computer’s main memory at once. And the algorithms used to solve such problems are called <code>external memory algorithms</code> or <code>disk-based algorithms</code>; since the input data are stored on an <a href="https://en.wikipedia.org/wiki/External_storage"><code>external memory</code> storage device</a>.</p><p>Instead of the <code>RAM</code> model, the <code>external memory algorithm</code> is analyzed based on the <code>external memory model</code>. The model consists of a CPU processor with an internal memory of bounded size, connected to an unbounded external memory. One I/O operation consists of moving a block of contiguous elements from external to internal memory(this is called <a href="https://en.wikipedia.org/wiki/Page_cache"><code>page cache</code></a> and is managed by the kernel.). </p><img src="/images/external-model.png" title="external memory model" width="400px" height="300px"><p>Compared with the main memory, the access speed of external memory is slower by <a href="https://en.wikipedia.org/wiki/Memory_hierarchy">several orders of magnitude</a>, even though modern storage techniques such as <a href="https://en.wikipedia.org/wiki/Solid-state_drive"><code>SSD</code></a> are already adopted. Thus, for external algorithms, the bottleneck of the performance is <code>disk IO</code> speed instead of the CPU cycles. </p><p>In this section, we examined the computational model of the external memory algorithms. Next, let’s review one typical type of external memory algorithm: external sorting. </p><h3 id="External-Mergesort"><a href="#External-Mergesort" class="headerlink" title="External Mergesort"></a>External Mergesort</h3><p>Similar to the traditional internal sorting algorithms, several different solutions are available for external sorting. In this article, I will focus on <code>external mergesort</code>.</p><p>External mergesort is a straightforward generalization of internal mergesort. The algorithm starts by repeatedly loading M input items into the memory(since the memory buffer size is limited, can only store M input items at once), sorting them, and writing them back out to disk. This step divides the input file into some(or many, if the input file is very large) sorted runs, each with M items sorted. Then the algorithm repeatedly merges multiple sorted runs, until only a single sorted run containing all the input data remains. </p><p>Let’s use the following example model to analyze this algorithm. First of all, assume the memory buffer is limited, and the size is one <code>page</code>. And the input file size is 8 <code>pages</code>. External mergesort can be divided into two phases: <code>sort phase</code> and <code>merge phase</code>.  </p><img src="/images/external-mergesort.png" title="external mergesort" width="800px" height="600px"><p><strong><em>Sort phase</em></strong>:</p><ul><li>Divide the entire input file into 8 groups, each group size is one page(memory buffer capacity).</li><li>Load each page into the memory, sort the items in the memory buffer(with an internal sorting algorithm), and save the sorted items in a temporary sub-file. Each sub-file is called a <code>run</code>.</li></ul><p>At the end of the sort phase, 8 temporary sorted 1-page runs will be created. This step can be marked as <strong><em>pass 0</em></strong>.</p><p><strong><em>Merge phase</em></strong>: </p><p>The 8 sorted runs in pass 0 will be merged into a single sorted file with 3 more passes.</p><ul><li>pass 1: Perform 4 runs for the merge. <ul><li>Run 1: Merge the first two small 1-page runs into a big 2-page run. This merging step goes as follows: <ul><li>Read the first two sorted sub-files (one item from each file).</li><li>Find the smaller item, output it in the new sub-file, and the appropriate input sub-file is advanced. Repeat this cycle until the input sub-file is completed. <strong>This routine’s logic is the same as the internal mergesort algorithm.</strong></li></ul></li><li>Run 2: Merge the next two 1-page runs into a 2-page run. </li><li>Run 3 and 4: follow the same process.   </li><li>At the end of <strong><em>pass 1</em></strong>, 4 temporary sorted 2-page runs will be created. </li></ul></li><li>pass 2: Perform 2 runs for the merge. <ul><li>At the end of <strong><em>pass 2</em></strong>, 2 temporary sorted 4-page runs will be created. </li></ul></li><li>pass 3: Perform 1 run for the merge. <ul><li>At the end of <strong><em>pass 3</em></strong>, the final 8-page run containing all the sorted items will be created.</li></ul></li></ul><p>Note: the above process may seem complicated at the first sight, but the logic is nearly the same as the internal merge sort. The only difference is internal merging is based on memory buffers, while external merging is based on disk files, and needs reading the item from disk to memory.</p><p>Since we keep merging two small sub-files into a big one with doubled size, the above algorithm can be called <code>two-way</code> external merge sorting. We can generalize the idea to <code>multi-way</code> external merge sorting, which merges M runs into one.  </p><p>Next, let’s analyze its complexity. Suppose the input file has <code>N</code> items and each page consists of <code>B</code> items. And <code>M</code> denotes the number of ways used in the merge phase, thus the number of passes should be: <b>log<sub>M</sub>(N/B) + 1</b>, where plus one means the first pass in the sort phase. And each pass, each item is read and written once from and to the disk file. So the total number of disk I/O is: <b>2N*(log<sub>M</sub>(N/B) + 1)</b></p><h3 id="Summary"><a href="#Summary" class="headerlink" title="Summary"></a>Summary</h3><p>In this article, we examined the abstract computational model of the external memory algorithm and analyzed the details of the external mergesort algorithm. Next article, let’s implement the code and evaluate the performance. </p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;Introduction&quot;&gt;&lt;a href=&quot;#Introduction&quot; class=&quot;headerlink&quot; title=&quot;Introduction&quot;&gt;&lt;/a&gt;Introduction&lt;/h3&gt;&lt;p&gt;This article will examine one </summary>
      
    
    
    
    
    <category term="algorithm, external, disk" scheme="https://baoqger.github.io/tags/algorithm-external-disk/"/>
    
  </entry>
  
  <entry>
    <title>Understand userland heap memory allocation: part three - free chunk</title>
    <link href="https://baoqger.github.io/2022/10/10/userland-memory-allocation-three/"/>
    <id>https://baoqger.github.io/2022/10/10/userland-memory-allocation-three/</id>
    <published>2022-10-10T08:27:46.000Z</published>
    <updated>2022-10-12T05:20:01.782Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Introduction"><a href="#Introduction" class="headerlink" title="Introduction"></a>Introduction</h3><p>In the last <a href="https://organicprogrammer.com/2022/09/08/userland-memory-allocation-two/">article</a>,  we investigated how the allocated chunks are aligned and stored in the heap. This article continues to examine how to free a chunk of memory and how the freed chunks are stored in the heap. </p><h3 id="Hands-on-demo"><a href="#Hands-on-demo" class="headerlink" title="Hands-on demo"></a>Hands-on demo</h3><p>Let’s continue debugging the demo code shown in the last article: </p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;string.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;malloc.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span> &#123;</span><br><span class="line">    <span class="type">char</span> *a = (<span class="type">char</span>*)<span class="built_in">malloc</span>(<span class="number">100</span>);</span><br><span class="line">    <span class="built_in">strcpy</span>(a, <span class="string">&quot;AAAABBBBCCCCDDDD&quot;</span>);</span><br><span class="line">    <span class="built_in">free</span>(a);</span><br><span class="line">    <span class="type">char</span> *b = (<span class="type">char</span>*)<span class="built_in">malloc</span>(<span class="number">100</span>);</span><br><span class="line">    <span class="built_in">free</span>(b);</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Previously, we allocated a chunk of memory and put data in it. The next line will free this chunk. Before we run the instruction and show the demo result, let’s discuss the theory first. </p><p>The freed chunk will not be returned to the kernel immediately after the <code>free</code> is called. Instead, the heap <code>allocator</code> keeps track of the freed chunks in a <a href="https://en.wikipedia.org/wiki/Linked_list"><code>linked list</code></a> data structure. So the freed chunks in the linked list can be reused when the application requests new allocations again. This can decrease the performance overhead by avoiding too many system calls. </p><p>The <code>allocator</code> could store all the freed chunks together in a long linked list, this would work but the performance would be slow. Instead, the <code>glibc</code> maintains a series of freed linked lists called <code>bins</code>, which can speed up the allocations and frees. We will examine how <code>bins</code> work later.  </p><p>It is worth noting that each free chunk needs to store <code>pointers</code> to other chunks to form the linked list. That’s what we discussed in the last section, there’re two points in the <code>malloc_chunk</code> structure: <code>fd</code> and <code>bk</code>, right? Since the <code>user data</code> region of the freed chunk is free for use by the <code>allocator</code>, so it repurposes the <code>user data</code> region as the place to store the pointer. </p><p>Based on the above description, the following picture illustrates the exact structure of a freed chunk:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">chunk-&gt; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+</span><br><span class="line">            |             Size of previous chunk, if freed                  | </span><br><span class="line">            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+</span><br><span class="line">            |             Size of chunk, in bytes                     |A|M|P|</span><br><span class="line">      mem-&gt; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+</span><br><span class="line">            |             pointer to the next freed chunk                   |</span><br><span class="line">            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+</span><br><span class="line">            |             pointer to the previous freed chunk               |</span><br><span class="line">            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+</span><br><span class="line">            .                                                               .</span><br><span class="line">            .                           ......                              .</span><br><span class="line">nextchunk-&gt; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+</span><br><span class="line">            |             Size of chunk                                     |</span><br><span class="line">            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>Now step over one line in <code>gdb</code> and check chunks in the heap as follows: </p><img src="/images/heap-demo-heap-free.png" title="pwndbg 1" width="300px" height="200px"><p>You can see the changes: the allocated chunk is marked as a <code>Free chunk (tcache)</code> and pointer <code>fd</code> is set(which indicates this freed chunk is inserted into a linked list). </p><p>The <code>tcache</code> is one kind of <code>bins</code> provided by <code>glibc</code>. The gdb <code>pwndbg</code> plugin allows you to check the content of <code>bins</code> by running command <code>bins</code> as follows:</p><img src="/images/heap-demo-bins.png" title="pwndbg 2" width="300px" height="200px"><p>Note that the freed chunk(at 0x5555555592a0) is inserted into <code>tcache bins</code> as the liked list header.  </p><p>Note that there 5 types of bins: <code>small bins</code>, <code>large bins</code>, <code>unsorted bins</code>, <code>fast bins</code> and <code>tcache bins</code>. If you don’t know, don’t worry I will examine them in the following section. </p><p>According to the definition, after the second <code>malloc(100)</code> is called, the <code>allocator</code> should reuse the freed chunk in the <code>bins</code>. The following image can prove this:  </p><img src="/images/heap-demo-reuse-100.png" title="pwndbg 3" width="300px" height="200px"><p>The freed chunk at 0x555555559290 is in use again and all <code>bins</code> are empty after the chunk is removed from the linked list. All right! </p><h3 id="Recycling-memory-with-bins"><a href="#Recycling-memory-with-bins" class="headerlink" title="Recycling memory with bins"></a>Recycling memory with bins</h3><p>Next, I want to spend a little bit of time examining why we need <code>bins</code> and how <code>bins</code> optimize chunk allocation and free. </p><p>If the <code>allocator</code> keeps track of all the freed chunks in a long linked list. The time complexity is <code>O(N)</code> for the allocator to find a freed chunk with fit size by traversing from the head to the tail. If the <code>allocator</code> wants to keep the chunks in order, then at least  <code>O(NlogN)</code> time is needed to sort the list by size. This slow process would have a bad impact on the overall performance of programs. That’s the reason why we need bins to optimize this process. In summary, the optimization is done on the following two aspects:</p><ul><li>High-performance data structure</li><li>Per-thread cache without lock contention</li></ul><h4 id="High-performance-data-structure"><a href="#High-performance-data-structure" class="headerlink" title="High-performance data structure"></a>High-performance data structure</h4><p>Take the <code>small bins</code> and <a href="https://sourceware.org/git/gitweb.cgi?p=glibc.git;a=blob;f=malloc/malloc.c;h=6e766d11bc85b6480fa5c9f2a76559f8acf9deb5;hb=HEAD#l1686"><code>large bins</code></a> as a reference, they are defined as follows:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> NBINS             128</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span> <span class="title">malloc_chunk</span>* <span class="title">mchunkptr</span>;</span></span><br><span class="line"></span><br><span class="line">mchunkptr bins[NBINS * <span class="number">2</span> - <span class="number">2</span>];</span><br></pre></td></tr></table></figure><p>They are defined together in an array of linked lists and each linked list(or bin) stores chunks that are all <code>the same fixed size</code>. From <code>bins[2] to bins[63]</code> are the <code>small bins</code>, which track freed chunks less than 1024 bytes while the <code>large bins</code> are for bigger chunks.  <code>small bins</code> and <code>large bins</code> can be represented as a <a href="https://en.wikipedia.org/wiki/Doubly_linked_list"><code>double-linked list</code></a> shown below: </p><img src="/images/small-bins-index.png" title="pwndbg 4" width="600px" height="400px"><p>The <code>glibc</code> provides a <a href="https://sourceware.org/git/gitweb.cgi?p=glibc.git;a=blob;f=malloc/malloc.c;h=6e766d11bc85b6480fa5c9f2a76559f8acf9deb5;hb=HEAD#l1686">function</a> to calculate the <code>index</code> of the corresponding small(or large) bin in the array based on the requested <code>size</code>. Since the <code>index</code> operation of the <a href="https://en.wikipedia.org/wiki/Array_(data_structure)">array</a> is in <code>O(1)</code> time. Moreover, each bin contains chunks of the same size, so it can also take <code>O(1)</code> time to insert or remove one chunk into or from the list. As a result, the entire allocation time is optimized to  <code>O(1)</code>. </p><p><code>bins</code> are <code>LIFO(Last In First Out)</code> data structure. The insert and remove operations can be illustrated as follows: </p><img src="/images/LIFO-linked-list.png" title="pwndbg 4" width="600px" height="400px"><p>Moreover, for <code>small bins</code> and <code>large bins</code>, if the neighbors of the current chunk are free, they are <code>merged</code> into a larger one. That’s the reason we need a <code>double-linked list</code> to allow running fast traverse both forward and backward. </p><p>Unlike <code>small bins</code> and <code>large bins</code>, <code>fast bins</code> and <code>tcache bins</code> chunks are <code>never merged</code> with their neighbors. In practice, the glibc <code>allocator</code> doesn’t set the <code>P</code> special flag at the start of the next chunk. This can avoid the overhead of merging chunks so that the freed chunk can be immediately reused if the same size chunk is requested. Moreover, since <code>fast bins</code> and <code>tcache bins</code> are never merged, they are implemented as a <a href="https://sourceware.org/git/gitweb.cgi?p=glibc.git;a=blob;f=malloc/malloc.c;h=6e766d11bc85b6480fa5c9f2a76559f8acf9deb5;hb=HEAD#l1678"><code>single-linked list</code></a>.</p><p>This can be proved by running the second <code>free</code> method in the demo code and checking the chunks in the heap as follows: </p><img src="/images/heap-demo-heap-free.png" title="pwndbg 1" width="300px" height="200px"><p>First, the <code>top</code> chunk’s size is still <code>0x20d01</code> rather than <code>0x20d00</code>, which indicates the <code>P</code> bit is equal to 1. Second, the <code>Free chunk</code> only has one pointer: <code>fd</code>. If it’s in a double-linked list, both <code>fd</code> and <code>bk</code> should point to a valid address. </p><h4 id="Per-thread-cache-without-lock-contention"><a href="#Per-thread-cache-without-lock-contention" class="headerlink" title="Per-thread cache without lock contention"></a>Per-thread cache without lock contention</h4><p>The letter <code>t</code> in <code>tcache bins</code> represents the <code>thread</code>, which is used to optimize the performance of multi-thread programs. In multi-thread programming, the most common way solution to prevent the <a href="https://en.wikipedia.org/wiki/Race_condition"><code>race condition</code></a> issue is using the <a href="https://en.wikipedia.org/wiki/Lock_(computer_science)"><code>lock or mutex</code></a>. Similarly, The <code>glibc</code> maintains a <code>lock</code> in the data structure for each heap. But this design comes with a performance cost: <a href="https://en.wikipedia.org/wiki/Lock_(computer_science)#:~:text=lock%20contention%3A%20this%20occurs%20whenever,lock%20held%20by%20the%20other."><code>lock contention</code></a>, which happens when one thread attempts to acquire a lock held by another thread. This means the thread can’t do any tasks. </p><p><code>tcache bins</code> are per-thread bins. This means if the thread has a chunk on its <code>tcache bins</code>, it can serve the allocation without waiting for the heap lock!  </p><h3 id="Summary"><a href="#Summary" class="headerlink" title="Summary"></a>Summary</h3><p>In this article, we examined how the userland heap allocaor works by debugging into the heap memory with gdb. The discussion is fully based on the <code>glibc</code> implementation. The design and behavior of the <code>glibc</code> heap allocator are complex but interesting, what we covered here just touches the tip of the iceberg. You can explore more by yourself. </p><p>Moreover, I plan to write a simple version of a heap allocator for learning and teaching purpose. Please keep watching my blog!</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;Introduction&quot;&gt;&lt;a href=&quot;#Introduction&quot; class=&quot;headerlink&quot; title=&quot;Introduction&quot;&gt;&lt;/a&gt;Introduction&lt;/h3&gt;&lt;p&gt;In the last &lt;a href=&quot;https://o</summary>
      
    
    
    
    
    <category term="Linux, memory layout, heap, gdb" scheme="https://baoqger.github.io/tags/Linux-memory-layout-heap-gdb/"/>
    
  </entry>
  
  <entry>
    <title>Understand userland heap memory allocation: part two - allocate chunk</title>
    <link href="https://baoqger.github.io/2022/09/08/userland-memory-allocation-two/"/>
    <id>https://baoqger.github.io/2022/09/08/userland-memory-allocation-two/</id>
    <published>2022-09-08T07:43:57.000Z</published>
    <updated>2022-10-11T14:20:13.307Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Introduction"><a href="#Introduction" class="headerlink" title="Introduction"></a>Introduction</h3><p>The previous <a href="https://organicprogrammer.com/2022/08/05/userland-memory-allocation-one/">article</a> gave a general overview of memory management. The story goes on. In this section, let’s break into the heap memory to see how it works basically. </p><h3 id="Memory-allocator"><a href="#Memory-allocator" class="headerlink" title="Memory allocator"></a>Memory allocator</h3><p>We need to first understand some terminology in the memory management field: </p><ul><li><strong>mutator</strong>: the program that modifies the objects in the heap, which is simply the user application. But I will use the term <code>mutator</code> in this article. </li><li><strong>allocator</strong>: the <code>mutator</code> doesn’t allocate memory by itself, it delegates this generic job to the <code>allocator</code>. At the code level, the <code>allocator</code> is generally implemented as a library. The detailed allocation behavior is fully determined by the implementations, in this article I will focus on the memory allocator in the library of <code>glibc</code>.  </li></ul><p>The relationship between the <code>mutator</code> and <code>allocator</code> is shown in the following diagram: </p><img src="/images/memo-allocator.png" title="memory allocator" width="400px" height="300px"><p>There is a third component in the memory management field: the <code>garbage collector(GC)</code>. <code>GC</code> reclaims memories automatically. Since this article is talking about manual heap memory allocation in system programming, we will ignore <code>GC</code> for now. <code>GC</code> is a very interesting technical challenge, I will examine it in the future. Please keep watching my blog!</p><h3 id="Hands-on-demo"><a href="#Hands-on-demo" class="headerlink" title="Hands-on demo"></a>Hands-on demo</h3><p>We will use <code>gdb</code> and <code>pwndbg</code>(which is a gdb <a href="https://github.com/pwndbg/pwndbg">plugin</a>) and break into the heap memory to see how it works. The <code>gdb</code> provides the functionality to extend it via <code>Python</code> plugins. <code>pwndbg</code> is the most widely used. </p><p>The demo code is as follows: </p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;string.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;malloc.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span> &#123;</span><br><span class="line">    <span class="type">char</span> *a = (<span class="type">char</span>*)<span class="built_in">malloc</span>(<span class="number">100</span>);</span><br><span class="line">    <span class="built_in">strcpy</span>(a, <span class="string">&quot;AAAABBBBCCCCDDDD&quot;</span>);</span><br><span class="line">    <span class="built_in">free</span>(a);</span><br><span class="line">    <span class="type">char</span> *b = (<span class="type">char</span>*)<span class="built_in">malloc</span>(<span class="number">100</span>);</span><br><span class="line">    <span class="built_in">free</span>(b);</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>The demo code above just allocates some memory, set the content of the memory and releases it later. And then allocate other chunks of memory again. Very simple, all right? </p><p>First, set a <code>breakpoint</code> at line 7(the first <code>malloc</code> call) and run the program in <code>gdb</code>. Then run <code>vmmap</code> command from <code>pwndbg</code>, which can get the process memory layout as follows: </p><img src="/images/heap-demo-vmmap-no-heap.png" title="pwndbg 1" width="800px" height="600px"><p>Note that there is no <code>heap</code> segment yet before the first <code>malloc</code> call is made. After step over one line in <code>gdb</code>, check the layout again: </p><img src="/images/heap-demo-vmmap-has-heap.png" title="pwndbg 2" width="800px" height="600px"><p>Now the <code>heap</code> segment is created with the size of <code>132KB</code>(21000 in hexadecimal). As described above, the kernel maps 132KB of physical memory to this process’s virtual memory and marks this 132KB block of physical memory as used to isolate other processes. This mapping routine is done via system calls like <code>brk</code>, <code>sbrk</code> and <code>mmap</code>. Please investigate these system calls yourself.</p><p>132KB is much bigger than the 100B(the size passed to <code>malloc</code>). This behavior can answer one question at the beginning of this article. The system calls aren’t necessary to be triggered each time when <code>malloc</code> is called. This design is aimed to decrease performance overhead. Now the 132KB heap memory is maintained by the <code>allocator</code>. Next time the application calls <code>malloc</code> again, the <code>allocator</code> will allocate memory for it. </p><p>Next, step one more line in <code>gdb</code> to assign value(“AAAABBBBCCCCDDDD”) to the allocated block. Let’s check the content of this 132KB heap segment with <code>heap</code> command as follows:</p><img src="/images/heap-demo-heap.png" title="pwndbg 3" width="300px" height="200px"><p>There are 3 chunks. Let’s examine these chunks one by one. </p><p>The <code>top</code> chunk contains all the remaining memories which have not been allocated yet. In our case, the kernel maps 132KB of physical memory to this process. And 100B memory is allocated by calling <code>malloc(100)</code>, so the remaining memories are in the <code>top</code> chunk. The <code>top</code> chunk stays on the border of the heap segment, and it can grow and shrink as the process allocates more memory or release unused memory. </p><p>Then let’s look at the chunk with the size of 0x291. The <code>allocator</code> uses this chunk to store heap management structures. It is not important for our analysis, just skip it. </p><p>What we care about is the chunk in the middle with a size of <code>0x71</code>. It should be the block we requested and contains the string “AAAABBBBCCCCDDDD”. We can verify this point by checking its content:</p><img src="/images/heap-demo-display.png" title="pwndbg 3" width="600px" height="400px"><p>gdb’s <a href="https://visualgdb.com/gdbreference/commands/x"><code>x</code></a> command can display the memory contents at a given address using the specified format. <code>x/40wx 0x555555559290</code> prints 40 words(each word is 32 bits) of memories starting from 0x555555559290 in the hexadecimal format.</p><p>We can see that the string “AAAABBBBCCCCDDDD” is there. So our guess is correct. But the question is why the size of this chunk is <code>0x71</code>. To understand this, we need to first analyze how the <code>allocator</code> stores <code>chunk</code>. A chunk of memory is represented by the following structure: </p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">malloc_chunk</span> &#123;</span></span><br><span class="line">  INTERNAL_SIZE_T      prev_size;  <span class="comment">/* Size of previous chunk (only if free).  */</span></span><br><span class="line">  INTERNAL_SIZE_T      size;       <span class="comment">/* Size in bytes, including overhead. */</span></span><br><span class="line">  <span class="class"><span class="keyword">struct</span> <span class="title">malloc_chunk</span>* <span class="title">fd</span>;</span>                <span class="comment">/* double links -- used only if free. */</span></span><br><span class="line">  <span class="class"><span class="keyword">struct</span> <span class="title">malloc_chunk</span>* <span class="title">bk</span>;</span>                <span class="comment">/* double links -- used only if free. */</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span> <span class="title">malloc_chunk</span>* <span class="title">mchunkptr</span>;</span></span><br></pre></td></tr></table></figure><ul><li><code>prev_size</code>: the size of the previous chunk only when the previous chunk is free, otherwise when the previous chunk is in use it stores the user data of the previous chunk. </li><li><code>size</code>: the size of the current chunk.</li><li><code>fd</code>: pointer to the next free chunk only when the current chunk is free, otherwise when the current chunk is in use it stores the user data.</li><li><code>bk</code>: pointer to the previous free chunk. Behaves in the same way as pointer <code>fd</code>.  </li></ul><p>Based on the above description, the following picture illustrates the exact structure of an allocated <code>chunk</code>: </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">    chunk-&gt; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+</span><br><span class="line">            |             Size of previous chunk, if freed                  | </span><br><span class="line">            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+</span><br><span class="line">            |             Size of chunk, in bytes                     |A|M|P|</span><br><span class="line">      mem-&gt; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+</span><br><span class="line">            |             User data starts here...                          .</span><br><span class="line">            .                                                               .</span><br><span class="line">            .                                                               .</span><br><span class="line">            .                                                               |</span><br><span class="line">nextchunk-&gt; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+</span><br><span class="line">            |             Size of chunk                                     |</span><br><span class="line">            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+</span><br></pre></td></tr></table></figure><ul><li>chunk: indicates the real starting address of the object in the heap memory. </li><li>mem: indicates the returned address by <code>malloc</code>. </li></ul><p>The memory in between is reserved for the metadata mentioned above: <code>prev_size</code> and <code>size</code>. On a 64-bit system, they’re (type of <code>INTERNAL_SIZE_T</code>) 8 bytes in length. </p><p>For the <code>size</code> field, it is worth noting: </p><ul><li>It includes both the size of metadata and the size of the actual user data.</li><li>It is usually aligned to a multiple of 16 bytes. You can investigate the <a href="https://stackoverflow.com/questions/381244/purpose-of-memory-alignment">purpose of memory alignment</a> by yourself.</li><li>It contains three special flags(<code>A|M|P</code>) at the three least significant bits. We can ignore the other two bits for now, but the last bit indicates whether the previous chunk is in use(set to 1) or not(set to 0). </li></ul><p>According to this, let’s review the content of this chunk again:</p><img src="/images/heap-demo-display-mark.png" title="pwndbg 3" width="600px" height="400px"><p>I add marks on the image to help you understand. Let’s do some simple calculations. <code>100 + 8 = 108</code>, 100 is the size of memory we requested, 8 is the size of metadata(for <code>size</code> field). Then <code>108</code> is aligned to <code>112</code> as a multiple of 16 bytes. Finally, since the special flag P is set to 1, then we get <code>112 + 1 = 113(0x71)</code>(that’s the reason why the size is <code>0x71</code> instead of <code>0x70</code>).  </p><p>In this section, we break into the heap segment and see how an allocated chunk works. Next, we’ll check how to free a chunk. </p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;Introduction&quot;&gt;&lt;a href=&quot;#Introduction&quot; class=&quot;headerlink&quot; title=&quot;Introduction&quot;&gt;&lt;/a&gt;Introduction&lt;/h3&gt;&lt;p&gt;The previous &lt;a href=&quot;https://</summary>
      
    
    
    
    
    <category term="Linux, memory layout, heap, gdb" scheme="https://baoqger.github.io/tags/Linux-memory-layout-heap-gdb/"/>
    
  </entry>
  
  <entry>
    <title>Understand userland heap memory allocation: part one - overview</title>
    <link href="https://baoqger.github.io/2022/08/05/userland-memory-allocation-one/"/>
    <id>https://baoqger.github.io/2022/08/05/userland-memory-allocation-one/</id>
    <published>2022-08-05T12:31:11.000Z</published>
    <updated>2022-10-08T06:58:08.764Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Introduction"><a href="#Introduction" class="headerlink" title="Introduction"></a>Introduction</h3><p>In my eyes, compared with developing applications with high-level programming languages, one of the biggest differences for system programming with low-level languages like C and C++, is you have to manage the memory by yourself. So you call APIs like <code>malloc</code>, and <code>free</code> to allocate the memory based on your need and release the memory when the resource is no longer needed. It is not only one of the most frequent causes of <a href="https://developers.redhat.com/articles/2021/11/01/debug-memory-errors-valgrind-and-gdb">bugs</a> in system programming; but also can lead to many <a href="https://en.wikipedia.org/wiki/Memory_safety">security issues</a>. </p><p>It’s not difficult to understand the correct usage of APIs like <code>malloc</code>, and <code>free</code>. But have you ever wondered how they work, for example: </p><ul><li>When you call <code>malloc</code>, does it trigger system calls and delegate the task to the kernel or there are some other mechanisms? </li><li>When you call <code>malloc(10)</code> and try to allocate 10 bytes of heap memory, how many bytes of memory do you get? 10 bytes or more?</li><li>When the memory is allocated, where exactly the heap objects are located?</li><li>When you call <code>free</code>, is the memory directly returned to the kernel? </li></ul><p>This article will try to answer these questions. </p><p>Note that memory is a super complex topic, so I can’t cover everything about it in one article (In fact, what is covered in this article is very limited). This article will focus on <code>userland memory(heap) allocation</code>. </p><h3 id="Process-memory-management-overview"><a href="#Process-memory-management-overview" class="headerlink" title="Process memory management overview"></a>Process memory management overview</h3><h4 id="Process-virtual-memory"><a href="#Process-virtual-memory" class="headerlink" title="Process virtual memory"></a>Process virtual memory</h4><p>Every time we start a program, a memory area for that program is reserved, and that’s <code>process virtual memory</code> as shown in the following image: </p><img src="/images/process-memory-address.png" title="process virtual memory" width="400px" height="300px"><p>You can note that each process has one <strong>invisible</strong> memory segment containing kernel codes and data structures. This invisible memory segment is important; since it’s directly related to <code>virtual memory</code>, which is employed by the kernel for memory management. Before we dive into the other different segments, let’s understand virtual memory first. </p><h4 id="Virtual-memory-technique"><a href="#Virtual-memory-technique" class="headerlink" title="Virtual memory technique"></a>Virtual memory technique</h4><img src="/images/virtual-memory-technique.png" title="virtual memory technique" width="600px" height="400px"><p>Why do we need virtual memory? Virtual memory is a service provided by the kernel in the form of abstraction. Without virtual memory, applications would need to manage their physical memory space, coordinating with every other process running on the computer. Virtual memory leaves that management to the kernel by creating the maps that allow translation between virtual and physical memory.  The kernel creates an illusion that each process occupies the entire physical memory space. We can also realize <a href="https://en.wikipedia.org/wiki/Process_isolation">process isolation</a> based on virtual memory to enhance security. </p><p>Virtual memory is out of this article’s scope, if you’re interested, please take a look at the core techniques: <a href="https://en.wikipedia.org/wiki/Memory_paging">paging</a> and <a href="https://linuxhint.com/linux-memory-management-swap-space/">swapping</a>. </p><h4 id="Static-vs-Dynamic-memory-allocation"><a href="#Static-vs-Dynamic-memory-allocation" class="headerlink" title="Static vs Dynamic memory allocation"></a>Static vs Dynamic memory allocation</h4><p>Next, let’s take a close look at the process memory layout above and understand where they are from. Generally speaking, there are two ways via which memories can be allocated for storing data: <code>static</code> and <code>dynamic</code>. Static memory allocation happens at <code>compile time</code>, while dynamic memory allocation occurs at <code>runtime</code>. </p><p>When a program started, the executable file(on the Linux system, it’s called an <code>ELF</code> file) will be loaded into the memory as a <code>Process Image</code>. This <code>ELF</code> file contains the following segments:</p><ul><li>.TEXT: contains the executable part of the program with all the machine codes.</li><li>.DATA: contains <code>initialized</code> static and global variables. </li><li>.BSS: is short for <code>block started by symbol</code> contains <code>uninitialized</code> static and global variables. </li></ul><p>The <code>ELF</code> file will be loaded by the kernel and create a process image. And these static data will be mapped into the corresponding segments of the virtual memory. The <a href="https://www.linuxjournal.com/article/1060">ELF loader</a> is also an interesting topic, I will write another article about it in the future. Please keep watching my blog!</p><p>The <code>memory-mapped region</code> segment is used for storing the <a href="https://organicprogrammer.com/2019/08/25/how-to-write-linux-c-program-with-external-library/">shared libraries</a>. </p><p>Finally, <code>stack</code> and <code>heap</code> segments are produced at runtime dynamically, which are used to store and operate on temporary variables that are used during the execution of the program. Previously, I once wrote an article about the <a href="https://organicprogrammer.com/2020/08/19/stack-frame/">stack</a>, please refer to it if you want to know the details.</p><p>The only remaining segment we didn’t mention yet is the <code>heap</code>, which is this article’s focus! </p><p>You can check the memory layout of one process by examining this file <code>/proc/&#123;pid&#125;/maps</code> as below: </p><img src="/images/maps-capture.png" title="proc/pid/maps" width="800px" height="600px"><p>Note that the above investigation doesn’t consider multiple threads. The memory layout of the process with multi-threads will be more complex, please refer to other online <a href="https://azeria-labs.com/heap-exploitation-part-2-glibc-heap-free-bins/">documents</a>.</p><p>In this section, we had a rough overview of memory management from top to bottom. Hope you can see the big picture and know where we are. Next, let’s dig into the <code>heap</code> segment and see how it works. </p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;Introduction&quot;&gt;&lt;a href=&quot;#Introduction&quot; class=&quot;headerlink&quot; title=&quot;Introduction&quot;&gt;&lt;/a&gt;Introduction&lt;/h3&gt;&lt;p&gt;In my eyes, compared with deve</summary>
      
    
    
    
    
    <category term="Linux, memory layout, heap, stack" scheme="https://baoqger.github.io/tags/Linux-memory-layout-heap-stack/"/>
    
  </entry>
  
  <entry>
    <title>cPacketSniffer</title>
    <link href="https://baoqger.github.io/2022/07/22/CPacketSniffer/"/>
    <id>https://baoqger.github.io/2022/07/22/CPacketSniffer/</id>
    <published>2022-07-22T02:19:48.000Z</published>
    <updated>2024-08-30T08:45:57.099Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Background"><a href="#Background" class="headerlink" title="Background"></a>Background</h3><p>In this post, I want to introduce my new project: <a href="https://github.com/baoqger/cPacketSniffer"><code>cPacketSniffer</code></a>. I worked on it for the past two months. Finally, I worked it out and feel very proud of putting it here!</p><h3 id="Motivation"><a href="#Motivation" class="headerlink" title="Motivation"></a>Motivation</h3><p>Simply speaking, I want to sharpen my techniques in <code>network programming</code> and <code>Linux system programming</code>. Both of these two topics can lead you to the bottom of computers or software. Feynman said <a href="https://en.wikipedia.org/wiki/There%27s_Plenty_of_Room_at_the_Bottom">“There is plenty of room at the bottom”</a>, I think this physics law can apply to software as well. </p><h3 id="Acknowledgement"><a href="#Acknowledgement" class="headerlink" title="Acknowledgement"></a>Acknowledgement</h3><p>It’s very lucky for me to come across this site <a href="http://tcpip.marcolavoie.ca/index.html">“Network programming in Linux”</a>, which developed a network packet capturing tool with <code>C++</code>. After confirming that the documents and source code on this site is completed and clear, I decided to refactor it with C language. That’s the starting point for my project <code>cPacketSniffer</code>.      </p><h3 id="Features"><a href="#Features" class="headerlink" title="Features"></a>Features</h3><p>As a network packets sniffer, <code>cPacketSniffer</code> provides the following features: </p><img src="/images/cPacketSniffer.png" title="cPacketSniffer modules" width="600px" height="400px"><ul><li>Integrate with <code>libpcap</code> to support: filtering captured packets, capturing packets offline, capturing packets on specific devices and capturing packets in promiscuous mode.</li><li>Analyze network packets at low layers of TCP/IP stack, including <code>Ethernet</code>, <code>ARP</code>, <code>ICMP</code>, <code>IP(IPv4)</code>, <code>TCP</code>, <code>UDP</code>, etc. Also one protocol in the application layer: <code>TFTP</code>. </li><li>Detect network security attacks:<ul><li>ARP spoofing detection.</li><li>Ping flood detection.</li></ul></li><li>Analyze and track network traffics:<ul><li>TCP session tracking and traffic analysis.</li><li>TFTP session tracking and traffic analysis.</li></ul></li></ul><p>The following images demonstrate some typical usages of <code>cPacketSniffer</code>:  </p><p><strong>Packet Analysis</strong>:</p><img src="/images/packet-analysis.png" title="packet analysis" width="600px" height="400px"><p><strong>ARP Spoofing Detection</strong>:</p><img src="/images/arpspoof.png" title="arp spoofing detection" width="600px" height="400px"><p><strong>PING Flood Detection</strong>:</p><img src="/images/pingflooddetection.png" title="ping flood detection" width="600px" height="400px"><p><strong>TCP Session Tracking</strong>:</p><img src="/images/tcpsessiontrack.png" title="tcp session track" width="600px" height="400px"><p>Besides the above network programming-related functionalities, it also covers the following points: </p><ul><li>Develop a generic data structure in C.</li><li>Error handling in C. </li><li>Data encapsulation (object-oriented style programming) in C.</li><li>Manual memory management in C.</li><li>etc.</li></ul><p>This article will not cover these points in detail, I will write articles on these topics separately in the future. Please keep watching my blog!</p><h3 id="Future-work"><a href="#Future-work" class="headerlink" title="Future work"></a>Future work</h3><p>Now <code>cPacketSniffer</code> can work as a network packet sniffer based on the design. Moreover, it can also serve as a testbed to try experimental features. Next step I plan to try the following ideas:</p><ul><li>Implement the network intrusion detection function. </li><li>Improve the performance with advanced data structures, like binary search trees. </li><li>Memory and cache performance tuning. </li><li>Automatic memory management by Garbage Collection.</li><li>Integrate <code>ncurses</code> for Text-based user interface.</li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;Background&quot;&gt;&lt;a href=&quot;#Background&quot; class=&quot;headerlink&quot; title=&quot;Background&quot;&gt;&lt;/a&gt;Background&lt;/h3&gt;&lt;p&gt;In this post, I want to introduce my n</summary>
      
    
    
    
    
    <category term="network packet capture, libpcap, analyze and track network traffics, detect network security attacks, Linux system programming" scheme="https://baoqger.github.io/tags/network-packet-capture-libpcap-analyze-and-track-network-traffics-detect-network-security-attacks-Linux-system-programming/"/>
    
  </entry>
  
  <entry>
    <title>Write a Linux firewall from scratch based on Netfilter: part three - Netfilter module</title>
    <link href="https://baoqger.github.io/2022/06/08/how-to-write-a-netfilter-firewall-part3/"/>
    <id>https://baoqger.github.io/2022/06/08/how-to-write-a-netfilter-firewall-part3/</id>
    <published>2022-06-08T06:59:19.000Z</published>
    <updated>2022-06-25T04:01:11.982Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Background"><a href="#Background" class="headerlink" title="Background"></a>Background</h3><p>In the previous <a href="https://organicprogrammer.com/2022/05/05/how-to-write-a-netfilter-firewall-part2/">article</a>, we examined how to write a Kernel module and load it dynamically into a running Linux system. Based on this understanding, let’s continue our journey to write a <code>Netfilter</code> module as our mini-firewall.  </p><h3 id="Netfilter-architecture"><a href="#Netfilter-architecture" class="headerlink" title="Netfilter architecture."></a>Netfilter architecture.</h3><h5 id="Basics-of-Netfilter-hooks"><a href="#Basics-of-Netfilter-hooks" class="headerlink" title="Basics of Netfilter hooks"></a>Basics of Netfilter hooks</h5><p><strong>The <code>Netfilter</code> framework provides a bunch of <code>hooks</code> in the Linux kernel. As network packets pass through the protocol stack in the kernel, they will traverse these hooks as well</strong>. And Netfilter allows you to write modules and register callback functions with these hooks. When the hooks are triggered, the callback functions will be called. This is the basic idea behind Netfilter architecture. Not difficult to understand, right? </p><img src="/images/netfilter-in-kernel.png" title="Netfilter architecture" width="800px" height="600px"><p>Currently, Netfilter provides the following 5 hooks for <code>IPv4</code>:</p><ul><li><em>NF_INET_PRE_ROUTING</em>: is triggered right after the packet has been received on a network card. This hook is triggered before the <code>routing decision</code> was made. Then the kernel determines whether this packet is destined for the current host or not. Based on the condition, the following two hooks will be triggered. </li><li><em>NF_INET_LOCAL_IN</em>: is triggered for network packets that are destined for the current host. </li><li><em>NF_INET_FORWARD</em>: is triggered for network packets that should be forwarded. </li><li><em>NF_INET_POST_ROUTING</em>: is triggered for network packets that have been routed and before being sent out to the network card. </li><li><em>NF_INET_LOCAL_OUT</em>: is triggered for network packets generated by the processes on the current host.</li></ul><p>The hook function you defined in the module can mangle or filter the packets, but it eventually must return a status code to Netfilter. There are several possible values for the code, but for now, you only need to understand two of them: </p><ul><li><em>NF_ACCEPT</em>: this means the hook function accepts the packet and it can go on the network stack trip. </li><li><em>NF_DROP</em>: this means the packet is dropped and no further parts of the network stack will be traversed.</li></ul><p>Netfilter allows you to register multiple callback functions to the same hook with different priorities. If the first hook function accepts the packet, then the packet will be passed to the next functions with low priority. If the packet is dropped by one callback function, then the next functions(if existing) will not be traversed. </p><p>As you see, <code>Netfilter</code> has a big scope and I can’t cover every detail in the articles. So the mini-firewall developed here will work on the hook <code>NF_INET_PRE_ROUTING</code>, which means it works by controlling the inbound network traffic. But the way of registering the hook and handling the packet can be applied to all other hooks. </p><p><em>Note</em>: there is another remarkable question: what’s the difference between <code>Netfilter</code> and <code>eBPF</code>? If you don’t know eBPF, please refer to my previous <a href="https://organicprogrammer.com/2022/03/28/how-to-implement-libpcap-on-linux-with-raw-socket-part2/">article</a>. Both of them are important network features in the Linux kernel. The important thing is <code>Netfilter</code> and <code>eBPF</code> hooks are located in different layers of the Kernel. As I drew in the above diagram, <code>eBPF</code> is located in a lower layer. </p><h5 id="Kernel-code-of-Netfilter-hooks"><a href="#Kernel-code-of-Netfilter-hooks" class="headerlink" title="Kernel code of Netfilter hooks"></a>Kernel code of Netfilter hooks</h5><p>To have a clear understanding of how the <code>Netfilter</code> framework is implemented inside the protocol stack, let’s dig a little bit deeper and take a look at the kernel source code (Don’t worry, only shows several simple functions). Let’s use the hook <code>NF_INET_PRE_ROUTING</code> as an example; since the mini-firewall will be written based on it. </p><p>When an IPv4 packet is received, its handler function <code>ip_rcv</code> will be called as follows: </p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//In source code file /kernel-src/net/ipv4/ip_input.c</span></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * IP receive entry point</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">ip_rcv</span><span class="params">(<span class="keyword">struct</span> sk_buff *skb, <span class="keyword">struct</span> net_device *dev, <span class="keyword">struct</span> packet_type *pt,</span></span><br><span class="line"><span class="params">           <span class="keyword">struct</span> net_device *orig_dev)</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">net</span> *<span class="title">net</span> =</span> dev_net(dev);</span><br><span class="line"></span><br><span class="line">        skb = ip_rcv_core(skb, net);</span><br><span class="line">        <span class="keyword">if</span> (skb == <span class="literal">NULL</span>)</span><br><span class="line">                <span class="keyword">return</span> NET_RX_DROP;</span><br><span class="line">        <span class="comment">// run Netfilter NF_INET_PRE_ROUTING hook&#x27;s callback function</span></span><br><span class="line">        <span class="keyword">return</span> NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, </span><br><span class="line">                       net, <span class="literal">NULL</span>, skb, dev, <span class="literal">NULL</span>,</span><br><span class="line">                       ip_rcv_finish);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>In this handler function, you can see the hook is passed to the function <code>NF_HOOK</code>. Based on the name <code>NF_HOOK</code>, you can guess that it is for triggering the Netfilter hooks. Right? Let’s continue to examine how <code>NF_HOOK</code> is implemented as follows: </p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//In source code file /kernel-src/include/linux/netfilter.h</span></span><br><span class="line"><span class="type">static</span> <span class="keyword">inline</span> <span class="type">int</span></span><br><span class="line"><span class="title function_">NF_HOOK</span><span class="params">(<span class="type">uint8_t</span> pf, <span class="type">unsigned</span> <span class="type">int</span> hook, <span class="keyword">struct</span> net *net, <span class="keyword">struct</span> sock *sk, <span class="keyword">struct</span> sk_buff *skb,</span></span><br><span class="line"><span class="params">        <span class="keyword">struct</span> net_device *in, <span class="keyword">struct</span> net_device *out,</span></span><br><span class="line"><span class="params">        <span class="type">int</span> (*okfn)(<span class="keyword">struct</span> net *, <span class="keyword">struct</span> sock *, <span class="keyword">struct</span> sk_buff *))</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="type">int</span> ret = nf_hook(pf, hook, net, sk, skb, in, out, okfn);</span><br><span class="line">        <span class="keyword">if</span> (ret == <span class="number">1</span>)</span><br><span class="line">                ret = okfn(net, sk, skb); <span class="comment">// in our case: okfn is ip_rcv_finish</span></span><br><span class="line">        <span class="keyword">return</span> ret;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> *      nf_hook - call a netfilter hook</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> *      Returns 1 if the hook has allowed the packet to pass.  The function</span></span><br><span class="line"><span class="comment"> *      okfn must be invoked by the caller in this case.  Any other return</span></span><br><span class="line"><span class="comment"> *      value indicates the packet has been consumed by the hook.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> <span class="keyword">inline</span> <span class="type">int</span> <span class="title function_">nf_hook</span><span class="params">(<span class="type">u_int8_t</span> pf, <span class="type">unsigned</span> <span class="type">int</span> hook, <span class="keyword">struct</span> net *net,</span></span><br><span class="line"><span class="params">                          <span class="keyword">struct</span> sock *sk, <span class="keyword">struct</span> sk_buff *skb,</span></span><br><span class="line"><span class="params">                          <span class="keyword">struct</span> net_device *indev, <span class="keyword">struct</span> net_device *outdev,</span></span><br><span class="line"><span class="params">                          <span class="type">int</span> (*okfn)(<span class="keyword">struct</span> net *, <span class="keyword">struct</span> sock *, <span class="keyword">struct</span> sk_buff *))</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="comment">// code omit</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>The function <code>NF_HOOK</code> contains two steps:</p><ul><li>First, runs the hook’s callback functions by calling the underlying function <code>nf_hook</code>. </li><li>Second, invokes the function <code>okfn</code> (passed to <em>NF_HOOK</em> as the argument), if the packet passes through the hook functions and doesn’t drop.</li></ul><p>For the hook <em>NF_INET_LOCAL_IN</em>, the function <code>ip_rcv_finish</code> will be invoked after the hook functions pass. Its job is to pass the packet on to the next protocol handler(TCP or UDP) in the protocol stack to continue its journey! </p><p>The other 4 hooks all use the same function <code>NF_HOOK</code> to trigger the callback functions. The following table shows where the hooks are embedded in the kernel, I leave them to the readers. </p><table><thead><tr><th>Hook</th><th>File</th><th>Function</th></tr></thead><tbody><tr><td>NF_INET_PRE_ROUTING</td><td>/kernel-src/net/ipv4/ip_input.c</td><td>ip_rcv()</td></tr><tr><td>NF_INET_LOCAL_IN</td><td>/kernel-src/net/ipv4/ip_input.c</td><td>ip_local_deliver()</td></tr><tr><td>NF_INET_FORWARD</td><td>/kernel-src/net/ipv4/ip_forward.c</td><td>ip_forward()</td></tr><tr><td>NF_INET_POST_ROUTING</td><td>/kernel-src/net/ipv4/ip_output.c</td><td>ip_build_and_send_pkt()</td></tr><tr><td>NF_INET_LOCAL_OUT</td><td>/kernel-src/net/ipv4/ip_output.c</td><td>ip_output()</td></tr></tbody></table><p>Next, Let’s review the Netfilter’s APIs to create and register the hook function. </p><h3 id="Netfilter-API"><a href="#Netfilter-API" class="headerlink" title="Netfilter API"></a>Netfilter API</h3><p>It’s straightforward to create a Netfilter module, which involves three steps: </p><ul><li>Define the hook function.</li><li>Register the hook function in the kernel module initialization process.</li><li>Unregister the hook function in the kernel module clean-up process. </li></ul><p>Let’s go through them quickly one by one. </p><h5 id="Define-a-hook-function"><a href="#Define-a-hook-function" class="headerlink" title="Define a hook function"></a>Define a hook function</h5><p>The hook function name can be whatever you want, but it must follow the signature below: </p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//In source code file /kernel-src/include/linux/netfilter.h</span></span><br><span class="line"><span class="keyword">typedef</span> <span class="type">unsigned</span> <span class="type">int</span> <span class="title function_">nf_hookfn</span><span class="params">(<span class="type">void</span> *priv,</span></span><br><span class="line"><span class="params">                               <span class="keyword">struct</span> sk_buff *skb,</span></span><br><span class="line"><span class="params">                               <span class="type">const</span> <span class="keyword">struct</span> nf_hook_state *state)</span>;</span><br></pre></td></tr></table></figure><p>The hook function can mangle or filter the packet whose data is stored in the <code>sk_buff</code> structure (we can ignore the other two parameters; since we don’t use them in our mini-firewall). As we mentioned above, the callback function must return a Netfilter status code which is an integer. For instance, the <code>accepted</code> and <code>dropped</code> status is defined as follows: </p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// In source code file /kernel-src/include/uapi/linux/netfilter.h</span></span><br><span class="line"><span class="comment">/* Responses from hook functions. */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> NF_DROP 0</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> NF_ACCEPT 1</span></span><br></pre></td></tr></table></figure><h5 id="Register-and-unregister-a-hook-function"><a href="#Register-and-unregister-a-hook-function" class="headerlink" title="Register and unregister a hook function"></a>Register and unregister a hook function</h5><p>To register a hook function, we should wrap the defined hook function with related information, such as which hook you want to bind to, the protocol family and the priority of the hook function,  into a structure <code>struct nf_hook_ops</code> and pass it to the function <code>nf_register_net_hook</code>. </p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//In source code file /kernel-src/include/linux/netfilter.h</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">nf_hook_ops</span> &#123;</span></span><br><span class="line">        <span class="comment">/* User fills in from here down. */</span></span><br><span class="line">        nf_hookfn               *hook;    <span class="comment">// callback function</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">net_device</span>       *<span class="title">dev</span>;</span>     <span class="comment">// network device interface</span></span><br><span class="line">        <span class="type">void</span>                    *priv; </span><br><span class="line">        <span class="type">u_int8_t</span>                pf;       <span class="comment">// protocol</span></span><br><span class="line">        <span class="type">unsigned</span> <span class="type">int</span>            hooknum;  <span class="comment">// Netfilter hook enum</span></span><br><span class="line">        <span class="comment">/* Hooks are ordered in ascending priority. */</span></span><br><span class="line">        <span class="type">int</span>                     priority; <span class="comment">// priority of callback function</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>Most of the fields are very straightforward to understand. The one need to emphasize is the field <code>hooknum</code>, which is just the Netfilter hooks discussed above. They are defined as enumerators as follows: </p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// In source code file /kernel-src/include/uapi/linux/netfilter.h</span></span><br><span class="line"><span class="class"><span class="keyword">enum</span> <span class="title">nf_inet_hooks</span> &#123;</span></span><br><span class="line">NF_INET_PRE_ROUTING,</span><br><span class="line">NF_INET_LOCAL_IN,</span><br><span class="line">NF_INET_FORWARD,</span><br><span class="line">NF_INET_LOCAL_OUT,</span><br><span class="line">NF_INET_POST_ROUTING,</span><br><span class="line">NF_INET_NUMHOOKS,</span><br><span class="line">NF_INET_INGRESS = NF_INET_NUMHOOKS,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>Next, let’s take a look at the functions to register and unregister hook functions goes as follows: </p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//In source code file /kernel-src/include/linux/netfilter.h</span></span><br><span class="line"><span class="comment">/* Function to register/unregister hook points. */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">nf_register_net_hook</span><span class="params">(<span class="keyword">struct</span> net *net, <span class="type">const</span> <span class="keyword">struct</span> nf_hook_ops *ops)</span>;</span><br><span class="line"><span class="type">void</span> <span class="title function_">nf_unregister_net_hook</span><span class="params">(<span class="keyword">struct</span> net *net, <span class="type">const</span> <span class="keyword">struct</span> nf_hook_ops *ops)</span>;</span><br></pre></td></tr></table></figure><p>The first parameter <code>struct net</code> is related to the network namespace, we can ignore it for now and use a default value. </p><p>Next, let’s implement our mini-firewall based on these APIs. All right? </p><h3 id="Implement-mini-firewall"><a href="#Implement-mini-firewall" class="headerlink" title="Implement mini-firewall"></a>Implement mini-firewall</h3><p>First, we need to clarify the requirements for our mini-firewall. We’ll implement two network traffic control rules in the mini-firewall as follows:</p><ul><li><em>Network protocol rule</em>: drops the <a href="https://en.wikipedia.org/wiki/Internet_Control_Message_Protocol">ICMP</a> protocol packets.</li><li><em>IP address rule</em>: drops the packets from one specific IP address.</li></ul><p>The completed code implementation is in this Github <a href="https://github.com/baoqger/linux-mini-firewall-netfilter/blob/main/mini_firewall.c">repo</a>.</p><h5 id="Drop-ICMP-protocol-packets"><a href="#Drop-ICMP-protocol-packets" class="headerlink" title="Drop ICMP protocol packets"></a>Drop ICMP protocol packets</h5><p><code>ICMP</code> is a network protocol widely used in the real world. The popular diagnostic tools like <code>ping</code> and <code>traceroute</code> run the ICMP protocol. We can filter out the ICMP packets based on the protocol type in the IP headers with the following hook function: </p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// In mini-firewall.c </span></span><br><span class="line"><span class="type">static</span> <span class="type">unsigned</span> <span class="type">int</span> <span class="title function_">nf_blockicmppkt_handler</span><span class="params">(<span class="type">void</span> *priv, <span class="keyword">struct</span> sk_buff *skb, <span class="type">const</span> <span class="keyword">struct</span> nf_hook_state *state)</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">iphdr</span> *<span class="title">iph</span>;</span>   <span class="comment">// IP header</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">udphdr</span> *<span class="title">udph</span>;</span> <span class="comment">// UDP header</span></span><br><span class="line"><span class="keyword">if</span>(!skb)</span><br><span class="line"><span class="keyword">return</span> NF_ACCEPT;</span><br><span class="line">iph = ip_hdr(skb); <span class="comment">// retrieve the IP headers from the packet</span></span><br><span class="line"><span class="keyword">if</span>(iph-&gt;protocol == IPPROTO_UDP) &#123; </span><br><span class="line">udph = udp_hdr(skb);</span><br><span class="line"><span class="keyword">if</span>(ntohs(udph-&gt;dest) == <span class="number">53</span>) &#123;</span><br><span class="line"><span class="keyword">return</span> NF_ACCEPT; <span class="comment">// accept UDP packet</span></span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">else</span> <span class="keyword">if</span> (iph-&gt;protocol == IPPROTO_TCP) &#123;</span><br><span class="line"><span class="keyword">return</span> NF_ACCEPT; <span class="comment">// accept TCP packet</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">else</span> <span class="keyword">if</span> (iph-&gt;protocol == IPPROTO_ICMP) &#123;</span><br><span class="line">printk(KERN_INFO <span class="string">&quot;Drop ICMP packet \n&quot;</span>);</span><br><span class="line"><span class="keyword">return</span> NF_DROP;   <span class="comment">// drop TCP packet</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> NF_ACCEPT;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>The logic in the above hook function is easy to understand. First, we retrieve the IP headers from the network packet. And then according to the <code>protocol</code> type field in the headers, we decided to accept TCP and UDP packets but drop the ICMP packets. The only technique we need to pay attention to is the function <code>ip_hdr</code>, which is the kernel function defined as follows: </p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//In source code file /kernel-src/include/linux/ip.h</span></span><br><span class="line"><span class="type">static</span> <span class="keyword">inline</span> <span class="keyword">struct</span> iphdr *<span class="title function_">ip_hdr</span><span class="params">(<span class="type">const</span> <span class="keyword">struct</span> sk_buff *skb)</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="keyword">return</span> (<span class="keyword">struct</span> iphdr *)skb_network_header(skb);</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// In source code file /kernel-src/include/linux/skbuff.h</span></span><br><span class="line"><span class="type">static</span> <span class="keyword">inline</span> <span class="type">unsigned</span> <span class="type">char</span> *<span class="title function_">skb_network_header</span><span class="params">(<span class="type">const</span> <span class="keyword">struct</span> sk_buff *skb)</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="keyword">return</span> skb-&gt;head + skb-&gt;network_header;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>The function <code>ip_hdr</code> delegates the task to the function <code>skb_network_header</code>. It gets IP headers based on the following two data: </p><ul><li>head: is the pointer to the packet;</li><li>network_header: is the offset between the pointer to the packet and the pointer to the network layer protocol header. In detail, you can refer to this <a href="https://linux-kernel-labs.github.io/refs/heads/master/labs/networking.html">document</a>.</li></ul><p>Next, we can register the above hook function as follows: </p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// In mini-firewall.c </span></span><br><span class="line"><span class="type">static</span> <span class="class"><span class="keyword">struct</span> <span class="title">nf_hook_ops</span> *<span class="title">nf_blockicmppkt_ops</span> =</span> <span class="literal">NULL</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">int</span> __init <span class="title function_">nf_minifirewall_init</span><span class="params">(<span class="type">void</span>)</span> &#123;</span><br><span class="line">nf_blockicmppkt_ops = (<span class="keyword">struct</span> nf_hook_ops*)kcalloc(<span class="number">1</span>,  <span class="keyword">sizeof</span>(<span class="keyword">struct</span> nf_hook_ops), GFP_KERNEL);</span><br><span class="line"><span class="keyword">if</span> (nf_blockicmppkt_ops != <span class="literal">NULL</span>) &#123;</span><br><span class="line">nf_blockicmppkt_ops-&gt;hook = (nf_hookfn*)nf_blockicmppkt_handler;</span><br><span class="line">nf_blockicmppkt_ops-&gt;hooknum = NF_INET_PRE_ROUTING;</span><br><span class="line">nf_blockicmppkt_ops-&gt;pf = NFPROTO_IPV4;</span><br><span class="line">nf_blockicmppkt_ops-&gt;priority = NF_IP_PRI_FIRST; <span class="comment">// set the priority</span></span><br><span class="line"></span><br><span class="line">nf_register_net_hook(&amp;init_net, nf_blockicmppkt_ops);</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">void</span> __exit <span class="title function_">nf_minifirewall_exit</span><span class="params">(<span class="type">void</span>)</span> &#123;</span><br><span class="line"><span class="keyword">if</span>(nf_blockicmppkt_ops != <span class="literal">NULL</span>) &#123;</span><br><span class="line">nf_unregister_net_hook(&amp;init_net, nf_blockicmppkt_ops);</span><br><span class="line">kfree(nf_blockicmppkt_ops);</span><br><span class="line">&#125;</span><br><span class="line">printk(KERN_INFO <span class="string">&quot;Exit&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">module_init(nf_minifirewall_init);</span><br><span class="line">module_exit(nf_minifirewall_exit);</span><br></pre></td></tr></table></figure><p>The above logic is self-explaining. I will not spend too much time here. </p><p>Next, it’s time to demo how our mini-firewall works. </p><h5 id="Demo-time"><a href="#Demo-time" class="headerlink" title="Demo time"></a>Demo time</h5><p>Before we load the mini-firewall module, the <code>ping</code> command can work as expected: </p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">chrisbao@CN0005DOU18129:~$ lsmod | grep mini_firewall</span><br><span class="line">chrisbao@CN0005DOU18129:~$ ping www.google.com</span><br><span class="line">PING www.google.com (<span class="number">142.250</span><span class="number">.4</span><span class="number">.103</span>) <span class="number">56</span>(<span class="number">84</span>) <span class="built_in">bytes</span> of data.</span><br><span class="line"><span class="number">64</span> <span class="built_in">bytes</span> <span class="keyword">from</span> sm-<span class="keyword">in</span>-f103<span class="number">.1e100</span>.net (<span class="number">142.250</span><span class="number">.4</span><span class="number">.103</span>): icmp_seq=<span class="number">1</span> ttl=<span class="number">104</span> time=<span class="number">71.9</span> ms</span><br><span class="line"><span class="number">64</span> <span class="built_in">bytes</span> <span class="keyword">from</span> sm-<span class="keyword">in</span>-f103<span class="number">.1e100</span>.net (<span class="number">142.250</span><span class="number">.4</span><span class="number">.103</span>): icmp_seq=<span class="number">2</span> ttl=<span class="number">104</span> time=<span class="number">71.8</span> ms</span><br><span class="line"><span class="number">64</span> <span class="built_in">bytes</span> <span class="keyword">from</span> sm-<span class="keyword">in</span>-f103<span class="number">.1e100</span>.net (<span class="number">142.250</span><span class="number">.4</span><span class="number">.103</span>): icmp_seq=<span class="number">3</span> ttl=<span class="number">104</span> time=<span class="number">71.9</span> ms</span><br><span class="line"><span class="number">64</span> <span class="built_in">bytes</span> <span class="keyword">from</span> sm-<span class="keyword">in</span>-f103<span class="number">.1e100</span>.net (<span class="number">142.250</span><span class="number">.4</span><span class="number">.103</span>): icmp_seq=<span class="number">4</span> ttl=<span class="number">104</span> time=<span class="number">71.8</span> ms</span><br><span class="line">^C</span><br><span class="line">--- www.google.com ping statistics ---</span><br><span class="line"><span class="number">4</span> packets transmitted, <span class="number">4</span> received, <span class="number">0</span>% packet loss, time 3005ms</span><br><span class="line">rtt <span class="built_in">min</span>/avg/<span class="built_in">max</span>/mdev = <span class="number">71.857</span>/<span class="number">71.902</span>/<span class="number">71.961</span>/<span class="number">0.193</span> ms</span><br></pre></td></tr></table></figure><p>In contrast, after the mini-firewall module is built and loaded (based on the commands we discussed previously): </p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">chrisbao@CN0005DOU18129:~$ lsmod | grep mini_firewall</span><br><span class="line">mini_firewall          <span class="number">16384</span>  <span class="number">0</span></span><br><span class="line">chrisbao@CN0005DOU18129:~$ ping www.google.com</span><br><span class="line">PING www.google.com (<span class="number">142.250</span><span class="number">.4</span><span class="number">.105</span>) <span class="number">56</span>(<span class="number">84</span>) <span class="built_in">bytes</span> of data.</span><br><span class="line">^C</span><br><span class="line">--- www.google.com ping statistics ---</span><br><span class="line"><span class="number">6</span> packets transmitted, <span class="number">0</span> received, <span class="number">100</span>% packet loss, time 5097ms</span><br></pre></td></tr></table></figure><p>You can see all the packets are lost; because it is dropped by our mini-firewall. We can verify this by running the command <code>dmesg</code>: </p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">chrisbao@CN0005DOU18129:~$ dmesg | tail -n <span class="number">5</span></span><br><span class="line">[ <span class="number">1260.184712</span>] Drop ICMP packet</span><br><span class="line">[ <span class="number">1261.208637</span>] Drop ICMP packet</span><br><span class="line">[ <span class="number">1262.232669</span>] Drop ICMP packet</span><br><span class="line">[ <span class="number">1263.256757</span>] Drop ICMP packet</span><br><span class="line">[ <span class="number">1264.280733</span>] Drop ICMP packet</span><br></pre></td></tr></table></figure><p>But other protocol packets can still run through the firewall. For instance, the command <code>wget 142.250.4.103</code> can return normally as follows:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">chrisbao@CN0005DOU18129:~$ wget <span class="number">142.250</span><span class="number">.4</span><span class="number">.103</span></span><br><span class="line">--<span class="number">2022</span>-06-<span class="number">25</span> <span class="number">10</span>:<span class="number">12</span>:<span class="number">39</span>--  http://<span class="number">142.250</span><span class="number">.4</span><span class="number">.103</span>/</span><br><span class="line">Connecting to <span class="number">142.250</span><span class="number">.4</span><span class="number">.103</span>:<span class="number">80.</span>.. connected.</span><br><span class="line">HTTP request sent, awaiting response... <span class="number">302</span> Moved Temporarily</span><br><span class="line">Location: http://<span class="number">142.250</span><span class="number">.4</span><span class="number">.103</span>:<span class="number">6080</span>/php/urlblock.php?args=AAAAfQAAABAjFEC0HSM7xhfO~a53FMMaAAAAEILI_eaKvZQ2xBfgKEgDtwsAAABNAAAATRPNhqoqFgHJ0ggbKLKcdinR4UvnlhgAR4~YyrY4tAnroOFkE_IsHsOg9~RFPc7nEoj6YdiDgqZImAmb_xw9ZuFLvF91P2HzP5tlu1WX&amp;url=http://<span class="number">142.250</span><span class="number">.4</span><span class="number">.103</span>%2f [following]</span><br><span class="line">--<span class="number">2022</span>-06-<span class="number">25</span> <span class="number">10</span>:<span class="number">12</span>:<span class="number">39</span>--  http://<span class="number">142.250</span><span class="number">.4</span><span class="number">.103</span>:<span class="number">6080</span>/php/urlblock.php?args=AAAAfQAAABAjFEC0HSM7xhfO~a53FMMaAAAAEILI_eaKvZQ2xBfgKEgDtwsAAABNAAAATRPNhqoqFgHJ0ggbKLKcdinR4UvnlhgAR4~YyrY4tAnroOFkE_IsHsOg9~RFPc7nEoj6YdiDgqZImAmb_xw9ZuFLvF91P2HzP5tlu1WX&amp;url=http://<span class="number">142.250</span><span class="number">.4</span><span class="number">.103</span>%2f</span><br><span class="line">Connecting to <span class="number">142.250</span><span class="number">.4</span><span class="number">.103</span>:<span class="number">6080.</span>.. connected.</span><br><span class="line">HTTP request sent, awaiting response... <span class="number">200</span> OK</span><br><span class="line">Length: <span class="number">3248</span> (<span class="number">3.2</span>K) [text/html]</span><br><span class="line">Saving to: ‘index.html’</span><br><span class="line"></span><br><span class="line">index.html                                           <span class="number">100</span>%[===================================================================================================================&gt;]   <span class="number">3.17</span>K  --.-KB/s    <span class="keyword">in</span> 0s</span><br><span class="line"></span><br><span class="line"><span class="number">2022</span>-06-<span class="number">25</span> <span class="number">10</span>:<span class="number">12</span>:<span class="number">39</span> (<span class="number">332</span> MB/s) - ‘index.html’ saved [<span class="number">3248</span>/<span class="number">3248</span>]</span><br></pre></td></tr></table></figure><p>Next, let’s try to ban the traffic from this IP address. </p><h5 id="Drop-packets-source-from-one-specific-IP-address"><a href="#Drop-packets-source-from-one-specific-IP-address" class="headerlink" title="Drop packets source from one specific IP address"></a>Drop packets source from one specific IP address</h5><p>As we mentioned above, multiple callback functions are allowed to be registered on the same Netfilter hook. So we will define the second hook function with a different priority. The logic of this hook function goes like this: we can get the source IP address from the IP headers and make the drop or accept decision according to it. The code goes as follows</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// In mini-firewall.c </span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> IPADDRESS(addr) \</span></span><br><span class="line"><span class="meta">((unsigned char *)&amp;addr)[3], \</span></span><br><span class="line"><span class="meta">((unsigned char *)&amp;addr)[2], \</span></span><br><span class="line"><span class="meta">((unsigned char *)&amp;addr)[1], \</span></span><br><span class="line"><span class="meta">((unsigned char *)&amp;addr)[0]</span></span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">char</span> *ip_addr_rule = <span class="string">&quot;142.250.4.103&quot;</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">unsigned</span> <span class="type">int</span> <span class="title function_">nf_blockipaddr_handler</span><span class="params">(<span class="type">void</span> *priv, <span class="keyword">struct</span> sk_buff *skb, <span class="type">const</span> <span class="keyword">struct</span> nf_hook_state *state)</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">if</span> (!skb) &#123;</span><br><span class="line"><span class="keyword">return</span> NF_ACCEPT;</span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line"><span class="type">char</span> *str = (<span class="type">char</span> *)kmalloc(<span class="number">16</span>, GFP_KERNEL);</span><br><span class="line">u32 sip;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">sk_buff</span> *<span class="title">sb</span> =</span> <span class="literal">NULL</span>;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">iphdr</span> *<span class="title">iph</span>;</span></span><br><span class="line"></span><br><span class="line">sb = skb;</span><br><span class="line">iph = ip_hdr(sb);</span><br><span class="line">sip = ntohl(iph-&gt;saddr); <span class="comment">// get source ip address; </span></span><br><span class="line"></span><br><span class="line"><span class="built_in">sprintf</span>(str, <span class="string">&quot;%u.%u.%u.%u&quot;</span>, IPADDRESS(sip)); <span class="comment">// convert to standard IP address format</span></span><br><span class="line"><span class="keyword">if</span>(!<span class="built_in">strcmp</span>(str, ip_addr_rule)) &#123;</span><br><span class="line"><span class="keyword">return</span> NF_DROP;</span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line"><span class="keyword">return</span> NF_ACCEPT;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>This hook function uses two interesting techniques:</p><ul><li><p><code>ntohl</code>: is a kernel function, which is used to convert the value from <code>network byte order</code> to <code>host byte order</code>. <code>Byte order</code> is related to the computer science concept of <a href="https://en.wikipedia.org/wiki/Endianness"><code>Endianness</code></a>. Endianness defines the order or sequence of bytes of a word of digital data in computer memory. A <code>big-endian</code> system stores the most significant byte of a word at the smallest memory address.  A <code>little-endian</code> system, in contrast, stores the least-significant byte at the smallest address. Network protocol uses the <code>big-endian</code> system. But different OS and platforms run various Endianness system. So it may need such conversion based on the host machine.</p></li><li><p><code>IPADDRESS</code>: is a macro, which generates the standard IP address format(four 8-bit fields separated by periods) from a 32-bit integer. It uses the technique of <a href="https://www.eskimo.com/~scs/cclass/notes/sx10e.html"><code>the equivalence of arrays and pointers in C</code></a>. I will write another article to examine what it is and how it works. Please keep watching my updates!</p></li></ul><p>Next, we can register this hook function in the same way discussed above. The only remarkable point is this callback function should have a different priority as follows:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">int</span> __init <span class="title function_">nf_minifirewall_init</span><span class="params">(<span class="type">void</span>)</span> &#123;</span><br><span class="line">&lt;-omit code-&gt;</span><br><span class="line">nf_blockipaddr_ops = (<span class="keyword">struct</span> nf_hook_ops*)kcalloc(<span class="number">1</span>, <span class="keyword">sizeof</span>(<span class="keyword">struct</span> nf_hook_ops), GFP_KERNEL);</span><br><span class="line"><span class="keyword">if</span> (nf_blockipaddr_ops != <span class="literal">NULL</span>) &#123;</span><br><span class="line">nf_blockipaddr_ops-&gt;hook = (nf_hookfn*)nf_blockipaddr_handler;</span><br><span class="line">nf_blockipaddr_ops-&gt;hooknum = NF_INET_PRE_ROUTING;  <span class="comment">// register to the same hook</span></span><br><span class="line">nf_blockipaddr_ops-&gt;pf = NFPROTO_IPV4;</span><br><span class="line">nf_blockipaddr_ops-&gt;priority = NF_IP_PRI_FIRST + <span class="number">1</span>; <span class="comment">// set a higher priority</span></span><br><span class="line"></span><br><span class="line">nf_register_net_hook(&amp;init_net, nf_blockipaddr_ops);</span><br><span class="line">&#125;</span><br><span class="line">&lt;-omit code-&gt;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Let’s see how it works with a demo. </p><h5 id="Demo-time-1"><a href="#Demo-time-1" class="headerlink" title="Demo time"></a>Demo time</h5><p>After re-build and re-load the module, we can get: </p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">chrisbao@CN0005DOU18129:~$ wget <span class="number">142.250</span><span class="number">.4</span><span class="number">.103</span></span><br><span class="line">--<span class="number">2022</span>-06-<span class="number">25</span> <span class="number">10</span>:<span class="number">20</span>:07--  http://<span class="number">142.250</span><span class="number">.4</span><span class="number">.103</span>/</span><br><span class="line">Connecting to <span class="number">142.250</span><span class="number">.4</span><span class="number">.103</span>:<span class="number">80.</span>.. failed: Connection timed out.</span><br><span class="line">Retrying.</span><br></pre></td></tr></table></figure><p>The <code>wget 142.250.4.103</code> can’t return response. Because it is dropped by our mini-firewall. Great!</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">chrisbao@CN0005DOU18129:~$ dmesg | tail -n <span class="number">5</span></span><br><span class="line">[ <span class="number">3162.064284</span>] Drop packet <span class="keyword">from</span> <span class="number">142.250</span><span class="number">.4</span><span class="number">.103</span></span><br><span class="line">[ <span class="number">3166.089466</span>] Drop packet <span class="keyword">from</span> <span class="number">142.250</span><span class="number">.4</span><span class="number">.103</span></span><br><span class="line">[ <span class="number">3166.288603</span>] Drop packet <span class="keyword">from</span> <span class="number">142.250</span><span class="number">.4</span><span class="number">.103</span></span><br><span class="line">[ <span class="number">3174.345463</span>] Drop packet <span class="keyword">from</span> <span class="number">142.250</span><span class="number">.4</span><span class="number">.103</span></span><br><span class="line">[ <span class="number">3174.480123</span>] Drop packet <span class="keyword">from</span> <span class="number">142.250</span><span class="number">.4</span><span class="number">.103</span></span><br></pre></td></tr></table></figure><h3 id="More-space-to-expand"><a href="#More-space-to-expand" class="headerlink" title="More space to expand"></a>More space to expand</h3><p>You can find the full code implementation <a href="https://github.com/baoqger/linux-mini-firewall-netfilter/blob/main/mini_firewall.c">here</a>. But I have to say, our mini-firewall only touches the surface of what Netfilter can provide. You can keep expanding the functionalities. For example, currently, the rules are hardcoded, why not make it possible to config the rules dynamically. There are many cool ideas worth trying. I leave it for the readers.  </p><h3 id="Summary"><a href="#Summary" class="headerlink" title="Summary"></a>Summary</h3><p>In this article, we implement the mini-firewall step by step and examined many detailed techniques. Not only code; but we also verify the behavior of the mini-firewall by running real demos.   </p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;Background&quot;&gt;&lt;a href=&quot;#Background&quot; class=&quot;headerlink&quot; title=&quot;Background&quot;&gt;&lt;/a&gt;Background&lt;/h3&gt;&lt;p&gt;In the previous &lt;a href=&quot;https://organ</summary>
      
    
    
    
    
    <category term="Linux module, Netfilter, firewall" scheme="https://baoqger.github.io/tags/Linux-module-Netfilter-firewall/"/>
    
  </entry>
  
  <entry>
    <title>Write a Linux firewall from scratch based on Netfilter: part two - hello world module</title>
    <link href="https://baoqger.github.io/2022/05/05/how-to-write-a-netfilter-firewall-part2/"/>
    <id>https://baoqger.github.io/2022/05/05/how-to-write-a-netfilter-firewall-part2/</id>
    <published>2022-05-05T10:06:50.000Z</published>
    <updated>2022-06-22T03:28:37.680Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Background"><a href="#Background" class="headerlink" title="Background"></a>Background</h3><p>In the last <a href="https://organicprogrammer.com/2022/05/04/how-to-write-a-netfilter-firewall-part1/">article</a>, we examined the basics of <code>Netfilter</code> and <code>Linux kernel modules</code> in theory. Starting from this article, we will make our hands dirty and start implementing our mini-firewall. We will walk through the whole process step by step. In this article, let’s write our first Linux kernel module using a simple <code>hello world</code> demo. Then let’s learn how to build the module(which is very different from compiling an application in the user space) and how to load it in the kernel. After understanding how to write a module, in the next article, let’s write the initial version of our mini-firewall module using <a href="https://wiki.nftables.org/wiki-nftables/index.php/Netfilter_hooks">Netfilter’s hook architecture</a>. All right. Let’s start the journey. </p><h3 id="Make-the-first-Kernel-module"><a href="#Make-the-first-Kernel-module" class="headerlink" title="Make the first Kernel module"></a>Make the first Kernel module</h3><p>First, I have to admit that Linux Kernel module development is a kind of large and complex technology topic. And there are many great <a href="https://sysprog21.github.io/lkmpg/">online resources</a> about it. This series of articles is focusing on developing the mini-firewall based on Netfilter, so we can’t cover all the aspects of the Kernel module itself. In future articles, I’ll examine more in-depth knowledge of kernel modules. </p><h4 id="Write-the-module"><a href="#Write-the-module" class="headerlink" title="Write the module"></a>Write the module</h4><p>You can write the <code>hello world</code> Kernel module with a single <code>C</code> source code file <code>hello.c</code> as follows:  </p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/init.h&gt;</span> <span class="comment">/* Needed for the macros */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/kernel.h&gt;</span> </span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/module.h&gt;</span> <span class="comment">/* Needed by all modules */</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">int</span> __init <span class="title function_">hello_init</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">    printk(KERN_INFO <span class="string">&quot;Hello, world\n&quot;</span>);</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">void</span> __exit <span class="title function_">hello_exit</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">    printk(KERN_INFO <span class="string">&quot;Goodbye, world\n&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">module_init(hello_init);</span><br><span class="line">module_exit(hello_exit);</span><br><span class="line"></span><br><span class="line">MODULE_LICENSE(<span class="string">&quot;GPL&quot;</span>);</span><br></pre></td></tr></table></figure><p>We can write a Kernel module in such an easy and simple way because the Linux Kernel does the magic for you. Remember the design philosophy of Linux(Unix): <strong><em>Design for simplicity; add complexity only where you must</em></strong>. </p><p>Let’s examine several technical points worth to remark as follows: </p><p>First, Kernel modules must have at least two functions: a “start” function which is called when the module is loaded into the kernel, and an “end” function which is called just before it is removed from the kernel. Before kernel 2.3.13, the names of these two functions are hardcoded as <code>init_module()</code> and <code>cleanup_module()</code>. But in the new versions, you can use whatever name you like for the start and end functions of a module by using the <code>module_init</code> and <code>module_exit</code> macros. The macros are defined in <code>include/linux/module.h</code> and <code>include/linux/init.h</code>. You can refer there for detailed information. </p><p>Typically, <code>module_init</code> either registers a handler for something with the kernel (for example, the mini-firewall developed in this article), or it replaces one of the kernel functions with its own code (usually code to do something and then call the original function). The <code>module_exit</code> function is supposed to undo whatever <code>module_init</code> did, so the module can be unloaded safely.</p><p>Second, <code>printk</code> function provides similar behaviors to <code>printf</code>, which accepts the <code>format string</code> as the first argument. The <code>printk</code> function prototype goes as follows:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">printk</span><span class="params">(<span class="type">const</span> <span class="type">char</span> *fmt, ...)</span>;</span><br></pre></td></tr></table></figure><p><code>printk</code> function allows a caller to specify <code>log level</code> to indicate the type and importance of the message being sent to the kernel message log. For example, in the above code, the log level <code>KERN_INFO</code> is specified by prepending to the format string. In C programming, this syntax is called <a href="https://en.wikipedia.org/wiki/String_literal#String_literal_concatenation"><code>string literal concatenation</code></a>. (In other high-level programming languages, string concatenation is generally done with <code>+</code> operator). For the function <code>printk</code> and <code>log level</code>, you can find more information in <code>include/linux/kern_levels.h</code> and <code>include/linux/printk.h</code>.   </p><p>Note: The path to header files for Linux kernel module development is different from the one you often used for the application development. Don’t try to find the header file inside <em>/usr/include/linux</em>, instead please use the following path <em>/lib/modules/`uname -r`/build/include/linux</em> (<code>uname -r</code> command returns your kernel version).</p><p>Next, let’s build this hello-world kernel module.</p><h4 id="Build-the-module"><a href="#Build-the-module" class="headerlink" title="Build the module"></a>Build the module</h4><p>The way to build a kernel module is a little different from how to build a user-space application. The efficient solution to build kernel image and its modules is <code>Kernel Build System(Kbuild)</code>. </p><p><code>Kbuild</code> is a complex topic and I won’t explain it in too much detail here. Simply speaking, <code>Kbuild</code> allows you to create highly customized kernel binary images and modules. Technically, each subdirectory contains a <code>Makefile</code> compiling only the source code files in its directory. And a top-level Makefile recursively executes each subdirectory’s Makefile to generate the binary objects. And you can control which subdirectories are included by defining <code>config files</code>. In detail, you can refer to other <a href="https://www.linuxjournal.com/content/kbuild-linux-kernel-build-system">documents</a>. </p><p>The following is the Makefile for the <code>hello world</code> module: </p><figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">obj-m += hello.o</span><br><span class="line">PWD := <span class="variable">$(CURDIR)</span></span><br><span class="line"><span class="section">all:</span></span><br><span class="line">        make -C /lib/modules/<span class="variable">$(<span class="built_in">shell</span> uname -r)</span>/build M=<span class="variable">$(PWD)</span> modules</span><br><span class="line"><span class="section">clean:</span></span><br><span class="line">        make -C /lib/modules/<span class="variable">$(<span class="built_in">shell</span> uname -r)</span>/build M=<span class="variable">$(PWD)</span> clean</span><br></pre></td></tr></table></figure><p>The <code>make -C dir</code> command changes to directory dir before reading the makefiles or doing anything else. The top-level Makefile in <em>/lib/modules/$(shell uname -r)/build</em> will be used. You can find that command <code>make M=dir modules</code> is used to make all modules in specified dir.</p><p>And in the module-level Makefile, the <code>obj-m</code> syntax tells <code>kbuild</code> system to build <code>module_name.o</code> from <code>module_name.c</code>, and after linking, will result in the kernel module <code>module_name.ko</code>. In our case, the module name is <code>hello</code>.</p><p>The build process goes as follows: </p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">chrisbao:~/develop/kernel/hello-1$ sudo make</span><br><span class="line">make -C /lib/modules/4.15.0-176-generic/build M=/home/DIR/jbao6/develop/kernel/hello-1  modules</span><br><span class="line">make[1]: Entering directory <span class="string">&#x27;/usr/src/linux-headers-4.15.0-176-generic&#x27;</span></span><br><span class="line">  CC [M]  /home/DIR/jbao6/develop/kernel/hello-1/hello.o</span><br><span class="line">  Building modules, stage 2.</span><br><span class="line">  MODPOST 1 modules</span><br><span class="line">  CC      /home/DIR/jbao6/develop/kernel/hello-1/hello.mod.o</span><br><span class="line">  LD [M]  /home/DIR/jbao6/develop/kernel/hello-1/hello.ko</span><br><span class="line">make[1]: Leaving directory <span class="string">&#x27;/usr/src/linux-headers-4.15.0-176-generic&#x27;</span></span><br></pre></td></tr></table></figure><p>After the build, you can get several new files in the same directory: </p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">chrisbao:~/develop/kernel/hello-1$ <span class="built_in">ls</span></span><br><span class="line">hello.c  hello.ko  hello.mod.c  hello.mod.o  hello.o  Makefile  modules.order  Module.symvers</span><br></pre></td></tr></table></figure><p>The file ends with <code>.ko</code> is the kernel module. You can ignore other files now, I will write another article later to have a deep discussion about the kernel module system. </p><h4 id="Load-the-module"><a href="#Load-the-module" class="headerlink" title="Load the module"></a>Load the module</h4><p>With the <code>file</code> command, you can note that the kernel module is an <code>ELF(Executable and Linkable Format)</code> format file. ELF files are typically the output of a compiler or linker and are a binary format. </p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">chrisba:~/develop/kernel/hello-1$ file hello.ko</span><br><span class="line">hello.ko: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), BuildID[sha1]=f0da99c757751e7e9f9c4e55f527fb034a0a4253, not stripped</span><br></pre></td></tr></table></figure><p>Next step, let’s try to install and remove the module dynamically. You need to know the following three commands: </p><ul><li><em>lsmod</em>: shows the list of kernel modules currently loaded.</li><li><em>insmod</em>: inserts a module into the Linux Kernel by running <code>sudo insmod module_name.ko</code></li><li><em>rmmod</em>: removes a module from the Linux Kernel by running <code>sudo rmmod module_name</code></li></ul><p>Since the <code>hello world</code> module is quite simple, you can easily install and remove the module as you wish. I will not show the detailed commands here and leave it to the readers. </p><p><strong>Note</strong>: It doesn’t mean that you can easily install and remove any kernel module without any issues. If the module you are loading has bugs, the entire system can crash. </p><h4 id="Debug-the-module"><a href="#Debug-the-module" class="headerlink" title="Debug the module"></a>Debug the module</h4><p>Next step, let’s prove that the <code>hello world</code> module is installed and removed as expected. We will use <code>dmesg</code> command. <code>dmesg</code> (diagnostic messages) can print the messages in the <code>kernel ring buffer</code>. </p><p>First, a <a href="https://en.wikipedia.org/wiki/Circular_buffer"><code>ring buffer</code></a> is a data structure that uses a single, fixed-size buffer as if it were connected end-to-end. The <code>kernel ring buffer</code> is a ring buffer that records messages related to the operation of the kernel. As we mentioned above, the kernel logs printed by the <code>printk</code> function will be sent to the kernel ring buffer. </p><p>We can find the messages produced by our module with command <code>dmesg | grep world</code> as follows:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">chrisbao:~$ dmesg | grep world</span><br><span class="line"></span><br><span class="line">[2147137.177254] Hello, world</span><br><span class="line">[3281962.445169] Goodbye, world</span><br><span class="line">[3282008.037591] Hello, world</span><br><span class="line">[3282054.921824] Goodbye, world</span><br></pre></td></tr></table></figure><p>Now you can see that the <code>hello world</code> is loaded into the kernel correctly. And it can be removed dynamically as well. Great. </p><h3 id="Summary"><a href="#Summary" class="headerlink" title="Summary"></a>Summary</h3><p>In this article, we examine how to write a kernel module, how to build it and how to install it into the kernel dynamically. Next article we can work on the mini-firewall as a <code>Netfilter</code> module. </p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;Background&quot;&gt;&lt;a href=&quot;#Background&quot; class=&quot;headerlink&quot; title=&quot;Background&quot;&gt;&lt;/a&gt;Background&lt;/h3&gt;&lt;p&gt;In the last &lt;a href=&quot;https://organicpr</summary>
      
    
    
    
    
    <category term="Linux module, Netfilter, firewall" scheme="https://baoqger.github.io/tags/Linux-module-Netfilter-firewall/"/>
    
  </entry>
  
  <entry>
    <title>Write a Linux firewall from scratch based on Netfilter: part one- Netfilter and Kernel Modules</title>
    <link href="https://baoqger.github.io/2022/05/04/how-to-write-a-netfilter-firewall-part1/"/>
    <id>https://baoqger.github.io/2022/05/04/how-to-write-a-netfilter-firewall-part1/</id>
    <published>2022-05-04T10:06:50.000Z</published>
    <updated>2022-06-22T02:15:31.063Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Background"><a href="#Background" class="headerlink" title="Background"></a>Background</h3><p><code>Firewalls</code> are an important tool that can be configured to protect your servers and infrastructure. Firewalls’ main functionalities are filtering data, redirecting traffic, and protecting against network attacks. There are both hardware-based firewalls and software-based firewalls. I will not discuss too much about the background here, since you can find many online documents about <a href="https://en.wikipedia.org/wiki/Firewall_(computing)">it</a>.</p><p>Have you ever thought of implementing a simple firewall from scratch? Sounds crazy? But with the power of Linux, you can do that. After you read this series of articles, you will find that actually, it is quite simple. </p><p>You may once use various firewalls on Linux such as <a href="https://en.wikipedia.org/wiki/Iptables">iptables</a>, <a href="https://en.wikipedia.org/wiki/Nftables">nftables</a>, <a href="https://en.wikipedia.org/wiki/Uncomplicated_Firewall">UFW</a>, etc. All of these firewall tools are user-space utility programs, and they are all relying on <a href="https://en.wikipedia.org/wiki/Netfilter"><code>Netfilter</code></a>. <code>Netfilter</code> is the Linux kernel subsystem that allows various networking-related operations to be implemented. <code>Netfilter</code> allows you to develop your firewall using the <code>Linux Kernel Module</code>.  If you don’t know the techniques such as the Linux Kernel module and Netfilter, don’t worry. In this article, let’s write a Linux firewall from scratch based on Netfilter. You can learn the following interesting points:</p><ul><li>Linux kernel module development.</li><li>Linux kernel network programming. </li><li>Netfilter module development.</li></ul><h3 id="Netfilter-and-Kernel-modules"><a href="#Netfilter-and-Kernel-modules" class="headerlink" title="Netfilter and Kernel modules"></a>Netfilter and Kernel modules</h3><h4 id="Basics-of-Netfilter"><a href="#Basics-of-Netfilter" class="headerlink" title="Basics of Netfilter"></a>Basics of Netfilter</h4><p><code>Netfilter</code> can be considered to be the third generation of <code>firewall</code> on Linux. Before <code>Netfilter</code>was introduced in Linux Kernel 2.4, there are two older generations of firewalls on Linux as follows: </p><ul><li>The first generation was a port of an early version of BSD UNIX’s <code>ipfw</code> to Linux 1.1. </li><li>The second generation was <code>ipchains</code> developed in the 2.2 series of Linux Kernel. </li></ul><p>As we mentioned above, <code>Netfilter</code> was designed to provide the infrastructure inside the Linux kernel for various networking operations. So <code>firewall</code> is just one of the multiple functionalities provided by <code>Netfilter</code> as follows:</p><img src="/images/netfilter-arch.png" title="Netfilter architecture" width="600px" height="400px"><ul><li><strong>Packet filtering</strong>: is in charge of filtering the packets based on the rules. It is also the topic of this article. </li><li><strong>NAT (Network address translation)</strong>: is in charge of translating the IP address of network packets. <code>NAT</code> is an important protocol, which has become a popular and essential tool in <code>conserving global address space in the face of IPv4 address exhaustion</code>. If you don’t know <code>NAT</code> protocol, you can refer to other <a href="https://en.wikipedia.org/wiki/Network_address_translation">documents</a>. I will examine it in other future articles. </li><li><strong>Packet mangling</strong>: is in charge of modifying the packet content(In fact, <code>NAT</code> is one kind of packet mangling, which modifies the source or destination IP address). For example, <code>MSS (Maximum Segment Size)</code> value of TCP SYN packets can be altered to allow large-size packets transported over the network. </li></ul><p>Note: this article will focus on building a simple firewall to filter packets based on Netfilter. So the <code>NAT</code> and <code>Packet Mangling</code> parts are not in the scope of this article. </p><p>Packet filtering can only be done inside the Linux kernel (Netfilter’s code is in the kernel as well), if we want to write a mini firewall, it has to run in the kernel space. Right? Does it mean we need to add our code into the kernel and recompile the kernel? Imagine you have to recompile the kernel each time you want to add a new packet filtering rule. That’s a bad idea. The good news is that <code>Netfilter</code> allows you to add extensions using the <a href="https://wiki.archlinux.org/title/Kernel_module"><code>Linux kernel modules</code></a>. </p><h4 id="Basics-of-Linux-Kernel-modules"><a href="#Basics-of-Linux-Kernel-modules" class="headerlink" title="Basics of Linux Kernel modules"></a>Basics of Linux Kernel modules</h4><p>Although Linux is a <a href="https://en.wikipedia.org/wiki/Monolithic_kernel"><code>monolithic kernel</code></a>, it can be extended using kernel modules. Modules can be inserted into the kernel and removed on demand. Linux isolates the kernel but allows you to add specific functionality on the fly through modules. In this way, Linux keeps a balance between stability and usability. </p><p>I want to examine one confusing point about the kernel module here: what is the difference between <code>driver</code> and <code>module</code>:</p><ul><li>A driver is a bit of code that runs in the kernel to talk to some hardware device. It drives the hardware. Standard practice is to build drivers as kernel modules where possible, rather than link them statically to the kernel since that gives more flexibility. </li><li>A kernel module may not be a device driver at all.    </li></ul><h3 id="Summary"><a href="#Summary" class="headerlink" title="Summary"></a>Summary</h3><p>In the first post of this series, we examine the basics of Netfilter and Linux kernel modules. In the next post, let’s start implementing the mini firewall. </p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;Background&quot;&gt;&lt;a href=&quot;#Background&quot; class=&quot;headerlink&quot; title=&quot;Background&quot;&gt;&lt;/a&gt;Background&lt;/h3&gt;&lt;p&gt;&lt;code&gt;Firewalls&lt;/code&gt; are an importan</summary>
      
    
    
    
    
    <category term="Linux module, Netfilter, firewall" scheme="https://baoqger.github.io/tags/Linux-module-Netfilter-firewall/"/>
    
  </entry>
  
  <entry>
    <title>Write a Linux packet sniffer from scratch: part two- BPF</title>
    <link href="https://baoqger.github.io/2022/03/28/how-to-implement-libpcap-on-linux-with-raw-socket-part2/"/>
    <id>https://baoqger.github.io/2022/03/28/how-to-implement-libpcap-on-linux-with-raw-socket-part2/</id>
    <published>2022-03-28T06:15:15.000Z</published>
    <updated>2022-04-23T00:30:12.713Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Introduction"><a href="#Introduction" class="headerlink" title="Introduction"></a>Introduction</h3><p>In the <a href="https://organicprogrammer.com/2022/02/22/how-to-implement-libpcap-on-linux-with-raw-socket-part1/">previous article</a>, we examined how to develop a network sniffer with <code>PF_SOCKET</code> socket in Linux platform. The sniffer developed in the last article captures all the network packets. But a powerful network sniffer like <code>tcpdump</code> should provide the packet filtering functionality. For instance, the sniffer can only capture the <code>TCP</code> segment(and skip the UPD), or it can only capture the packets from a specific source IP address. In this article, let’s continue to explore how to do that. </p><h3 id="Background-of-BPF"><a href="#Background-of-BPF" class="headerlink" title="Background of BPF"></a>Background of BPF</h3><p><code>Berkeley Packet Filter(BPF)</code> is the essential underlying technology for packet capture in Unix-like operating systems.<br>Search BPF as the keyword online, and the result is very confusing. It turns out that <code>BPF</code> keeps evolving, and there are several associated concepts such as <code>BPF</code> <code>cBPF</code> <code>eBPF</code> and <code>LSF</code>. So let us examine those concepts along the timeline:</p><ul><li><p>In <strong>1992</strong>, <code>BPF</code> was first introduced to the BSD Unix system for filtering unwanted network packets. The proposal of BPF was from researchers in Lawrence Berkeley Laboratory, who also developed the <code>libpcap</code> and <code>tcpdump</code>. </p></li><li><p>In <strong>1997</strong>, Linux Socket Filter(LSF) was developed based on BPF and introduced in Linux kernel version 2.1.75. Note that <code>LSF</code> and <code>BPF</code> have some distinct differences, but in the Linux context, when we speak of BPF or LSF, we mean the same packet filtering mechanism in the Linux kernel. We’ll examine the detailed theory and design of BPF in the following sections. </p></li><li><p>Originally, BPF was designed as a network packet filter. But in <strong>2013</strong>, BPF was widely extended, and it can be used for non-networking purposes such as performance analysis and troubleshooting. Nowadays, the extended BPF is called <code>eBPF</code>, and the original and obsolete version is renamed to classic BPF (<code>cBPF</code>). <strong>Note that what we examine in this article is cBPF, and eBPF is not inside the scope of this article</strong>. <code>eBPF</code> is the hottest technology in today’s software world, and I’ll talk about it in the future. </p></li></ul><h3 id="Where-to-place-BPF"><a href="#Where-to-place-BPF" class="headerlink" title="Where to place BPF"></a>Where to place BPF</h3><p>The first question to answer is where should we place the filter. The last article examines the path of a received packet  as follows: </p><img src="/images/pf-packet-socket.png" title="PF_PACKET socket" width="400px" height="300px"><p>The best solution to this question is to put the filter as early as possible in the path. Since copying a large amount of data from kernel space to the user space produces a huge overhead, which can influence the system performance a lot. So BPF is a kernel feature. The filter should be triggered immediately when a packet is received at the network interface.As the original BPF <a href="https://www.tcpdump.org/papers/bpf-usenix93.pdf">paper</a> said <strong>To minimize memory traffic, the major bottleneck in most modern system, the packet should be filtered ‘in place’ (e.g., where the network interface DMA engine put it) rather than copied to some other kernel buffer before filtering.</strong><br>Let’s verify this behavior by examining the kernel source code as follows (<strong>Note</strong> the kernel code shown in this article is based on version 2.6, which contains the <code>cBPF</code> implementation.): </p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* source code file of net/packet/af_packet.c */</span></span><br><span class="line"><span class="comment">/* packet_create: create socket */</span></span><br><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">packet_create</span><span class="params">(<span class="keyword">struct</span> net *net, <span class="keyword">struct</span> socket *sock, <span class="type">int</span> protocol)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="comment">/* some code omitted ... */</span></span><br><span class="line">po = pkt_sk(sk);</span><br><span class="line">sk-&gt;sk_family = PF_PACKET;</span><br><span class="line">po-&gt;num = proto;</span><br><span class="line"></span><br><span class="line">spin_lock_init(&amp;po-&gt;bind_lock);</span><br><span class="line">po-&gt;prot_hook.func = packet_rcv; <span class="comment">// attach hook function to socket</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (sock-&gt;type == SOCK_PACKET)</span><br><span class="line">po-&gt;prot_hook.func = packet_rcv_spkt; <span class="comment">// attach hook function to socket</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (proto) &#123;</span><br><span class="line">po-&gt;prot_hook.type = proto;</span><br><span class="line">dev_add_pack(&amp;po-&gt;prot_hook);</span><br><span class="line">sock_hold(sk);</span><br><span class="line">po-&gt;running = <span class="number">1</span>;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>packet_create</code> function handles the socket creation when the application calls the <code>socket</code> system call. In lines 11 and 14, it attaches the hook function to the socket. The hook function executes when the packet is received.</p><p>The following code block shows the hook function <code>packet_rcv</code>:  </p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* hook function packet_rcv is triggered, when the packet is received */</span></span><br><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">packet_rcv</span><span class="params">(<span class="keyword">struct</span> sk_buff *skb, <span class="keyword">struct</span> net_device *dev, <span class="keyword">struct</span> packet_type *pt, <span class="keyword">struct</span> net_device *orig_dev)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="comment">/* some code omitted ... */</span></span><br><span class="line">    sk = pt-&gt;af_packet_priv;</span><br><span class="line">    snaplen = skb-&gt;len;</span><br><span class="line">    res = run_filter(skb, sk, snaplen); <span class="comment">// filter logic</span></span><br><span class="line">    <span class="keyword">if</span> (!res)</span><br><span class="line">    <span class="keyword">goto</span> drop_n_restore; <span class="comment">// drop the packet</span></span><br><span class="line"></span><br><span class="line">    __skb_queue_tail(&amp;sk-&gt;sk_receive_queue, skb); <span class="comment">// put the packet into the queue</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>packet_rcv</code> function calls <code>run_filter</code>, which is just the BPF logic part(Currently, you can regard it as a black box. In the next section, we’ll examine the details). Based on the return value of <code>run_filter</code> the packet can be filtered out or put into the queue. </p><p>So far, you can understand BPF(or the packet filtering) is working inside kernel space. But the packet sniffer is a user-space application. The next question is how to link the filtering rules in user space to the filtering handler in kernel space. </p><p>To answer this question, we have to understand BPF itself. It’s right time to understand this great piece of work. </p><h3 id="BPF-machine"><a href="#BPF-machine" class="headerlink" title="BPF machine"></a>BPF machine</h3><p>As I mentioned above, <code>BPF</code> was introduced in this original <a href="https://www.tcpdump.org/papers/bpf-usenix93.pdf">paper</a> written by researchers from Berkeley. I strongly recommend you read this great paper based on my own experience. In the beginning, I felt crazy to read it, so I read other related documents and tried to understand BPF. But most documents only cover one portion of the entire system, so it is difficult to piece all the information together. Finally, I read the original paper and connected all parts together. <strong>As the saying goes, sometimes taking time is actually a shortcut.</strong></p><h5 id="Virtual-CPU"><a href="#Virtual-CPU" class="headerlink" title="Virtual CPU"></a>Virtual CPU</h5><p>A packet filter is simply a boolean-valued function on a packet. If the value of the function is true the kernel copies the packet for the application; if it is false the packet is ignored. </p><p>In order to be as flexible as possible and not to limit the application to a set of predefined conditions, the <code>BPF</code> is actually implemented as a <code>register-based virtual machine</code> (for the difference between stack-based and register-based virtual machine, you can refer to <a href="http://troubles.md/wasm-is-not-a-stack-machine/">this article</a>) running a user-defined program.  </p><p>You can regard the <code>BPF</code> as a <code>virtual CPU</code>. And it consists of an <code>accumulator</code>, an <code>index register(x)</code>, a scratch memory store, and an implicit <code>program counter</code>. If you’re not familiar with these concepts, I add some simple illustrations as follows:</p><ul><li>An <code>accumulator</code> is a type of register included in a CPU. It acts as a temporary storage location holding an intermediate value in mathematical and logical calculations. For example, in the operation of “1+2+3”, the accumulator would hold the value 1, then the value 3, then the value 6. The benefit of an accumulator is that it does not need to be explicitly referenced.</li><li>An <code>index register</code> in a computer’s CPU is a processor register or assigned memory location used for modifying operand addresses during the run of a program. </li><li>A <code>program counter</code> is a CPU register in the computer processor which has the address of the next instruction to be executed from memory. </li></ul><p>In the BPF machine, the accumulator is used for arithmetic operations, while the index register provides offsets into the packet or the scratch memory areas.  </p><h5 id="Instructions-set-and-addressing-mode"><a href="#Instructions-set-and-addressing-mode" class="headerlink" title="Instructions set and addressing mode"></a>Instructions set and addressing mode</h5><p>Same as the physical CPU, the <code>BPF</code> provides a small set of arithmetic, logical and jump instructions as follows, these instructions run on the BPF virtual machine(or CPU): </p><img src="/images/bpf-instructions.png" title="BPF instructions" width="400px" height="300px"><p>The first column <em>opcodes</em> lists the BPF instructions written in an assembly language style. For example, <strong>ld</strong>, <strong>ldh</strong> and <strong>ldb</strong> means to copy the indicated value into the <code>accumulator</code>. <strong>ldx</strong> means to copy the indicated value into the <code>index register</code>. <strong>jeq</strong> means jump to the target instruction if the <code>accumulator</code> equals the indicated value. <strong>ret</strong> means return the indicated value. You can check the functionality of the instructions set in detail in the paper. </p><p>This kind of assembly-like style is more readable to humans. But when we develop an application (like the sniffer written in this article), we use binary code directly as the BPF instruction. This kind of binary format is called <code>BPF Bytecode</code>. I’ll examine the way to convert this assembly language to bytecode later. </p><p>The second column <em>addr modes</em> lists the addressing modes allowed for each instruction. The semantics of the addressing modes are listed in the following table: </p><img src="/images/address-mode.png" title="BPF instructions address mode" width="400px" height="300px"><p>For instance, <strong>[k]</strong> means the data at byte offset k in the packet. <strong>#k</strong> means the literal value stored in k. You can read the paper in detail to check the meaning of other address modes.  </p><h5 id="Example-BPF-program"><a href="#Example-BPF-program" class="headerlink" title="Example BPF program"></a>Example BPF program</h5><p>Now let’s try to understand the following small BPF program based on the knowledge above: </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">(000) ldh      [12]</span><br><span class="line">(001) jeq      #0x800           jt 2    jf 3</span><br><span class="line">(002) ret      #262144</span><br><span class="line">(003) ret      #0</span><br></pre></td></tr></table></figure><p>The BPF program consists of an array of BPF instructions. For example, the above BPF program contains four instructions. </p><p>The first instruction <strong>ldh</strong> loads a half-word(16-bit) value into the accumulator from offset 12 in the Ethernet packet. According to the Ethernet frame format shown below, the value is just the <code>Ethernet type</code> field. The Ethernet type is used to indicate which protocol is encapsulated in the frame’s payload (for example,  0x0806 for ARP, <strong>0x0800</strong> for IPv4, and 0x86DD for IPv6).</p><img src="/images/ethernet-frame-format.png" title="Ethernet frame fromat" width="600px" height="400px"><p>The second instruction <strong>jeq</strong> compares the accumulator (currently stores <code>Ethernet type</code> field) to <code>0x800</code>(stands for IPv4). If the comparison fails, zero is returned, and the packet is rejected. If it is successful, a non-zero value is returned, and the packet is accepted. <strong>So the small BPF program filters and accepts all IP packets</strong>. You can find other BPF programs in the original paper. Go to read it, and you can feel the flexibility of BPF as well as the beauty of the design. </p><h5 id="Kernel-implementation-of-BPF"><a href="#Kernel-implementation-of-BPF" class="headerlink" title="Kernel implementation of BPF"></a>Kernel implementation of BPF</h5><p>Next, let’s examine how kernel implements BPF. As mentioned above, the hook function <code>packet_rcv</code> calls <code>run_filter</code> to handle the filtering logic. <code>run_filter</code> is defined as follows: </p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Copied from net/packet/af_packet.c */</span></span><br><span class="line"><span class="comment">/* function run_filter is called in packet_rcv*/</span></span><br><span class="line"><span class="type">static</span> <span class="keyword">inline</span> <span class="type">unsigned</span> <span class="type">int</span> <span class="title function_">run_filter</span><span class="params">(<span class="keyword">struct</span> sk_buff *skb, <span class="keyword">struct</span> sock *sk,</span></span><br><span class="line"><span class="params">      <span class="type">unsigned</span> <span class="type">int</span> res)</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">sk_filter</span> *<span class="title">filter</span>;</span></span><br><span class="line"></span><br><span class="line">rcu_read_lock_bh();</span><br><span class="line">filter = rcu_dereference(sk-&gt;sk_filter); <span class="comment">// get the filter bound to the socket</span></span><br><span class="line"><span class="keyword">if</span> (filter != <span class="literal">NULL</span>)</span><br><span class="line">res = sk_run_filter(skb, filter-&gt;insns, filter-&gt;len); <span class="comment">// the filtering is inside sk_run_filter function</span></span><br><span class="line">rcu_read_unlock_bh();</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> res;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>You can find that the real filtering logic is inside <code>sk_run_filter</code>:  </p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">unsigned</span> <span class="type">int</span> <span class="title function_">sk_run_filter</span><span class="params">(<span class="keyword">struct</span> sk_buff *skb, <span class="keyword">struct</span> sock_filter *filter, <span class="type">int</span> flen)</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">sock_filter</span> *<span class="title">fentry</span>;</span><span class="comment">/* We walk down these */</span></span><br><span class="line"><span class="type">void</span> *ptr;</span><br><span class="line">u32 A = <span class="number">0</span>;<span class="comment">/* Accumulator */</span></span><br><span class="line">u32 X = <span class="number">0</span>;<span class="comment">/* Index Register */</span></span><br><span class="line">u32 mem[BPF_MEMWORDS];<span class="comment">/* Scratch Memory Store */</span></span><br><span class="line">u32 tmp;</span><br><span class="line"><span class="type">int</span> k;</span><br><span class="line"><span class="type">int</span> pc;</span><br><span class="line"></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * Process array of filter instructions.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">for</span> (pc = <span class="number">0</span>; pc &lt; flen; pc++) &#123;</span><br><span class="line">fentry = &amp;filter[pc];</span><br><span class="line"></span><br><span class="line"><span class="keyword">switch</span> (fentry-&gt;code) &#123;</span><br><span class="line"><span class="keyword">case</span> BPF_ALU|BPF_ADD|BPF_X:</span><br><span class="line">A += X;</span><br><span class="line"><span class="keyword">continue</span>;</span><br><span class="line"><span class="keyword">case</span> BPF_ALU|BPF_ADD|BPF_K:</span><br><span class="line">A += fentry-&gt;k;</span><br><span class="line"><span class="keyword">continue</span>;</span><br><span class="line"><span class="keyword">case</span> BPF_ALU|BPF_SUB|BPF_X:</span><br><span class="line">A -= X;</span><br><span class="line"><span class="keyword">continue</span>;</span><br><span class="line"><span class="keyword">case</span> BPF_ALU|BPF_SUB|BPF_K:</span><br><span class="line">A -= fentry-&gt;k;</span><br><span class="line"><span class="keyword">continue</span>;</span><br><span class="line"><span class="keyword">case</span> BPF_ALU|BPF_MUL|BPF_X:</span><br><span class="line">A *= X;</span><br><span class="line"><span class="keyword">continue</span>;</span><br><span class="line"><span class="comment">/* some code omitted ... */</span></span><br><span class="line"><span class="keyword">case</span> BPF_RET|BPF_K:</span><br><span class="line"><span class="keyword">return</span> fentry-&gt;k;</span><br><span class="line"><span class="keyword">case</span> BPF_RET|BPF_A:</span><br><span class="line"><span class="keyword">return</span> A;</span><br><span class="line"><span class="keyword">case</span> BPF_ST:</span><br><span class="line">mem[fentry-&gt;k] = A;</span><br><span class="line"><span class="keyword">continue</span>;</span><br><span class="line"><span class="keyword">case</span> BPF_STX:</span><br><span class="line">mem[fentry-&gt;k] = X;</span><br><span class="line"><span class="keyword">continue</span>;</span><br><span class="line"><span class="keyword">default</span>:</span><br><span class="line">WARN_ON(<span class="number">1</span>);</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Same as we mentioned, <code>sk_run_filter</code> is simply a boolean-valued function on a packet. It maintains the accumulator, the index register, etc. as local variables. And process the array of BPF filter instructions in a <code>for</code> loop. Each instruction will update the value of local variables. In this way, it simulates a virtual CPU. Interesting, right? </p><h5 id="BPF-JIT"><a href="#BPF-JIT" class="headerlink" title="BPF JIT"></a>BPF JIT</h5><p>Since each network packet must go through the filtering function, it becomes the performance bottleneck of the entire system. </p><p>A <code>just-in-time (JIT)</code> compiler was introduced into the kernel in <strong>2011</strong> to speed up BPF bytecode execution. </p><ul><li>What is a <code>JIT</code> compiler? A <code>JIT</code> compiler runs <strong>after</strong> the program has started and compiles the code(usually bytecode or some type of VM instructions) on the fly(or just in time) into a form that’s usually faster, typically the host CPU’s native instruction set. This is in contrast to a <code>traditional compiler</code> that compiles all the code to machine language <strong>before</strong> the program is first run. </li></ul><p>In the <code>BPF</code> case, the <code>JIT</code> compiler translates BPF bytecode into a host system’s assembly code directly, which can optimize the performance a lot. I’ll not show details about JIT in this article. You can refer to the <a href="https://elixir.bootlin.com/linux/v3.19.8/source/arch/arm/net/bpf_jit_32.c#L868">kernel code</a>.  </p><h3 id="Set-BPF-in-sniffer"><a href="#Set-BPF-in-sniffer" class="headerlink" title="Set BPF in sniffer"></a>Set BPF in sniffer</h3><p>Next, let’s add BPF into our packet sniffer. As we mentioned above in the application level, the BPF instructions should use bytecode format with the following data structure:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">sock_filter</span> &#123;</span>    <span class="comment">/* Filter block */</span></span><br><span class="line">        __u16   code;   <span class="comment">/* Actual filter code */</span></span><br><span class="line">        __u8    jt;     <span class="comment">/* Jump true */</span></span><br><span class="line">        __u8    jf;     <span class="comment">/* Jump false */</span></span><br><span class="line">        __u32   k;      <span class="comment">/* Generic multiuse field */</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>How can we convert the BPF assembly language into bytecode? There are two solutions. First, there is a small helper tool called <code>bpf_asm</code>(which is provided along with the Linux kernel), and you can regard it as the BPF assembly language interpreter. But it is not recommended to application developers. </p><p>Second, we can use <code>tcpdump</code>, which provides the converting functionality. You can find the following information from the tcpdump man page: </p><ul><li><p>-d:   Dump the compiled packet-matching code in a human-readable form to standard output and stop.</p></li><li><p>-dd:  Dump packet-matching code as a C program fragment.</p></li><li><p>-ddd: Dump packet-matching code as decimal numbers (preceded with a count).</p></li></ul><p><code>tcpdump ip</code> means we want to capture all the IP packets. With options <strong>-d</strong>, <strong>-dd</strong> and <strong>-ddd</strong>, the output goes as follows: </p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">baoqger@ubuntu:~$ sudo tcpdump -d ip</span><br><span class="line">[sudo] password <span class="keyword">for</span> baoqger:</span><br><span class="line">(000) ldh      [12]</span><br><span class="line">(001) jeq      <span class="comment">#0x800           jt 2    jf 3</span></span><br><span class="line">(002) ret      <span class="comment">#262144</span></span><br><span class="line">(003) ret      <span class="comment">#0</span></span><br><span class="line"></span><br><span class="line">baoqger@SLB-C8JWZH3:~$ sudo tcpdump -<span class="built_in">dd</span> ip</span><br><span class="line">&#123; 0x28, 0, 0, 0x0000000c &#125;,</span><br><span class="line">&#123; 0x15, 0, 1, 0x00000800 &#125;,</span><br><span class="line">&#123; 0x6, 0, 0, 0x00040000 &#125;,</span><br><span class="line">&#123; 0x6, 0, 0, 0x00000000 &#125;,</span><br><span class="line"></span><br><span class="line">baoqger@SLB-C8JWZH3:~$ sudo tcpdump -ddd ip</span><br><span class="line">4</span><br><span class="line">40 0 0 12</span><br><span class="line">21 0 1 2048</span><br><span class="line">6 0 0 262144</span><br><span class="line">6 0 0 0</span><br></pre></td></tr></table></figure><p>Option <strong>-d</strong> prints the BPF instructions in assembly language (same as the example BPF program shown above). Options <strong>-dd</strong> prints the bytecode as a C program fragment. <strong>So tcpdump is the most convenient tool when you want to get the BPF bytecode</strong>.</p><p>The BPF filter bytecode (wrapped in the structure <code>sock_fprog</code>) can be passed to the kernel through <code>setsockopt</code> system call as follows: </p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// attach the filter to the socket</span></span><br><span class="line"><span class="comment">// the filter code is generated by running: tcpdump tcp</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">sock_filter</span> <span class="title">BPF_code</span>[] =</span> &#123;</span><br><span class="line">&#123; <span class="number">0x28</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0x0000000c</span> &#125;,</span><br><span class="line">&#123; <span class="number">0x15</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">0x00000800</span> &#125;,</span><br><span class="line">&#123; <span class="number">0x6</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0x00040000</span> &#125;,</span><br><span class="line">&#123; <span class="number">0x6</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0x00000000</span> &#125;</span><br><span class="line">&#125;;    </span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">sock_fprog</span> <span class="title">Filter</span>;</span></span><br><span class="line"><span class="comment">// error prone code, .len field should be consistent with the real length of the filter code array</span></span><br><span class="line">Filter.len = <span class="keyword">sizeof</span>(BPF_code)/<span class="keyword">sizeof</span>(BPF_code[<span class="number">0</span>]); </span><br><span class="line">Filter.filter = BPF_code;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &amp;Filter, <span class="keyword">sizeof</span>(Filter)) &lt; <span class="number">0</span>) &#123;</span><br><span class="line">perror(<span class="string">&quot;setsockopt attach filter&quot;</span>);</span><br><span class="line">close(sock);</span><br><span class="line"><span class="built_in">exit</span>(<span class="number">1</span>);</span><br><span class="line">&#125; </span><br></pre></td></tr></table></figure><p><code>setsockopt</code> system call triggers two kernel functions: <code>sock_setsockopt</code> and <code>sk_attach_filter</code> (I’ll not show the details for these two functions), which <strong>binds the filters to the socket</strong>. And in <code>run_filter</code> kernel function (mentioned above), it can <strong>get the filters from the socket</strong> and <strong>execute the filters on the packet</strong>. </p><p>So far, every piece is connected. The puzzle of BPF is solved. The <code>BPF</code> machine allows the user-space applications to inject customized BPF programs straight into a kernel. Once loaded and verified, BPF programs execute in kernel context. These BPF programs operate inside kernel memory space with access to all the internal kernel states available to it. For example, the <code>cBPF</code> machine which uses the network packet data. But this power can be extended as <code>eBPF</code>, which can be used in many other varied applications. As someone <a href="https://www.brendangregg.com/bpf-performance-tools-book.html">said</a> <strong>In some way, eBPF does to the kernel what Javascript does to the websites: it allows all sorts of new application to be created.</strong>  In the future, I plan to examine eBPF in depth. </p><img src="/images/bpf-run-instructions.png" title="BPF Run Instructions" width="600px" height="400px"><h3 id="Process-the-packet"><a href="#Process-the-packet" class="headerlink" title="Process the packet"></a>Process the packet</h3><p>We examined the <code>BPF</code> filtering theory on the kernel level a lot in the above section. But for our tiny sniffer, the last step we need to do is process the network packet. </p><ul><li><p>First, the <code>recvfrom</code> system call reads the packet from the socket. And we put the system call in a <code>while</code> loop to keep reading the incoming packets. </p></li><li><p>Then, we print the source and destination <code>MAC</code> address in the packet(the packet we got is a raw Ethernet frame in Layer 2, right?). And if what this Ethernet frame contains is an <code>IP4</code> packet, then we print out the source and destination <code>IP</code> address. To understand more about it, you can study the header format of various network protocols. I will not cover in details here.</p></li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">while</span>(<span class="number">1</span>) &#123;</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;-----------\n&quot;</span>);</span><br><span class="line">n = recvfrom(sock, buffer, <span class="number">2048</span>, <span class="number">0</span>, <span class="literal">NULL</span>, <span class="literal">NULL</span>);</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;%d bytes read\n&quot;</span>, n);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* Check to see if the packet contains at least</span></span><br><span class="line"><span class="comment">* complete Ethernet (14), IP (20) and TCP/UDP</span></span><br><span class="line"><span class="comment">* (8) headers.</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="keyword">if</span> (n &lt; <span class="number">42</span>) &#123;</span><br><span class="line">perror(<span class="string">&quot;recvfrom():&quot;</span>);</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;Incomplete packet (errno is %d)\n&quot;</span>, errno);</span><br><span class="line">close(sock);</span><br><span class="line"><span class="built_in">exit</span>(<span class="number">0</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">ethhead = buffer;</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;Source MAC address: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n&quot;</span>,</span><br><span class="line">ethhead[<span class="number">0</span>], ethhead[<span class="number">1</span>], ethhead[<span class="number">2</span>], ethhead[<span class="number">3</span>], ethhead[<span class="number">4</span>], ethhead[<span class="number">5</span>]</span><br><span class="line">);</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;Destination MAC address: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n&quot;</span>,</span><br><span class="line">ethhead[<span class="number">6</span>], ethhead[<span class="number">7</span>], ethhead[<span class="number">8</span>], ethhead[<span class="number">9</span>], ethhead[<span class="number">10</span>], ethhead[<span class="number">11</span>]</span><br><span class="line">);</span><br><span class="line"></span><br><span class="line">iphead = buffer + <span class="number">14</span>; </span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (*iphead==<span class="number">0x45</span>) &#123; <span class="comment">/* Double check for IPv4</span></span><br><span class="line"><span class="comment">* and no options present */</span></span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;Source host %d.%d.%d.%d\n&quot;</span>,</span><br><span class="line">iphead[<span class="number">12</span>],iphead[<span class="number">13</span>],</span><br><span class="line">iphead[<span class="number">14</span>],iphead[<span class="number">15</span>]);</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;Dest host %d.%d.%d.%d\n&quot;</span>,</span><br><span class="line">iphead[<span class="number">16</span>],iphead[<span class="number">17</span>],</span><br><span class="line">iphead[<span class="number">18</span>],iphead[<span class="number">19</span>]);</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;Source,Dest ports %d,%d\n&quot;</span>,</span><br><span class="line">(iphead[<span class="number">20</span>]&lt;&lt;<span class="number">8</span>)+iphead[<span class="number">21</span>],</span><br><span class="line">(iphead[<span class="number">22</span>]&lt;&lt;<span class="number">8</span>)+iphead[<span class="number">23</span>]);</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;Layer-4 protocol %s\n&quot;</span>, transport_protocol(iphead[<span class="number">9</span>]));</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>You can find the complete source code of the sniffer in this Github <a href="https://github.com/baoqger/raw-socket-packet-capture-/blob/master/raw_socket.c">repo</a>.</p><h3 id="Summary"><a href="#Summary" class="headerlink" title="Summary"></a>Summary</h3><p>In this article, we examine how to add filters to our sniffer. First, we analyze why the filter should be running inside kernel space instead of the application space. Then, this article examines the <code>BPF</code> machine design and implementation in detail based on the paper. We reviewed the kernel source code to understand how to implement the <code>BPF</code> virtual machine. As I mentioned above, the original <code>BPF</code>(<code>cBPF</code>) was extended to <code>eBPF</code> now. But the understanding of the BPF virtual machine is very helpful to <code>eBPF</code> as well.   </p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;Introduction&quot;&gt;&lt;a href=&quot;#Introduction&quot; class=&quot;headerlink&quot; title=&quot;Introduction&quot;&gt;&lt;/a&gt;Introduction&lt;/h3&gt;&lt;p&gt;In the &lt;a href=&quot;https://organi</summary>
      
    
    
    
    
    <category term="BPF, JIT, virtual machine" scheme="https://baoqger.github.io/tags/BPF-JIT-virtual-machine/"/>
    
  </entry>
  
  <entry>
    <title>Write a Linux packet sniffer from scratch: part one- PF_PACKET socket and promiscuous mode</title>
    <link href="https://baoqger.github.io/2022/02/22/how-to-implement-libpcap-on-linux-with-raw-socket-part1/"/>
    <id>https://baoqger.github.io/2022/02/22/how-to-implement-libpcap-on-linux-with-raw-socket-part1/</id>
    <published>2022-02-22T02:21:14.000Z</published>
    <updated>2022-04-23T00:31:15.818Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Background"><a href="#Background" class="headerlink" title="Background"></a>Background</h3><p>When we refer to network packet sniffer, some famous and popular tools come to your mind, like <code>tcpdump</code>. I have shown you how to capture network packets with such tools in my previous articles. But have you ever thought about writing a packet sniffer from scratch without dependencies on any third-party libraries? We need to dig deep into the operating system and find the weapons needed to build this tool. Sounds complex, right? In this article, let us do it. After reading this article, you can find that it is not as difficult as you think. </p><p>Note that different operating system kernels have different internal network implementations. This article will focus on the <code>Linux</code> platform. </p><h3 id="Introduction"><a href="#Introduction" class="headerlink" title="Introduction"></a>Introduction</h3><p>Firstly, we need to review how <code>tcpdump</code> is implemented. According to the official <a href="https://www.tcpdump.org/">document</a>, <code>tcpdump</code> is built on the library <code>libpcap</code>, which is developed based on the remarkable research result from Berkeley, in details you can refer to <a href="https://www.tcpdump.org/papers/bpf-usenix93.pdf">this paper</a>.</p><p>As you know, different operating systems have different internal implementations of network stacks. <code>libpcap</code> covers all of these differences and provides the system-independent interface for user-level packet capture. I want to focus on the Linux platform, so how does <code>libpcap</code> work on the Linux system? According to some <a href="https://stackoverflow.com/questions/21200009/capturing-performance-with-pcap-vs-raw-socket">documents</a>, it turns out that libpcap uses the <code>PF_PACKET</code> socket to capture packets on a network interface.</p><p>So the next question is: what the <code>PF_PACKET</code> socket is? </p><h3 id="PF-PACKET-socket"><a href="#PF-PACKET-socket" class="headerlink" title="PF_PACKET socket"></a>PF_PACKET socket</h3><p>In my previous <a href="https://organicprogrammer.com/2021/07/31/how-to-implement-simple-http-server-golang/">article</a>, we mentioned that the socket interface is TCP/IP’s window on the world. In most modern systems incorporating TCP/IP, the socket interface is the only way applications can use the TCP/IP suite of protocols. </p><img src="/images/pf-packet-socket.png" title="PF_PACKET socket" width="400px" height="300px"><p>It is correct. This time, let’s dig deeper about <code>socket</code> by examining the system call executed when we create a new socket: </p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">socket</span><span class="params">(<span class="type">int</span> domain, <span class="type">int</span> type, <span class="type">int</span> protocol)</span>;</span><br></pre></td></tr></table></figure><p>When you want to create a socket with the above system call, you have to specify which domain (or protocol family) you want to use with that socket as the first argument. The most commonly used family is <code>PF_INET</code>, which is for communications based on IPv4 protocols (when you create a TCP server, you use this family). Moreover, you have to specify a type for your socket as the second argument. And the possible values depend on the family you specified. For example, when dealing with the <code>PF_INET</code> family, the values for type include <code>SOCK_STREAM</code>(for TCP) and <code>SOCK_DGRAM</code>(for UDP). For other detailed information about the socket system call, you can refer to the socket(3) man page. </p><p>You can find one potential value for the <code>domain</code> argument as follows:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">AF_PACKET    Low-level packet interface</span><br></pre></td></tr></table></figure><p><strong>Note</strong>: <code>AF_PACKET</code> and <code>PF_PACKET</code> are same. It is called <code>PF_PACKET</code> in history and then renamed  <code>AF_PACKET</code> later. <code>PF</code> means protocol families, and <code>AF</code> means address families. In this article, I use <code>PF_PACKET</code>. </p><p>Different from <code>PF_INET</code> socket, which can give you TCP segment. By <code>PF_PACKET</code> socket, you can get the raw <code>Ethernet</code> frame which bypasses the usual upper layer handling of TCP/IP stack. It might sound a little bit crazy. But, that is, any packet received will be directly passed to the application. </p><p>For a better understanding of <code>PF_PACKET</code> socket, let us go deeper and roughly examine the path of a received packet from the network interface to the application level. </p><p>(As shown in the image above) When the network interface card(NIC) receives a packet, it is handled by the driver. The driver maintains a structure called <code>ring buffer</code> internally. And write the packet to kernel memory (the memory is pre-allocated with ring buffer)  with direct memory access(DMA). The packet is placed inside a structure called <strong><code>sk_buff</code></strong>(one of the most important structures related to kernel network subsystem).   </p><p>After entering the kernel space, the packet goes through protocol stack handling layer by layer, such as <code>IP processing</code> and <code>TCP/UDP processing</code>. And the packet goes into applications via the socket interface. You already understand this familiar path very well.</p><p>But for the <code>PF_PACKET</code> socket, the packet in <code>sk_buff</code> is cloned, then it skips the protocol stacks and directly goes to the application. The kernel needs the clone operation, because one copy is consumed by the <code>PF_PACKET</code> socket, and the other one goes through the usual protocol stacks.</p><p>In future articles, I’ll demonstrate more about Linux kernel network internals.</p><p>Next step, let us see how to create a <code>PF_PACKET</code> socket at the code level. For brevity, I omit some code and only show the essential part. You can refer to this Github <a href="https://github.com/baoqger/raw-socket-packet-capture-/blob/master/raw_socket.c">repo</a> in detail.  </p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> ((sock = <span class="built_in">socket</span>(PF_PACKET, SOCK_RAW, <span class="built_in">htons</span>(ETH_P_IP))) &lt; <span class="number">0</span>) &#123;</span><br><span class="line">    <span class="built_in">perror</span>(<span class="string">&quot;socket&quot;</span>);</span><br><span class="line">    <span class="built_in">exit</span>(<span class="number">1</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Please ensure to include the system header files: <code>&lt;sys/socket.h&gt; &lt;sys/types.h&gt;</code>. </p><h3 id="Bind-to-one-network-interface"><a href="#Bind-to-one-network-interface" class="headerlink" title="Bind to one network interface"></a>Bind to one network interface</h3><p>Without the additional settings, the sniffer captures all the packets received on all the network devices. Next step, let us try to bind the sniffer to a specific network device. </p><p>Firstly, you can use <code>ifconfig</code> command to list all the available <code>network interfaces</code> on your machines. The network interface is a software interface to the networking hardware. </p><p>For example, the following image shows information of network interface <code>eth0</code>: </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">eth0: flags=4163&lt;UP,BROADCAST,RUNNING,MULTICAST&gt;  mtu 1500</span><br><span class="line">        inet 192.168.230.49  netmask 255.255.240.0  broadcast 192.168.239.255</span><br><span class="line">        inet6 fe80::215:5dff:fefb:e31f  prefixlen 64  scopeid 0x20&lt;link&gt;</span><br><span class="line">        ether 00:15:5d:fb:e3:1f  txqueuelen 1000  (Ethernet)</span><br><span class="line">        RX packets 260  bytes 87732 (87.7 KB)</span><br><span class="line">        RX errors 0  dropped 0  overruns 0  frame 0</span><br><span class="line">        TX packets 178  bytes 29393 (29.3 KB)</span><br><span class="line">        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0</span><br></pre></td></tr></table></figure><p>Let’s bind the sniffer to <code>eth0</code> as follows:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// bind to eth0 interface only</span></span><br><span class="line"><span class="type">const</span> <span class="type">char</span> *opt;</span><br><span class="line">opt = <span class="string">&quot;eth0&quot;</span>;</span><br><span class="line"><span class="keyword">if</span> (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, opt, <span class="built_in">strlen</span>(opt) + <span class="number">1</span>) &lt; <span class="number">0</span>) &#123;</span><br><span class="line">    perror(<span class="string">&quot;setsockopt bind device&quot;</span>);</span><br><span class="line">    close(sock);</span><br><span class="line">    <span class="built_in">exit</span>(<span class="number">1</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>We do it by calling the <code>setsockopt</code> system call. I leave the detailed usage of it to you. </p><p>Now the sniffer only captures network packets received on the specified network card. </p><h3 id="Non-promiscuous-and-promiscuous-mode"><a href="#Non-promiscuous-and-promiscuous-mode" class="headerlink" title="Non-promiscuous and promiscuous mode"></a>Non-promiscuous and promiscuous mode</h3><p>By default, each network card minds its own business and reads only the frames directed to it. It means that the network card discards all the packets that do not contain its own MAC address, which is called <code>non-promiscuous</code> mode. </p><p>Next, let us make the sniffer can work in <code>promiscuous</code> mode. In this way, it retrieves all the data packets. Even the ones that are not addressed to its host. </p><p>To set a network interface to promiscuous mode, all we have to do is issue the <code>ioctl()</code> system call to an open socket on that interface.</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* set the network card in promiscuos mode*/</span></span><br><span class="line"><span class="comment">// An ioctl() request has encoded in it whether the argument is an in parameter or out parameter</span></span><br><span class="line"><span class="comment">// SIOCGIFFLAGS0x8913/* get flags*/</span></span><br><span class="line"><span class="comment">// SIOCSIFFLAGS0x8914/* set flags*/</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">ifreq</span> <span class="title">ethreq</span>;</span></span><br><span class="line"><span class="built_in">strncpy</span>(ethreq.ifr_name, <span class="string">&quot;eth0&quot;</span>, IF_NAMESIZE);</span><br><span class="line"><span class="keyword">if</span> (ioctl(sock, SIOCGIFFLAGS, &amp;ethreq) == <span class="number">-1</span>) &#123;</span><br><span class="line">    perror(<span class="string">&quot;ioctl&quot;</span>);</span><br><span class="line">    close(sock);</span><br><span class="line">    <span class="built_in">exit</span>(<span class="number">1</span>);</span><br><span class="line">&#125;</span><br><span class="line">ethreq.ifr_flags |= IFF_PROMISC;</span><br><span class="line"><span class="keyword">if</span> (ioctl(sock, SIOCSIFFLAGS, &amp;ethreq) == <span class="number">-1</span>) &#123;</span><br><span class="line">    perror(<span class="string">&quot;ioctl&quot;</span>);</span><br><span class="line">    close(sock);</span><br><span class="line">    <span class="built_in">exit</span>(<span class="number">1</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>ioctl</code> stands for <strong>I/O control</strong>, which manipulates the underlying device parameters of specific files. <code>ioctl</code> takes three arguments: </p><ul><li>The first argument must be an open file descriptor. We use the socket file descriptor bound to the network interface in our case.</li><li>The second argument is a device-dependent request code. You can see we called <code>ioctl</code> twice. The first call uses request code <em>SIOC<strong>G</strong>IFFLAGS</em> to get flags, and the second call uses request code <em>SIOC<strong>S</strong>IFFLAGS</em> to set flags. Do not be fooled by these two constant values, which are spelled alike.</li><li>The third argument is for returning information to the requesting process.  </li></ul><p>Now the sniffer can retrieve all the data packets received on the network card, no matter to which host the packets are addressed.</p><h3 id="Summary"><a href="#Summary" class="headerlink" title="Summary"></a>Summary</h3><p>This article examined what <code>PF_PACKET</code> socket is, how it works and why the application can get raw Ethernet packets. Furthermore, we discussed how to bind the sniffer to one specific network interface and how can make the sniffer work in the promiscuous mode. The next article will examine how to implement the packet filter functionality, which is very useful to a network sniffer. </p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;Background&quot;&gt;&lt;a href=&quot;#Background&quot; class=&quot;headerlink&quot; title=&quot;Background&quot;&gt;&lt;/a&gt;Background&lt;/h3&gt;&lt;p&gt;When we refer to network packet sniffe</summary>
      
    
    
    
    
    <category term="packet sniffer, socket, PF_PACKET" scheme="https://baoqger.github.io/tags/packet-sniffer-socket-PF-PACKET/"/>
    
  </entry>
  
  <entry>
    <title>stack-smashing-detect-in-c</title>
    <link href="https://baoqger.github.io/2022/02/07/stack-smashing-detect-in-c/"/>
    <id>https://baoqger.github.io/2022/02/07/stack-smashing-detect-in-c/</id>
    <published>2022-02-07T05:12:08.000Z</published>
    <updated>2022-02-07T05:12:08.929Z</updated>
    
    
    
    
    
  </entry>
  
  <entry>
    <title>how-to-implement-arp-spoof</title>
    <link href="https://baoqger.github.io/2022/01/28/how-to-implement-arp-spoof/"/>
    <id>https://baoqger.github.io/2022/01/28/how-to-implement-arp-spoof/</id>
    <published>2022-01-28T09:29:48.000Z</published>
    <updated>2022-01-28T09:29:48.225Z</updated>
    
    
    
    
    
  </entry>
  
  <entry>
    <title>extern-in-c</title>
    <link href="https://baoqger.github.io/2022/01/20/extern-in-c/"/>
    <id>https://baoqger.github.io/2022/01/20/extern-in-c/</id>
    <published>2022-01-20T03:47:18.000Z</published>
    <updated>2022-01-20T03:47:18.108Z</updated>
    
    
    
    
    
  </entry>
  
  <entry>
    <title>md5-implementation</title>
    <link href="https://baoqger.github.io/2022/01/12/md5-implementation/"/>
    <id>https://baoqger.github.io/2022/01/12/md5-implementation/</id>
    <published>2022-01-12T09:33:01.000Z</published>
    <updated>2022-01-12T09:33:01.060Z</updated>
    
    
    
    
    
  </entry>
  
  <entry>
    <title>how-traceroute-works</title>
    <link href="https://baoqger.github.io/2021/12/24/how-traceroute-works/"/>
    <id>https://baoqger.github.io/2021/12/24/how-traceroute-works/</id>
    <published>2021-12-24T14:08:39.000Z</published>
    <updated>2021-12-24T14:08:39.488Z</updated>
    
    
    
    
    
  </entry>
  
  <entry>
    <title>How  HTTP1.1 protocol is implemented in Golang net/http package: part two -  write HTTP message to socket</title>
    <link href="https://baoqger.github.io/2021/12/15/understand-http-1-1-client-golang-part2/"/>
    <id>https://baoqger.github.io/2021/12/15/understand-http-1-1-client-golang-part2/</id>
    <published>2021-12-15T06:01:03.000Z</published>
    <updated>2021-12-23T12:34:34.799Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Background"><a href="#Background" class="headerlink" title="Background"></a>Background</h3><p>In the <a href="https://baoqger.github.io/2021/12/01/understand-http1-1-client-golang/">previous</a> article, I introduced the main workflow of an HTTP request implemented inside Golang <code>net/http</code> package. As the second article of this series, I’ll focus on how to pass the HTTP message to TCP/IP stack, and then it can be transported over the network. </p><h3 id="Architecture-diagram"><a href="#Architecture-diagram" class="headerlink" title="Architecture diagram"></a>Architecture diagram</h3><p>When the client application sends an HTTP request, it determines what is next step based on whether there is an available persistent connection in the cached connection pool. If no, then a new TCP connection will be established. If yes, then a persistent connection will be selected. </p><p>The details of the connection pool is not in this article’s scope. I’ll discuss it in the next article. For now you can regard it as a block box. </p><p>The overall diagram of this article goes as follows, we can review each piece of it in the below sections</p><img src="/images/golang-http1-1-flow-write-socket.png" title="write to socket" width="800px" height="600px"><h3 id="persistConn"><a href="#persistConn" class="headerlink" title="persistConn"></a>persistConn</h3><p>The key structure in this part is <code>persistConn</code>: </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> persistConn <span class="keyword">struct</span> &#123;</span><br><span class="line">alt RoundTripper</span><br><span class="line">t         *Transport</span><br><span class="line">cacheKey  connectMethodKey</span><br><span class="line">conn      net.Conn            <span class="comment">// underlying TCP connection</span></span><br><span class="line">tlsState  *tls.ConnectionState</span><br><span class="line">br        *bufio.Reader       </span><br><span class="line">bw        *bufio.Writer       <span class="comment">// buffer io for writing data</span></span><br><span class="line">nwrite    <span class="type">int64</span>               </span><br><span class="line">reqch     <span class="keyword">chan</span> requestAndChan </span><br><span class="line">writech   <span class="keyword">chan</span> writeRequest   <span class="comment">// channel for writing request</span></span><br><span class="line">closech   <span class="keyword">chan</span> <span class="keyword">struct</span>&#123;&#125;      </span><br><span class="line">isProxy   <span class="type">bool</span></span><br><span class="line">sawEOF    <span class="type">bool</span>  </span><br><span class="line">readLimit <span class="type">int64</span> </span><br><span class="line">writeErrCh <span class="keyword">chan</span> <span class="type">error</span></span><br><span class="line">writeLoopDone <span class="keyword">chan</span> <span class="keyword">struct</span>&#123;&#125; </span><br><span class="line">idleAt    time.Time   </span><br><span class="line">idleTimer *time.Timer </span><br><span class="line">mu                   sync.Mutex </span><br><span class="line">numExpectedResponses <span class="type">int</span></span><br><span class="line">closed               <span class="type">error</span> </span><br><span class="line">canceledErr          <span class="type">error</span> </span><br><span class="line">broken               <span class="type">bool</span> </span><br><span class="line">reused               <span class="type">bool</span>  </span><br><span class="line">mutateHeaderFunc <span class="function"><span class="keyword">func</span><span class="params">(Header)</span></span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>There are many fields defined in <code>persistConn</code>, but we can focus on these three: </p><ul><li><code>conn</code>: type of <code>net.Conn</code> which defines TCP connection in Golang;</li><li><code>bw</code>: type of <code>*bufio.Writer</code> which implements <code>buffer io</code> functionality;</li><li><code>writech</code>: type of <code>channel</code> which is used to communicate and sync data among different Goroutines in Golang.</li></ul><p>In next sections, let’s investigate how <code>persistConn</code> is used to write HTTP message to socket. </p><h3 id="New-connection"><a href="#New-connection" class="headerlink" title="New connection"></a>New connection</h3><p>First, let’s see how to establish a new TCP connection and bind it to <code>persistConn</code> structure. The job is done inside <strong>dialConn</strong> method of <strong>Transport</strong></p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// dialConn in transport.go file</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(t *Transport)</span></span> dialConn(ctx context.Context, cm connectMethod) (pconn *persistConn, err <span class="type">error</span>) &#123;</span><br><span class="line"><span class="comment">// construct a new persistConn</span></span><br><span class="line">pconn = &amp;persistConn&#123;</span><br><span class="line">t:             t,</span><br><span class="line">cacheKey:      cm.key(),</span><br><span class="line">reqch:         <span class="built_in">make</span>(<span class="keyword">chan</span> requestAndChan, <span class="number">1</span>),</span><br><span class="line">writech:       <span class="built_in">make</span>(<span class="keyword">chan</span> writeRequest, <span class="number">1</span>),</span><br><span class="line">closech:       <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="keyword">struct</span>&#123;&#125;),</span><br><span class="line">writeErrCh:    <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="type">error</span>, <span class="number">1</span>),</span><br><span class="line">writeLoopDone: <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="keyword">struct</span>&#123;&#125;),</span><br><span class="line">&#125;</span><br><span class="line">trace := httptrace.ContextClientTrace(ctx)</span><br><span class="line">wrapErr := <span class="function"><span class="keyword">func</span><span class="params">(err <span class="type">error</span>)</span></span> <span class="type">error</span> &#123;</span><br><span class="line"><span class="keyword">if</span> cm.proxyURL != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span> &amp;net.OpError&#123;Op: <span class="string">&quot;proxyconnect&quot;</span>, Net: <span class="string">&quot;tcp&quot;</span>, Err: err&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> err</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> cm.scheme() == <span class="string">&quot;https&quot;</span> &amp;&amp; t.hasCustomTLSDialer() &#123;</span><br><span class="line"><span class="keyword">var</span> err <span class="type">error</span></span><br><span class="line"><span class="comment">// dial secure TCP connection, assign to field pconn.conn</span></span><br><span class="line">pconn.conn, err = t.customDialTLS(ctx, <span class="string">&quot;tcp&quot;</span>, cm.addr())</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, wrapErr(err)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> tc, ok := pconn.conn.(*tls.Conn); ok &#123;</span><br><span class="line"><span class="keyword">if</span> trace != <span class="literal">nil</span> &amp;&amp; trace.TLSHandshakeStart != <span class="literal">nil</span> &#123;</span><br><span class="line">trace.TLSHandshakeStart()</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> err := tc.Handshake(); err != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">go</span> pconn.conn.Close()</span><br><span class="line"><span class="keyword">if</span> trace != <span class="literal">nil</span> &amp;&amp; trace.TLSHandshakeDone != <span class="literal">nil</span> &#123;</span><br><span class="line">trace.TLSHandshakeDone(tls.ConnectionState&#123;&#125;, err)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, err</span><br><span class="line">&#125;</span><br><span class="line">cs := tc.ConnectionState()</span><br><span class="line"><span class="keyword">if</span> trace != <span class="literal">nil</span> &amp;&amp; trace.TLSHandshakeDone != <span class="literal">nil</span> &#123;</span><br><span class="line">trace.TLSHandshakeDone(cs, <span class="literal">nil</span>)</span><br><span class="line">&#125;</span><br><span class="line">pconn.tlsState = &amp;cs</span><br><span class="line">&#125;</span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line"><span class="comment">// dial TCP connection</span></span><br><span class="line">conn, err := t.dial(ctx, <span class="string">&quot;tcp&quot;</span>, cm.addr())</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, wrapErr(err)</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// assign to pconn.conn</span></span><br><span class="line">pconn.conn = conn</span><br><span class="line"><span class="keyword">if</span> cm.scheme() == <span class="string">&quot;https&quot;</span> &#123;</span><br><span class="line"><span class="keyword">var</span> firstTLSHost <span class="type">string</span></span><br><span class="line"><span class="keyword">if</span> firstTLSHost, _, err = net.SplitHostPort(cm.addr()); err != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, wrapErr(err)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> err = pconn.addTLS(firstTLSHost, trace); err != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, wrapErr(err)</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">switch</span> &#123;</span><br><span class="line"><span class="keyword">case</span> cm.proxyURL == <span class="literal">nil</span>:</span><br><span class="line"><span class="keyword">case</span> cm.proxyURL.Scheme == <span class="string">&quot;socks5&quot;</span>:</span><br><span class="line">conn := pconn.conn</span><br><span class="line">d := socksNewDialer(<span class="string">&quot;tcp&quot;</span>, conn.RemoteAddr().String())</span><br><span class="line"><span class="keyword">if</span> u := cm.proxyURL.User; u != <span class="literal">nil</span> &#123;</span><br><span class="line">auth := &amp;socksUsernamePassword&#123;</span><br><span class="line">Username: u.Username(),</span><br><span class="line">&#125;</span><br><span class="line">auth.Password, _ = u.Password()</span><br><span class="line">d.AuthMethods = []socksAuthMethod&#123;</span><br><span class="line">socksAuthMethodNotRequired,</span><br><span class="line">socksAuthMethodUsernamePassword,</span><br><span class="line">&#125;</span><br><span class="line">d.Authenticate = auth.Authenticate</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> _, err := d.DialWithConn(ctx, conn, <span class="string">&quot;tcp&quot;</span>, cm.targetAddr); err != <span class="literal">nil</span> &#123;</span><br><span class="line">conn.Close()</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, err</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">case</span> cm.targetScheme == <span class="string">&quot;http&quot;</span>:</span><br><span class="line">pconn.isProxy = <span class="literal">true</span></span><br><span class="line"><span class="keyword">if</span> pa := cm.proxyAuth(); pa != <span class="string">&quot;&quot;</span> &#123;</span><br><span class="line">pconn.mutateHeaderFunc = <span class="function"><span class="keyword">func</span><span class="params">(h Header)</span></span> &#123;</span><br><span class="line">h.Set(<span class="string">&quot;Proxy-Authorization&quot;</span>, pa)</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">case</span> cm.targetScheme == <span class="string">&quot;https&quot;</span>:</span><br><span class="line">conn := pconn.conn</span><br><span class="line">hdr := t.ProxyConnectHeader</span><br><span class="line"><span class="keyword">if</span> hdr == <span class="literal">nil</span> &#123;</span><br><span class="line">hdr = <span class="built_in">make</span>(Header)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> pa := cm.proxyAuth(); pa != <span class="string">&quot;&quot;</span> &#123;</span><br><span class="line">hdr = hdr.Clone()</span><br><span class="line">hdr.Set(<span class="string">&quot;Proxy-Authorization&quot;</span>, pa)</span><br><span class="line">&#125;</span><br><span class="line">connectReq := &amp;Request&#123;</span><br><span class="line">Method: <span class="string">&quot;CONNECT&quot;</span>,</span><br><span class="line">URL:    &amp;url.URL&#123;Opaque: cm.targetAddr&#125;,</span><br><span class="line">Host:   cm.targetAddr,</span><br><span class="line">Header: hdr,</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">connectCtx := ctx</span><br><span class="line"><span class="keyword">if</span> ctx.Done() == <span class="literal">nil</span> &#123;</span><br><span class="line">newCtx, cancel := context.WithTimeout(ctx, <span class="number">1</span>*time.Minute)</span><br><span class="line"><span class="keyword">defer</span> cancel()</span><br><span class="line">connectCtx = newCtx</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">didReadResponse := <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="keyword">struct</span>&#123;&#125;) </span><br><span class="line"><span class="keyword">var</span> (</span><br><span class="line">resp *Response</span><br><span class="line">err  <span class="type">error</span> </span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="keyword">go</span> <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line"><span class="keyword">defer</span> <span class="built_in">close</span>(didReadResponse)</span><br><span class="line">err = connectReq.Write(conn)</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">&#125;</span><br><span class="line">br := bufio.NewReader(conn)</span><br><span class="line">resp, err = ReadResponse(br, connectReq)</span><br><span class="line">&#125;()</span><br><span class="line"><span class="keyword">select</span> &#123;</span><br><span class="line"><span class="keyword">case</span> &lt;-connectCtx.Done():</span><br><span class="line">conn.Close()</span><br><span class="line">&lt;-didReadResponse</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, connectCtx.Err()</span><br><span class="line"><span class="keyword">case</span> &lt;-didReadResponse:</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">conn.Close()</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, err</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> resp.StatusCode != <span class="number">200</span> &#123;</span><br><span class="line">f := strings.SplitN(resp.Status, <span class="string">&quot; &quot;</span>, <span class="number">2</span>)</span><br><span class="line">conn.Close()</span><br><span class="line"><span class="keyword">if</span> <span class="built_in">len</span>(f) &lt; <span class="number">2</span> &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, errors.New(<span class="string">&quot;unknown status code&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, errors.New(f[<span class="number">1</span>])</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> cm.proxyURL != <span class="literal">nil</span> &amp;&amp; cm.targetScheme == <span class="string">&quot;https&quot;</span> &#123;</span><br><span class="line"><span class="keyword">if</span> err := pconn.addTLS(cm.tlsHost(), trace); err != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, err</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> s := pconn.tlsState; s != <span class="literal">nil</span> &amp;&amp; s.NegotiatedProtocolIsMutual &amp;&amp; s.NegotiatedProtocol != <span class="string">&quot;&quot;</span> &#123;</span><br><span class="line"><span class="keyword">if</span> next, ok := t.TLSNextProto[s.NegotiatedProtocol]; ok &#123;</span><br><span class="line">alt := next(cm.targetAddr, pconn.conn.(*tls.Conn))</span><br><span class="line"><span class="keyword">if</span> e, ok := alt.(http2erringRoundTripper); ok &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, e.err</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> &amp;persistConn&#123;t: t, cacheKey: pconn.cacheKey, alt: alt&#125;, <span class="literal">nil</span></span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">pconn.br = bufio.NewReaderSize(pconn, t.readBufferSize())</span><br><span class="line"><span class="comment">// buffer io wrapper for writing request</span></span><br><span class="line">pconn.bw = bufio.NewWriterSize(persistConnWriter&#123;pconn&#125;, t.writeBufferSize())</span><br><span class="line"><span class="comment">// read loop</span></span><br><span class="line"><span class="keyword">go</span> pconn.readLoop()</span><br><span class="line"><span class="comment">// write loop</span></span><br><span class="line"><span class="keyword">go</span> pconn.writeLoop()</span><br><span class="line"><span class="keyword">return</span> pconn, <span class="literal">nil</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>At <strong>line 4</strong>, it creates a new <code>persistConn</code> object, which is also the return value for this method. </p><p>At <strong>line 22</strong> and <strong>line 46</strong>, it calls <code>dial</code> method to establish a new TCP connection (note line 22 handles <code>TLS</code> case). In Golang a TCP connection is represented as <code>net.Conn</code> type. And then the underlying TCP connection is bound to the <code>conn</code> field of <code>persistConn</code>. </p><p>Now that we have the TCP connection, how can we use it? We’ll skip the many lines of code and go to the end to this function. </p><p>At <strong>line 166</strong>,  it creates <code>bufio.Writer</code> based on <code>persistConn</code>. <code>Buffer IO</code> is an interesting topic, in detail you can refer to my previous <a href="https://baoqger.github.io/2021/04/04/golang-bytes-buffer/">article</a>. In one word, it can optimize the performance by reducing the number of system calls. For example in the current case, it can avoid too many <code>socket</code> system calls. </p><p>At <strong>line 171</strong>, it creates a Goroutine and execute <code>writeLoop</code> method. Let’s take a look at it. </p><h3 id="writeLoop"><a href="#writeLoop" class="headerlink" title="writeLoop"></a>writeLoop</h3><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// writeLoop method in transport.go file</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(pc *persistConn)</span></span> writeLoop() &#123;</span><br><span class="line"><span class="keyword">defer</span> <span class="built_in">close</span>(pc.writeLoopDone)</span><br><span class="line"><span class="keyword">for</span> &#123;</span><br><span class="line"><span class="keyword">select</span> &#123;</span><br><span class="line"><span class="comment">// receive request from writech channel</span></span><br><span class="line"><span class="keyword">case</span> wr := &lt;-pc.writech:</span><br><span class="line">startBytesWritten := pc.nwrite</span><br><span class="line"><span class="comment">// call write method</span></span><br><span class="line">err := wr.req.Request.write(pc.bw, pc.isProxy, wr.req.extra, pc.waitForContinue(wr.continueCh))</span><br><span class="line"><span class="keyword">if</span> bre, ok := err.(requestBodyReadError); ok &#123;</span><br><span class="line">err = bre.<span class="type">error</span></span><br><span class="line">wr.req.setError(err)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> err == <span class="literal">nil</span> &#123;</span><br><span class="line">err = pc.bw.Flush()</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">wr.req.Request.closeBody()</span><br><span class="line"><span class="keyword">if</span> pc.nwrite == startBytesWritten &#123;</span><br><span class="line">err = nothingWrittenError&#123;err&#125;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">pc.writeErrCh &lt;- err <span class="comment">// to the body reader, which might recycle us</span></span><br><span class="line">wr.ch &lt;- err         <span class="comment">// to the roundTrip function</span></span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">pc.<span class="built_in">close</span>(err)</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">case</span> &lt;-pc.closech:</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>As the function name <strong>writeLoop</strong> implies, there is a <strong>for</strong> loop, and it keeps receiving data from the <strong>writech</strong> channel. Everytime it receive a request from the channel, call the <code>write</code> method at <strong>line 10</strong>. Then let’s review what message it actually writes:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// write method in request.go</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(r *Request)</span></span> write(w io.Writer, usingProxy <span class="type">bool</span>, extraHeaders Header, waitForContinue <span class="function"><span class="keyword">func</span><span class="params">()</span></span> <span class="type">bool</span>) (err <span class="type">error</span>) &#123;</span><br><span class="line">trace := httptrace.ContextClientTrace(r.Context())</span><br><span class="line"><span class="keyword">if</span> trace != <span class="literal">nil</span> &amp;&amp; trace.WroteRequest != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">defer</span> <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">trace.WroteRequest(httptrace.WroteRequestInfo&#123;</span><br><span class="line">Err: err,</span><br><span class="line">&#125;)</span><br><span class="line">&#125;()</span><br><span class="line">&#125;</span><br><span class="line">host := cleanHost(r.Host)</span><br><span class="line"><span class="keyword">if</span> host == <span class="string">&quot;&quot;</span> &#123;</span><br><span class="line"><span class="keyword">if</span> r.URL == <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span> errMissingHost</span><br><span class="line">&#125;</span><br><span class="line">host = cleanHost(r.URL.Host)</span><br><span class="line">&#125;</span><br><span class="line">host = removeZone(host)</span><br><span class="line">ruri := r.URL.RequestURI()</span><br><span class="line"><span class="keyword">if</span> usingProxy &amp;&amp; r.URL.Scheme != <span class="string">&quot;&quot;</span> &amp;&amp; r.URL.Opaque == <span class="string">&quot;&quot;</span> &#123;</span><br><span class="line">ruri = r.URL.Scheme + <span class="string">&quot;://&quot;</span> + host + ruri</span><br><span class="line">&#125; <span class="keyword">else</span> <span class="keyword">if</span> r.Method == <span class="string">&quot;CONNECT&quot;</span> &amp;&amp; r.URL.Path == <span class="string">&quot;&quot;</span> &#123;</span><br><span class="line">ruri = host</span><br><span class="line"><span class="keyword">if</span> r.URL.Opaque != <span class="string">&quot;&quot;</span> &#123;</span><br><span class="line">ruri = r.URL.Opaque</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> stringContainsCTLByte(ruri) &#123;</span><br><span class="line"><span class="keyword">return</span> errors.New(<span class="string">&quot;net/http: can&#x27;t write control character in Request.URL&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">var</span> bw *bufio.Writer</span><br><span class="line"><span class="keyword">if</span> _, ok := w.(io.ByteWriter); !ok &#123;</span><br><span class="line">bw = bufio.NewWriter(w)</span><br><span class="line">w = bw</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// write HTTP request line</span></span><br><span class="line">_, err = fmt.Fprintf(w, <span class="string">&quot;%s %s HTTP/1.1\r\n&quot;</span>, valueOrDefault(r.Method, <span class="string">&quot;GET&quot;</span>), ruri)</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span> err</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// write HTTP request Host header </span></span><br><span class="line">_, err = fmt.Fprintf(w, <span class="string">&quot;Host: %s\r\n&quot;</span>, host)</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span> err</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> trace != <span class="literal">nil</span> &amp;&amp; trace.WroteHeaderField != <span class="literal">nil</span> &#123;</span><br><span class="line">trace.WroteHeaderField(<span class="string">&quot;Host&quot;</span>, []<span class="type">string</span>&#123;host&#125;)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">userAgent := defaultUserAgent</span><br><span class="line"><span class="keyword">if</span> r.Header.has(<span class="string">&quot;User-Agent&quot;</span>) &#123;</span><br><span class="line">userAgent = r.Header.Get(<span class="string">&quot;User-Agent&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> userAgent != <span class="string">&quot;&quot;</span> &#123;</span><br><span class="line"><span class="comment">// write HTTP request User-Agent header </span></span><br><span class="line">_, err = fmt.Fprintf(w, <span class="string">&quot;User-Agent: %s\r\n&quot;</span>, userAgent)</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span> err</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> trace != <span class="literal">nil</span> &amp;&amp; trace.WroteHeaderField != <span class="literal">nil</span> &#123;</span><br><span class="line">trace.WroteHeaderField(<span class="string">&quot;User-Agent&quot;</span>, []<span class="type">string</span>&#123;userAgent&#125;)</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">tw, err := newTransferWriter(r)</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span> err</span><br><span class="line">&#125;</span><br><span class="line">err = tw.writeHeader(w, trace)</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span> err</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">err = r.Header.writeSubset(w, reqWriteExcludeHeader, trace)</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span> err</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> extraHeaders != <span class="literal">nil</span> &#123;</span><br><span class="line">err = extraHeaders.write(w, trace)</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span> err</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// write blank line after HTTP request headers</span></span><br><span class="line">_, err = io.WriteString(w, <span class="string">&quot;\r\n&quot;</span>)</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span> err</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> trace != <span class="literal">nil</span> &amp;&amp; trace.WroteHeaders != <span class="literal">nil</span> &#123;</span><br><span class="line">trace.WroteHeaders()</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> waitForContinue != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">if</span> bw, ok := w.(*bufio.Writer); ok &#123;</span><br><span class="line">err = bw.Flush()</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span> err</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> trace != <span class="literal">nil</span> &amp;&amp; trace.Wait100Continue != <span class="literal">nil</span> &#123;</span><br><span class="line">trace.Wait100Continue()</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> !waitForContinue() &#123;</span><br><span class="line">r.closeBody()</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span></span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> bw, ok := w.(*bufio.Writer); ok &amp;&amp; tw.FlushHeaders &#123;</span><br><span class="line"><span class="keyword">if</span> err := bw.Flush(); err != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span> err</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">err = tw.writeBody(w)</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">if</span> tw.bodyReadError == err &#123;</span><br><span class="line">err = requestBodyReadError&#123;err&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> err</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> bw != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span> bw.Flush()</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>We will not go through every line of code in above function. But I bet you find many familiar information, for example, at line 37 it write <strong>HTTP request line</strong> as the first information in the HTTP message. Then it continues writing <strong>HTTP headers</strong> such as <strong>Host</strong> and <strong>User-Agent</strong>(at line 42 and line 56), and finally add the <strong>blank line</strong> after the headers (at line 86). An HTTP request message is built up bit by bit. All right.  </p><h3 id="Bufio-and-underlying-writer"><a href="#Bufio-and-underlying-writer" class="headerlink" title="Bufio and underlying writer"></a>Bufio and underlying writer</h3><p>Next piece of this puzzle is how it’s related to the underlying TCP connection. </p><p>Note this method call in the write loop: </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// write method call in writeLoop</span></span><br><span class="line">wr.req.Request.write(pc.bw, pc.isProxy, wr.req.extra, pc.waitForContinue(wr.continueCh))</span><br></pre></td></tr></table></figure><p>The first parameter is <code>pc.bw</code> mentioned above. It’s time to take a deep look at it. <code>pc.bw</code>, a <strong>bufio.Write</strong>, is created by calling the following method from <code>bufio</code> package: </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// pconn.bw is created by this method call</span></span><br><span class="line">pconn.bw = bufio.NewWriterSize(persistConnWriter&#123;pconn&#125;, t.writeBufferSize())</span><br></pre></td></tr></table></figure><p>Note that this <strong>bufio.Writer</strong> isn’t based on <code>persistConn</code> directly, instead a simple wrapper over <code>persistConn</code> called <code>persistConnWriter</code> is used here. </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// persistConnWriter in transport.go file</span></span><br><span class="line"><span class="keyword">type</span> persistConnWriter <span class="keyword">struct</span> &#123;</span><br><span class="line">pc *persistConn</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>What we need to understand is <strong>bufio.Writer wraps an io.Writer object, creating another Writer that also implements the interface but provides buffering functionality.</strong> And <strong>bufio.Writer’s Flush method writes the buffered data to the underlying io.Writer.</strong></p><p>In this case, the underlying io.Writer is <code>persistConnWriter</code>. Its <code>Write</code> method will be used to write the buffered data: </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// persistConnWriter in transport.go file</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(w persistConnWriter)</span></span> Write(p []<span class="type">byte</span>) (n <span class="type">int</span>, err <span class="type">error</span>) &#123;</span><br><span class="line">n, err = w.pc.conn.Write(p) <span class="comment">// TCP socket Write system call is called here!</span></span><br><span class="line">w.pc.nwrite += <span class="type">int64</span>(n)</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Internally it delegates the task to the TCP connection bond to <code>pconn.conn</code>! </p><h3 id="roundTrip"><a href="#roundTrip" class="headerlink" title="roundTrip"></a>roundTrip</h3><p>As we mentioned above, <code>writeLoop</code> keeps receiving reqeusts from <code>writech</code> channel. So on the other hand, it means the requests should be sent to this channel somewhere. This is implemented inside the <code>roundTrip</code> method: </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// roundTrip in transport.go file</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(pc *persistConn)</span></span> roundTrip(req *transportRequest) (resp *Response, err <span class="type">error</span>) &#123;</span><br><span class="line">testHookEnterRoundTrip()</span><br><span class="line"><span class="keyword">if</span> !pc.t.replaceReqCanceler(req.cancelKey, pc.cancelRequest) &#123;</span><br><span class="line">pc.t.putOrCloseIdleConn(pc)</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, errRequestCanceled</span><br><span class="line">&#125;</span><br><span class="line">pc.mu.Lock()</span><br><span class="line">pc.numExpectedResponses++</span><br><span class="line">headerFn := pc.mutateHeaderFunc</span><br><span class="line">pc.mu.Unlock()</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> headerFn != <span class="literal">nil</span> &#123;</span><br><span class="line">headerFn(req.extraHeaders())</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">requestedGzip := <span class="literal">false</span></span><br><span class="line"><span class="keyword">if</span> !pc.t.DisableCompression &amp;&amp;</span><br><span class="line">req.Header.Get(<span class="string">&quot;Accept-Encoding&quot;</span>) == <span class="string">&quot;&quot;</span> &amp;&amp;</span><br><span class="line">req.Header.Get(<span class="string">&quot;Range&quot;</span>) == <span class="string">&quot;&quot;</span> &amp;&amp;</span><br><span class="line">req.Method != <span class="string">&quot;HEAD&quot;</span> &#123;</span><br><span class="line">requestedGzip = <span class="literal">true</span></span><br><span class="line">req.extraHeaders().Set(<span class="string">&quot;Accept-Encoding&quot;</span>, <span class="string">&quot;gzip&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> continueCh <span class="keyword">chan</span> <span class="keyword">struct</span>&#123;&#125;</span><br><span class="line"><span class="keyword">if</span> req.ProtoAtLeast(<span class="number">1</span>, <span class="number">1</span>) &amp;&amp; req.Body != <span class="literal">nil</span> &amp;&amp; req.expectsContinue() &#123;</span><br><span class="line">continueCh = <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="keyword">struct</span>&#123;&#125;, <span class="number">1</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> pc.t.DisableKeepAlives &amp;&amp; !req.wantsClose() &#123;</span><br><span class="line">req.extraHeaders().Set(<span class="string">&quot;Connection&quot;</span>, <span class="string">&quot;close&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">gone := <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="keyword">struct</span>&#123;&#125;)</span><br><span class="line"><span class="keyword">defer</span> <span class="built_in">close</span>(gone)</span><br><span class="line"></span><br><span class="line"><span class="keyword">defer</span> <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">pc.t.setReqCanceler(req.cancelKey, <span class="literal">nil</span>)</span><br><span class="line">&#125;</span><br><span class="line">&#125;()</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> debugRoundTrip = <span class="literal">false</span></span><br><span class="line">startBytesWritten := pc.nwrite</span><br><span class="line">writeErrCh := <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="type">error</span>, <span class="number">1</span>)</span><br><span class="line"><span class="comment">// send requet to pc.writech channel </span></span><br><span class="line">pc.writech &lt;- writeRequest&#123;req, writeErrCh, continueCh&#125;</span><br><span class="line"></span><br><span class="line">resc := <span class="built_in">make</span>(<span class="keyword">chan</span> responseAndError)</span><br><span class="line">pc.reqch &lt;- requestAndChan&#123;</span><br><span class="line">req:        req.Request,</span><br><span class="line">cancelKey:  req.cancelKey,</span><br><span class="line">ch:         resc,</span><br><span class="line">addedGzip:  requestedGzip,</span><br><span class="line">continueCh: continueCh,</span><br><span class="line">callerGone: gone,</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> respHeaderTimer &lt;-<span class="keyword">chan</span> time.Time</span><br><span class="line">cancelChan := req.Request.Cancel</span><br><span class="line">ctxDoneChan := req.Context().Done()</span><br><span class="line"><span class="keyword">for</span> &#123;</span><br><span class="line">testHookWaitResLoop()</span><br><span class="line"><span class="keyword">select</span> &#123;</span><br><span class="line"><span class="keyword">case</span> err := &lt;-writeErrCh:</span><br><span class="line"><span class="keyword">if</span> debugRoundTrip &#123;</span><br><span class="line">req.logf(<span class="string">&quot;writeErrCh resv: %T/%#v&quot;</span>, err, err)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">pc.<span class="built_in">close</span>(fmt.Errorf(<span class="string">&quot;write error: %v&quot;</span>, err))</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, pc.mapRoundTripError(req, startBytesWritten, err)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> d := pc.t.ResponseHeaderTimeout; d &gt; <span class="number">0</span> &#123;</span><br><span class="line"><span class="keyword">if</span> debugRoundTrip &#123;</span><br><span class="line">req.logf(<span class="string">&quot;starting timer for %v&quot;</span>, d)</span><br><span class="line">&#125;</span><br><span class="line">timer := time.NewTimer(d)</span><br><span class="line"><span class="keyword">defer</span> timer.Stop() </span><br><span class="line">respHeaderTimer = timer.C</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">case</span> &lt;-pc.closech:</span><br><span class="line"><span class="keyword">if</span> debugRoundTrip &#123;</span><br><span class="line">req.logf(<span class="string">&quot;closech recv: %T %#v&quot;</span>, pc.closed, pc.closed)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, pc.mapRoundTripError(req, startBytesWritten, pc.closed)</span><br><span class="line"><span class="keyword">case</span> &lt;-respHeaderTimer:</span><br><span class="line"><span class="keyword">if</span> debugRoundTrip &#123;</span><br><span class="line">req.logf(<span class="string">&quot;timeout waiting for response headers.&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line">pc.<span class="built_in">close</span>(errTimeout)</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, errTimeout</span><br><span class="line"><span class="keyword">case</span> re := &lt;-resc:</span><br><span class="line"><span class="keyword">if</span> (re.res == <span class="literal">nil</span>) == (re.err == <span class="literal">nil</span>) &#123;</span><br><span class="line"><span class="built_in">panic</span>(fmt.Sprintf(<span class="string">&quot;internal error: exactly one of res or err should be set; nil=%v&quot;</span>, re.res == <span class="literal">nil</span>))</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> debugRoundTrip &#123;</span><br><span class="line">req.logf(<span class="string">&quot;resc recv: %p, %T/%#v&quot;</span>, re.res, re.err, re.err)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> re.err != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, pc.mapRoundTripError(req, startBytesWritten, re.err)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> re.res, <span class="literal">nil</span></span><br><span class="line"><span class="keyword">case</span> &lt;-cancelChan:</span><br><span class="line">pc.t.cancelRequest(req.cancelKey, errRequestCanceled)</span><br><span class="line">cancelChan = <span class="literal">nil</span></span><br><span class="line"><span class="keyword">case</span> &lt;-ctxDoneChan:</span><br><span class="line">pc.t.cancelRequest(req.cancelKey, req.Context().Err())</span><br><span class="line">cancelChan = <span class="literal">nil</span></span><br><span class="line">ctxDoneChan = <span class="literal">nil</span></span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>At line 48, you can find it clearly. In <a href="https://baoqger.github.io/2021/12/01/understand-http1-1-client-golang/">last article</a>, you can see that <code>pconn.roundTrip</code> is the end of the HTTP request workflow. Now we had put all parts together. Great. </p><h3 id="Summary"><a href="#Summary" class="headerlink" title="Summary"></a>Summary</h3><p>In this article (as the second part of this series), we reviewed how the HTTP request message is written to TCP/IP stack via socket system call.  </p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;Background&quot;&gt;&lt;a href=&quot;#Background&quot; class=&quot;headerlink&quot; title=&quot;Background&quot;&gt;&lt;/a&gt;Background&lt;/h3&gt;&lt;p&gt;In the &lt;a href=&quot;https://baoqger.github</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>How  HTTP1.1 protocol is implemented in Golang net/http package: part one - request workflow</title>
    <link href="https://baoqger.github.io/2021/12/01/understand-http-1-1-client-golang/"/>
    <id>https://baoqger.github.io/2021/12/01/understand-http-1-1-client-golang/</id>
    <published>2021-12-01T02:02:34.000Z</published>
    <updated>2021-12-23T12:34:34.799Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Background"><a href="#Background" class="headerlink" title="Background"></a>Background</h3><p>In this article, I’ll write about one topic: how to implement the HTTP protocol. I keep planning to write about this topic for a long time. In my previous articles, I already wrote several articles about HTTP protocol:</p><ul><li><a href="https://baoqger.github.io/2021/07/31/how-to-implement-simple-http-server-golang/">How to write a Golang HTTP server with Linux system calls</a></li><li><a href="https://baoqger.github.io/2021/10/25/understand-http1-1-persistent-connection-golang/">Understand how HTTP/1.1 persistent connection works based on Golang: part one - sequential requests</a></li><li><a href="https://baoqger.github.io/2021/10/27/understand-http1-1-persitent-connection-golang-part2/">Understand how HTTP/1.1 persistent connection works based on Golang: part two - concurrent requests</a></li></ul><p>I recommend you to read these articles above before this one. </p><p>As you know, HTTP protocol is in the application layer, which is the closest one to the end-user in the protocol stack. </p><p>So relatively speaking, HTTP protocol is not as mysterious as other protocols in the lower layers of this stack. Software engineers use HTTP every day and take it for granted. Have you ever thought about how we can implement a fully functional HTTP protocol library? </p><p>It turns out to be a very complex and big work in terms of software engineering. Frankly speaking, I can’t work it out by myself in a short period. So in this article, we’ll try to understand how to do it by investigating Golang <code>net/http</code> package as an example. We’ll read a lot of source code and draw diagrams to help your understanding of the source code.</p><p><strong>Note</strong> HTTP protocol itself has evolved a lot from <code>HTTP1.1</code> to <code>HTTP2</code> and <code>HTTP3</code>, not to mention <code>HTTPS</code>. In this article, we’ll focus on the mechanism of <code>HTTP1.1</code>, but what you learned here can help you understand other new versions of HTTP protocol. </p><p><strong>Note</strong> HTTP protocol is on the basis of client-server model. This article will focus on the client-side. For the HTTP server part, I’ll write another article next. </p><h3 id="Main-workflow-of-http-Client"><a href="#Main-workflow-of-http-Client" class="headerlink" title="Main workflow of http.Client"></a>Main workflow of http.Client</h3><p>HTTP client’s request starts from the application’s call to <code>Get</code> method of <code>net/http</code> package, and ends by writing the HTTP message to the TCP socket. The whole workflow can be simplified to the following diagram:   </p><img src="/images/golang-http1-1-client-flow.png" title="golang client flow" width="800px" height="600px"><p>First, the public <code>Get</code> method calls Get method of <code>DefaultClient</code>, which is a global variable of type <code>Client</code>,  </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Get method</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">Get</span><span class="params">(url <span class="type">string</span>)</span></span> (resp *Response, err <span class="type">error</span>) &#123;</span><br><span class="line"><span class="keyword">return</span> DefaultClient.Get(url)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// DefaultClient is a global variable in net/http package</span></span><br><span class="line"><span class="keyword">var</span> DefaultClient = &amp;Client&#123;&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// struct type Client</span></span><br><span class="line"><span class="keyword">type</span> Client <span class="keyword">struct</span> &#123;</span><br><span class="line">Transport RoundTripper</span><br><span class="line"></span><br><span class="line">CheckRedirect <span class="function"><span class="keyword">func</span><span class="params">(req *Request, via []*Request)</span></span> <span class="type">error</span></span><br><span class="line"></span><br><span class="line">Jar CookieJar</span><br><span class="line"></span><br><span class="line">Timeout time.Duration</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Then, <code>NewRequest</code> method is used to construct a new request of type <code>Request</code>: </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(c *Client)</span></span> Get(url <span class="type">string</span>) (resp *Response, err <span class="type">error</span>) &#123;</span><br><span class="line">req, err := NewRequest(<span class="string">&quot;GET&quot;</span>, url, <span class="literal">nil</span>)</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, err</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> c.Do(req)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">NewRequest</span><span class="params">(method, url <span class="type">string</span>, body io.Reader)</span></span> (*Request, <span class="type">error</span>) &#123;</span><br><span class="line"><span class="keyword">return</span> NewRequestWithContext(context.Background(), method, url, body)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>I’ll not show the function body of <code>NewRequestWithContext</code>, since it’s very long. But only paste the block of code for actually building the <code>Request</code> object as follows:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">req := &amp;Request&#123;</span><br><span class="line">    <span class="comment">// omit some code </span></span><br><span class="line">    Proto:      <span class="string">&quot;HTTP/1.1&quot;</span>, <span class="comment">// the default HTTP protocol version is set to 1.1</span></span><br><span class="line">    ProtoMajor: <span class="number">1</span>,</span><br><span class="line">    ProtoMinor: <span class="number">1</span>,</span><br><span class="line">    <span class="comment">// omit some code</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Note that by default the HTTP protocol version is set to 1.1. If you want to send HTTP2 request, then you need other solutions, and I’ll write about it in other articles.  </p><p>Next, <code>Do</code> method is called, which delegates the work to the private <code>do</code> method.  </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(c *Client)</span></span> Do(req *Request) (*Response, <span class="type">error</span>) &#123;</span><br><span class="line"><span class="keyword">return</span> c.do(req)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>do</code> method handles the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Redirections"><code>HTTP redirect</code></a> behavior, which is very interesting. But since the code block is too long, I’ll not show its function body here. You can refer to the source code of it <a href="https://cs.opensource.google/go/go/+/refs/tags/go1.17.3:src/net/http/client.go;drc=refs%2Ftags%2Fgo1.17.3;l=598">here</a>.</p><p>Next, <code>send</code> method of Client is called which goes as follows: </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(c *Client)</span></span> send(req *Request, deadline time.Time) (resp *Response, didTimeout <span class="function"><span class="keyword">func</span><span class="params">()</span></span> <span class="type">bool</span>, err <span class="type">error</span>) &#123;</span><br><span class="line"><span class="keyword">if</span> c.Jar != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">for</span> _, cookie := <span class="keyword">range</span> c.Jar.Cookies(req.URL) &#123;</span><br><span class="line">req.AddCookie(cookie)</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">    <span class="comment">// call send method here</span></span><br><span class="line">resp, didTimeout, err = send(req, c.transport(), deadline)</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, didTimeout, err</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> c.Jar != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">if</span> rc := resp.Cookies(); <span class="built_in">len</span>(rc) &gt; <span class="number">0</span> &#123;</span><br><span class="line">c.Jar.SetCookies(req.URL, rc)</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> resp, <span class="literal">nil</span>, <span class="literal">nil</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>It handles cookies for the request, then calls the private method <code>send</code> with three parameters.</p><p>We already talked about the first parameter above. Let’s take a look at the second parameter <code>c.transport()</code> as follows: </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(c *Client)</span></span> transport() RoundTripper &#123;</span><br><span class="line"><span class="keyword">if</span> c.Transport != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span> c.Transport</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> DefaultTransport</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>Transport</code> is extremely important for HTTP client workflow. Let’s examine how it works bit by bit.  First of all, it’s type of <code>RoundTripper</code> interface. </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// this interface is defined inside client.go file </span></span><br><span class="line"></span><br><span class="line"><span class="keyword">type</span> RoundTripper <span class="keyword">interface</span> &#123;</span><br><span class="line"><span class="comment">// RoundTrip executes a single HTTP transaction, returning</span></span><br><span class="line"><span class="comment">// a Response for the provided Request.</span></span><br><span class="line">RoundTrip(*Request) (*Response, <span class="type">error</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>RoundTripper</code> interface only defines one method <code>RoundTrip</code>, all right. </p><p>If you don’t have any special settings, the <code>DefaultTransport</code> will be used for <code>c.Transport</code> above. </p><p>The <code>DefaultTransport</code> is going as follows: </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// defined in transport.go</span></span><br><span class="line"><span class="keyword">var</span> DefaultTransport RoundTripper = &amp;Transport&#123;</span><br><span class="line">Proxy: ProxyFromEnvironment,</span><br><span class="line">DialContext: (&amp;net.Dialer&#123;</span><br><span class="line">Timeout:   <span class="number">30</span> * time.Second,</span><br><span class="line">KeepAlive: <span class="number">30</span> * time.Second,</span><br><span class="line">DualStack: <span class="literal">true</span>,</span><br><span class="line">&#125;).DialContext,</span><br><span class="line">ForceAttemptHTTP2:     <span class="literal">true</span>,</span><br><span class="line">MaxIdleConns:          <span class="number">100</span>,</span><br><span class="line">IdleConnTimeout:       <span class="number">90</span> * time.Second,</span><br><span class="line">TLSHandshakeTimeout:   <span class="number">10</span> * time.Second,</span><br><span class="line">ExpectContinueTimeout: <span class="number">1</span> * time.Second,</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Note that its actual type  is <code>Transport</code> as below:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> Transport <span class="keyword">struct</span> &#123;</span><br><span class="line">idleMu       sync.Mutex</span><br><span class="line">closeIdle    <span class="type">bool</span>                                <span class="comment">// user has requested to close all idle conns</span></span><br><span class="line">idleConn     <span class="keyword">map</span>[connectMethodKey][]*persistConn <span class="comment">// most recently used at end</span></span><br><span class="line">idleConnWait <span class="keyword">map</span>[connectMethodKey]wantConnQueue  <span class="comment">// waiting getConns</span></span><br><span class="line">idleLRU      connLRU</span><br><span class="line">reqMu       sync.Mutex</span><br><span class="line">reqCanceler <span class="keyword">map</span>[cancelKey]<span class="function"><span class="keyword">func</span><span class="params">(<span class="type">error</span>)</span></span></span><br><span class="line">altMu    sync.Mutex   <span class="comment">// guards changing altProto only</span></span><br><span class="line">altProto atomic.Value <span class="comment">// of nil or map[string]RoundTripper, key is URI scheme</span></span><br><span class="line">connsPerHostMu   sync.Mutex</span><br><span class="line">connsPerHost     <span class="keyword">map</span>[connectMethodKey]<span class="type">int</span></span><br><span class="line">connsPerHostWait <span class="keyword">map</span>[connectMethodKey]wantConnQueue <span class="comment">// waiting getConns</span></span><br><span class="line">Proxy <span class="function"><span class="keyword">func</span><span class="params">(*Request)</span></span> (*url.URL, <span class="type">error</span>)</span><br><span class="line">DialContext <span class="function"><span class="keyword">func</span><span class="params">(ctx context.Context, network, addr <span class="type">string</span>)</span></span> (net.Conn, <span class="type">error</span>)</span><br><span class="line">Dial <span class="function"><span class="keyword">func</span><span class="params">(network, addr <span class="type">string</span>)</span></span> (net.Conn, <span class="type">error</span>)</span><br><span class="line">DialTLSContext <span class="function"><span class="keyword">func</span><span class="params">(ctx context.Context, network, addr <span class="type">string</span>)</span></span> (net.Conn, <span class="type">error</span>)</span><br><span class="line">DialTLS <span class="function"><span class="keyword">func</span><span class="params">(network, addr <span class="type">string</span>)</span></span> (net.Conn, <span class="type">error</span>)</span><br><span class="line">TLSClientConfig *tls.Config</span><br><span class="line">TLSHandshakeTimeout time.Duration</span><br><span class="line">DisableKeepAlives <span class="type">bool</span></span><br><span class="line">DisableCompression <span class="type">bool</span></span><br><span class="line">MaxIdleConns <span class="type">int</span></span><br><span class="line">MaxIdleConnsPerHost <span class="type">int</span></span><br><span class="line">MaxConnsPerHost <span class="type">int</span></span><br><span class="line">IdleConnTimeout time.Duration</span><br><span class="line">ResponseHeaderTimeout time.Duration</span><br><span class="line">ExpectContinueTimeout time.Duration</span><br><span class="line">TLSNextProto <span class="keyword">map</span>[<span class="type">string</span>]<span class="function"><span class="keyword">func</span><span class="params">(authority <span class="type">string</span>, c *tls.Conn)</span></span> RoundTripper</span><br><span class="line">ProxyConnectHeader Header</span><br><span class="line">MaxResponseHeaderBytes <span class="type">int64</span></span><br><span class="line">WriteBufferSize <span class="type">int</span></span><br><span class="line">ReadBufferSize <span class="type">int</span></span><br><span class="line">nextProtoOnce      sync.Once</span><br><span class="line">h2transport        h2Transport <span class="comment">// non-nil if http2 wired up</span></span><br><span class="line">tlsNextProtoWasNil <span class="type">bool</span>        <span class="comment">// whether TLSNextProto was nil when the Once fired</span></span><br><span class="line">ForceAttemptHTTP2 <span class="type">bool</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>I list the full content of <code>Transport</code> struct here, although it contains many fields, and many of them will not be discussed in this article.</p><p>As we just mentioned, <code>Transport</code> is type of <code>RoundTripper</code> interface, it must implement the method <code>RoundTrip</code>, right? </p><p>You can find the <code>RoundTrip</code> method implementation of <code>Transport</code> struct type in <strong>roundtrip.go</strong> file as follows:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// RoundTrip method in roundtrip.go</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(t *Transport)</span></span> RoundTrip(req *Request) (*Response, <span class="type">error</span>) &#123;</span><br><span class="line"><span class="keyword">return</span> t.roundTrip(req)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>In the beginning, I thought this method should be included inside <code>transport.go</code> file, but it is defined inside another file.  </p><p>Let’s back to the <code>send</code> method which takes <code>c.Transport</code> as the second argument:  </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// send method in client.go </span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">send</span><span class="params">(ireq *Request, rt RoundTripper, deadline time.Time)</span></span> (resp *Response, didTimeout <span class="function"><span class="keyword">func</span><span class="params">()</span></span> <span class="type">bool</span>, err <span class="type">error</span>) &#123;</span><br><span class="line">req := ireq <span class="comment">// req is either the original request, or a modified fork</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> rt == <span class="literal">nil</span> &#123;</span><br><span class="line">req.closeBody()</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, alwaysFalse, errors.New(<span class="string">&quot;http: no Client.Transport or DefaultTransport&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> req.URL == <span class="literal">nil</span> &#123;</span><br><span class="line">req.closeBody()</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, alwaysFalse, errors.New(<span class="string">&quot;http: nil Request.URL&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> req.RequestURI != <span class="string">&quot;&quot;</span> &#123;</span><br><span class="line">req.closeBody()</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, alwaysFalse, errors.New(<span class="string">&quot;http: Request.RequestURI can&#x27;t be set in client requests&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// forkReq forks req into a shallow clone of ireq the first</span></span><br><span class="line"><span class="comment">// time it&#x27;s called.</span></span><br><span class="line">forkReq := <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line"><span class="keyword">if</span> ireq == req &#123;</span><br><span class="line">req = <span class="built_in">new</span>(Request)</span><br><span class="line">*req = *ireq <span class="comment">// shallow clone</span></span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Most the callers of send (Get, Post, et al) don&#x27;t need</span></span><br><span class="line"><span class="comment">// Headers, leaving it uninitialized. We guarantee to the</span></span><br><span class="line"><span class="comment">// Transport that this has been initialized, though.</span></span><br><span class="line"><span class="keyword">if</span> req.Header == <span class="literal">nil</span> &#123;</span><br><span class="line">forkReq()</span><br><span class="line">req.Header = <span class="built_in">make</span>(Header)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> u := req.URL.User; u != <span class="literal">nil</span> &amp;&amp; req.Header.Get(<span class="string">&quot;Authorization&quot;</span>) == <span class="string">&quot;&quot;</span> &#123;</span><br><span class="line">username := u.Username()</span><br><span class="line">password, _ := u.Password()</span><br><span class="line">forkReq()</span><br><span class="line">req.Header = cloneOrMakeHeader(ireq.Header)</span><br><span class="line">req.Header.Set(<span class="string">&quot;Authorization&quot;</span>, <span class="string">&quot;Basic &quot;</span>+basicAuth(username, password))</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> !deadline.IsZero() &#123;</span><br><span class="line">forkReq()</span><br><span class="line">&#125;</span><br><span class="line">stopTimer, didTimeout := setRequestCancel(req, rt, deadline)</span><br><span class="line"></span><br><span class="line">resp, err = rt.RoundTrip(req)</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">stopTimer()</span><br><span class="line"><span class="keyword">if</span> resp != <span class="literal">nil</span> &#123;</span><br><span class="line">log.Printf(<span class="string">&quot;RoundTripper returned a response &amp; error; ignoring response&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> tlsErr, ok := err.(tls.RecordHeaderError); ok &#123;</span><br><span class="line"><span class="comment">// If we get a bad TLS record header, check to see if the</span></span><br><span class="line"><span class="comment">// response looks like HTTP and give a more helpful error.</span></span><br><span class="line"><span class="comment">// See golang.org/issue/11111.</span></span><br><span class="line"><span class="keyword">if</span> <span class="type">string</span>(tlsErr.RecordHeader[:]) == <span class="string">&quot;HTTP/&quot;</span> &#123;</span><br><span class="line">err = errors.New(<span class="string">&quot;http: server gave HTTP response to HTTPS client&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, didTimeout, err</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> resp == <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, didTimeout, fmt.Errorf(<span class="string">&quot;http: RoundTripper implementation (%T) returned a nil *Response with a nil error&quot;</span>, rt)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> resp.Body == <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="comment">// The documentation on the Body field says “The http Client and Transport</span></span><br><span class="line"><span class="comment">// guarantee that Body is always non-nil, even on responses without a body</span></span><br><span class="line"><span class="comment">// or responses with a zero-length body.” Unfortunately, we didn&#x27;t document</span></span><br><span class="line"><span class="comment">// that same constraint for arbitrary RoundTripper implementations, and</span></span><br><span class="line"><span class="comment">// RoundTripper implementations in the wild (mostly in tests) assume that</span></span><br><span class="line"><span class="comment">// they can use a nil Body to mean an empty one (similar to Request.Body).</span></span><br><span class="line"><span class="comment">// (See https://golang.org/issue/38095.)</span></span><br><span class="line"><span class="comment">//</span></span><br><span class="line"><span class="comment">// If the ContentLength allows the Body to be empty, fill in an empty one</span></span><br><span class="line"><span class="comment">// here to ensure that it is non-nil.</span></span><br><span class="line"><span class="keyword">if</span> resp.ContentLength &gt; <span class="number">0</span> &amp;&amp; req.Method != <span class="string">&quot;HEAD&quot;</span> &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, didTimeout, fmt.Errorf(<span class="string">&quot;http: RoundTripper implementation (%T) returned a *Response with content length %d but a nil Body&quot;</span>, rt, resp.ContentLength)</span><br><span class="line">&#125;</span><br><span class="line">resp.Body = ioutil.NopCloser(strings.NewReader(<span class="string">&quot;&quot;</span>))</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> !deadline.IsZero() &#123;</span><br><span class="line">resp.Body = &amp;cancelTimerBody&#123;</span><br><span class="line">stop:          stopTimer,</span><br><span class="line">rc:            resp.Body,</span><br><span class="line">reqDidTimeout: didTimeout,</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> resp, <span class="literal">nil</span>, <span class="literal">nil</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>At <strong>line 50</strong> of <code>send</code> method above: </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">resp, err = rt.RoundTrip(req)</span><br></pre></td></tr></table></figure><p><code>RoundTrip</code> method is called to send the request. Based on the comments in the source code, you can understand it in the following way:</p><ul><li>RoundTripper is an interface representing the ability to execute a single HTTP transaction, obtaining the Response for a given Request.</li></ul><p>Next, let’s go to <code>roundTrip</code> method of <code>Transport</code>: </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// roundTrip method in transport.go, which is called by RoundTrip method internally </span></span><br><span class="line"></span><br><span class="line"><span class="comment">// roundTrip implements a RoundTripper over HTTP.</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(t *Transport)</span></span> roundTrip(req *Request) (*Response, <span class="type">error</span>) &#123;</span><br><span class="line">t.nextProtoOnce.Do(t.onceSetNextProtoDefaults)</span><br><span class="line">ctx := req.Context()</span><br><span class="line">trace := httptrace.ContextClientTrace(ctx)</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> req.URL == <span class="literal">nil</span> &#123;</span><br><span class="line">req.closeBody()</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, errors.New(<span class="string">&quot;http: nil Request.URL&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> req.Header == <span class="literal">nil</span> &#123;</span><br><span class="line">req.closeBody()</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, errors.New(<span class="string">&quot;http: nil Request.Header&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line">scheme := req.URL.Scheme</span><br><span class="line">isHTTP := scheme == <span class="string">&quot;http&quot;</span> || scheme == <span class="string">&quot;https&quot;</span></span><br><span class="line"><span class="keyword">if</span> isHTTP &#123;</span><br><span class="line"><span class="keyword">for</span> k, vv := <span class="keyword">range</span> req.Header &#123;</span><br><span class="line"><span class="keyword">if</span> !httpguts.ValidHeaderFieldName(k) &#123;</span><br><span class="line">req.closeBody()</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, fmt.Errorf(<span class="string">&quot;net/http: invalid header field name %q&quot;</span>, k)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">for</span> _, v := <span class="keyword">range</span> vv &#123;</span><br><span class="line"><span class="keyword">if</span> !httpguts.ValidHeaderFieldValue(v) &#123;</span><br><span class="line">req.closeBody()</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, fmt.Errorf(<span class="string">&quot;net/http: invalid header field value %q for key %v&quot;</span>, v, k)</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">origReq := req</span><br><span class="line">cancelKey := cancelKey&#123;origReq&#125;</span><br><span class="line">req = setupRewindBody(req)</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> altRT := t.alternateRoundTripper(req); altRT != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">if</span> resp, err := altRT.RoundTrip(req); err != ErrSkipAltProtocol &#123;</span><br><span class="line"><span class="keyword">return</span> resp, err</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">var</span> err <span class="type">error</span></span><br><span class="line">req, err = rewindBody(req)</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, err</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> !isHTTP &#123;</span><br><span class="line">req.closeBody()</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, badStringError(<span class="string">&quot;unsupported protocol scheme&quot;</span>, scheme)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> req.Method != <span class="string">&quot;&quot;</span> &amp;&amp; !validMethod(req.Method) &#123;</span><br><span class="line">req.closeBody()</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, fmt.Errorf(<span class="string">&quot;net/http: invalid method %q&quot;</span>, req.Method)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> req.URL.Host == <span class="string">&quot;&quot;</span> &#123;</span><br><span class="line">req.closeBody()</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, errors.New(<span class="string">&quot;http: no Host in request URL&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> &#123;</span><br><span class="line"><span class="keyword">select</span> &#123;</span><br><span class="line"><span class="keyword">case</span> &lt;-ctx.Done():</span><br><span class="line">req.closeBody()</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, ctx.Err()</span><br><span class="line"><span class="keyword">default</span>:</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// treq gets modified by roundTrip, so we need to recreate for each retry.</span></span><br><span class="line">treq := &amp;transportRequest&#123;Request: req, trace: trace, cancelKey: cancelKey&#125;</span><br><span class="line">cm, err := t.connectMethodForRequest(treq)</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">req.closeBody()</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, err</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Get the cached or newly-created connection to either the</span></span><br><span class="line"><span class="comment">// host (for http or https), the http proxy, or the http proxy</span></span><br><span class="line"><span class="comment">// pre-CONNECTed to https server. In any case, we&#x27;ll be ready</span></span><br><span class="line"><span class="comment">// to send it requests.</span></span><br><span class="line">pconn, err := t.getConn(treq, cm)</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">t.setReqCanceler(cancelKey, <span class="literal">nil</span>)</span><br><span class="line">req.closeBody()</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, err</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> resp *Response</span><br><span class="line"><span class="keyword">if</span> pconn.alt != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="comment">// HTTP/2 path.</span></span><br><span class="line">t.setReqCanceler(cancelKey, <span class="literal">nil</span>) <span class="comment">// not cancelable with CancelRequest</span></span><br><span class="line">resp, err = pconn.alt.RoundTrip(req)</span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">resp, err = pconn.roundTrip(treq)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> err == <span class="literal">nil</span> &#123;</span><br><span class="line">resp.Request = origReq</span><br><span class="line"><span class="keyword">return</span> resp, <span class="literal">nil</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Failed. Clean up and determine whether to retry.</span></span><br><span class="line"><span class="keyword">if</span> http2isNoCachedConnError(err) &#123;</span><br><span class="line"><span class="keyword">if</span> t.removeIdleConn(pconn) &#123;</span><br><span class="line">t.decConnsPerHost(pconn.cacheKey)</span><br><span class="line">&#125;</span><br><span class="line">&#125; <span class="keyword">else</span> <span class="keyword">if</span> !pconn.shouldRetryRequest(req, err) &#123;</span><br><span class="line"><span class="comment">// Issue 16465: return underlying net.Conn.Read error from peek,</span></span><br><span class="line"><span class="comment">// as we&#x27;ve historically done.</span></span><br><span class="line"><span class="keyword">if</span> e, ok := err.(transportReadFromServerError); ok &#123;</span><br><span class="line">err = e.err</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, err</span><br><span class="line">&#125;</span><br><span class="line">testHookRoundTripRetried()</span><br><span class="line"></span><br><span class="line"><span class="comment">// Rewind the body if we&#x27;re able to.</span></span><br><span class="line">req, err = rewindBody(req)</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, err</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>There are three key points:</p><ul><li>at <strong>line 70</strong>, a new variable of type <code>transportRequest</code>, which embeds <code>Request</code>, is created.  </li><li>at <strong>line 81</strong>, <code>getConn</code> method is called, which implements the cached <code>connection pool</code> to support the <code>persistent connection</code> mode. Of course, if no cached connection is available, a new connection will be created and added to the connection pool. I will explain this behavior in detail next section. </li><li>from <strong>line 89</strong> to <strong>line 95</strong>, <code>pconn.roundTrip</code> is called. The name of variable <code>pconn</code> is self-explaining which means it is type of <code>persistConn</code>. </li></ul><p><code>transportRequest</code> is passed as parameter to <code>getConn</code> method, which returns <code>pconn</code>. <code>pconn.roundTrip</code> is called to execute the HTTP request. we have covered all the steps in the above workflow diagram. </p><h3 id="Summary"><a href="#Summary" class="headerlink" title="Summary"></a>Summary</h3><p>In this first article of this series, we talked about the workflow of sending an HTTP request step by step. And I’ll discuss how to send the HTTP message to the TCP stack in the second article.   </p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;Background&quot;&gt;&lt;a href=&quot;#Background&quot; class=&quot;headerlink&quot; title=&quot;Background&quot;&gt;&lt;/a&gt;Background&lt;/h3&gt;&lt;p&gt;In this article, I’ll write about one </summary>
      
    
    
    
    
    <category term="HTTP protocol, Golang, TCP, socket" scheme="https://baoqger.github.io/tags/HTTP-protocol-Golang-TCP-socket/"/>
    
  </entry>
  
  <entry>
    <title>Understand how HTTP/1.1 persistent connection works based on Golang: part two - concurrent requests</title>
    <link href="https://baoqger.github.io/2021/10/27/understand-http1-1-persitent-connection-golang-part2/"/>
    <id>https://baoqger.github.io/2021/10/27/understand-http1-1-persitent-connection-golang-part2/</id>
    <published>2021-10-27T09:51:29.000Z</published>
    <updated>2021-12-23T12:34:34.800Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Background"><a href="#Background" class="headerlink" title="Background"></a>Background</h3><p>In the <a href="https://baoqger.github.io/2021/10/25/understand-http1-1-persistent-connection-golang/">last post</a>, I show you how HTTP/1.1 persistent connection works in a simple demo app, which sends sequential requests.</p><p>We observe the underlying TCP connection behavior based on the network analysis tool: <code>netstat</code> and <code>tcpdump</code>.</p><p>In this article, I will modify the demo app and make it send concurrent requests. In this way, we can have more understanding about HTTP/1.1’s persistent connection.  </p><h3 id="Concurrent-requests"><a href="#Concurrent-requests" class="headerlink" title="Concurrent requests"></a>Concurrent requests</h3><p>The <a href="https://github.com/baoqger/http-persistent-connection-golang/blob/master/concurrent/non-persistent-connection/non-persistent-connection-concurrent.go">demo code</a> goes as follows:  </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line"><span class="string">&quot;fmt&quot;</span></span><br><span class="line"><span class="string">&quot;io&quot;</span></span><br><span class="line"><span class="string">&quot;io/ioutil&quot;</span></span><br><span class="line"><span class="string">&quot;log&quot;</span></span><br><span class="line"><span class="string">&quot;net/http&quot;</span></span><br><span class="line"><span class="string">&quot;sync&quot;</span></span><br><span class="line"><span class="string">&quot;time&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">startHTTPserver</span><span class="params">()</span></span> &#123;</span><br><span class="line"></span><br><span class="line">http.HandleFunc(<span class="string">&quot;/&quot;</span>, <span class="function"><span class="keyword">func</span><span class="params">(w http.ResponseWriter, r *http.Request)</span></span> &#123;</span><br><span class="line">time.Sleep(time.Duration(<span class="number">50</span>) * time.Microsecond)</span><br><span class="line">fmt.Fprintf(w, <span class="string">&quot;Hello world&quot;</span>)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="keyword">go</span> <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">http.ListenAndServe(<span class="string">&quot;:8080&quot;</span>, <span class="literal">nil</span>)</span><br><span class="line">&#125;()</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">startHTTPRequest</span><span class="params">(index <span class="type">int</span>, wg *sync.WaitGroup)</span></span> &#123;</span><br><span class="line">counter := <span class="number">0</span></span><br><span class="line"><span class="keyword">for</span> i := <span class="number">0</span>; i &lt; <span class="number">10</span>; i++ &#123;</span><br><span class="line">resp, err := http.Get(<span class="string">&quot;http://localhost:8080/&quot;</span>)</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="built_in">panic</span>(fmt.Sprintf(<span class="string">&quot;Error: %v&quot;</span>, err))</span><br><span class="line">&#125;</span><br><span class="line">io.Copy(ioutil.Discard, resp.Body) <span class="comment">// fully read the response body</span></span><br><span class="line">resp.Body.Close()                  <span class="comment">// close the response body</span></span><br><span class="line">log.Printf(<span class="string">&quot;HTTP request #%v in Goroutine #%v&quot;</span>, counter, index)</span><br><span class="line">counter += <span class="number">1</span></span><br><span class="line">time.Sleep(time.Duration(<span class="number">1</span>) * time.Second)</span><br><span class="line">&#125;</span><br><span class="line">wg.Done()</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">startHTTPserver()</span><br><span class="line"><span class="keyword">var</span> wg sync.WaitGroup</span><br><span class="line"><span class="keyword">for</span> i := <span class="number">0</span>; i &lt; <span class="number">10</span>; i++ &#123;</span><br><span class="line">wg.Add(<span class="number">1</span>)</span><br><span class="line"><span class="keyword">go</span> startHTTPRequest(i, &amp;wg)</span><br><span class="line">&#125;</span><br><span class="line">wg.Wait()</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>We create 10 goroutines, and each goroutine sends 10 sequential requests concurrently. </p><p><strong>Note</strong>: In HTTP/1.1 protocol, concurrent requests will establish multiple TCP connections. That’s the restriction of HTTP/1.1, the way to enhance it is using <code>HTTP/2</code> which can multiplex one TCP connection for multiple parallel HTTP connections. <code>HTTP/2</code> is not in the scope of this post. I will talk about it in another article. </p><p>Note that in the above demo, we have fully read the response body and closed it, and based on the discussion in <a href="https://baoqger.github.io/2021/10/25/understand-http1-1-persistent-connection-golang/">last article</a>, the HTTP requests should work in the persistent connection model. </p><p>Before we use the network tool to analyze the behavior, let’s imagine how many TCP connections will be established. As there are 10 concurrent goroutines, 10 TCP connections should be established, and all the HTTP requests should re-use these 10 TCP connections, right? That’s our expectation. </p><p>Next, let’s verify our expectation with <code>netstat</code> as follows: </p><img src="/images/netstat-concurrent-non-persistent.png" title="tcp termination" width="600px" height="400px"><p>It shows that the number of TCP connections is much more than 10. The persistent connection does not work as we expect. </p><p>After reading the source code of <code>net/http</code> package, I find the following hints: </p><p>The <code>Client</code> is defined inside <a href="https://golang.org/src/net/http/client.go">client.go</a> which is the type for HTTP client, and <code>Transport</code> is one of the properties.  </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> Client <span class="keyword">struct</span> &#123;</span><br><span class="line">Transport RoundTripper</span><br><span class="line"></span><br><span class="line">CheckRedirect <span class="function"><span class="keyword">func</span><span class="params">(req *Request, via []*Request)</span></span> <span class="type">error</span></span><br><span class="line"></span><br><span class="line">Jar CookieJar</span><br><span class="line"></span><br><span class="line">Timeout time.Duration</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>Transport</code> is defined in <a href="https://golang.org/src/net/http/transport.go">transport.go</a> like this: </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// DefaultTransport is the default implementation of Transport and is</span></span><br><span class="line"><span class="comment">// used by DefaultClient. It establishes network connections as needed</span></span><br><span class="line"><span class="comment">// and caches them for reuse by subsequent calls. It uses HTTP proxies</span></span><br><span class="line"><span class="comment">// as directed by the $HTTP_PROXY and $NO_PROXY (or $http_proxy and</span></span><br><span class="line"><span class="comment">// $no_proxy) environment variables.</span></span><br><span class="line"><span class="keyword">var</span> DefaultTransport RoundTripper = &amp;Transport&#123;</span><br><span class="line">Proxy: ProxyFromEnvironment,</span><br><span class="line">DialContext: (&amp;net.Dialer&#123;</span><br><span class="line">Timeout:   <span class="number">30</span> * time.Second,</span><br><span class="line">KeepAlive: <span class="number">30</span> * time.Second,</span><br><span class="line">&#125;).DialContext,</span><br><span class="line">ForceAttemptHTTP2:     <span class="literal">true</span>,</span><br><span class="line">MaxIdleConns:          <span class="number">100</span>,</span><br><span class="line">IdleConnTimeout:       <span class="number">90</span> * time.Second,</span><br><span class="line">TLSHandshakeTimeout:   <span class="number">10</span> * time.Second,</span><br><span class="line">ExpectContinueTimeout: <span class="number">1</span> * time.Second,</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// DefaultMaxIdleConnsPerHost is the default value of Transport&#x27;s</span></span><br><span class="line"><span class="comment">// MaxIdleConnsPerHost.</span></span><br><span class="line"><span class="keyword">const</span> DefaultMaxIdleConnsPerHost = <span class="number">2</span></span><br></pre></td></tr></table></figure><p><code>Transport</code> is type of  <code>RoundTripper</code>, which is an interface representing the ability to execute a single HTTP transaction, obtaining the Response for a given Request. <code>RoundTripper</code> is a very important structure in <code>net/http</code> package, we’ll review (and analyze) the source code in the next article. In this article, we’ll not discuss the details. </p><p>Note that there are two parameters of <code>Transport</code>: </p><ul><li><strong>MaxIdleConns</strong>: controls the maximum number of idle (keep-alive) connections across all hosts.</li><li><strong>MaxIdleConnsPerHost</strong>: controls the maximum idle (keep-alive) connections to keep per-host. If zero, DefaultMaxIdleConnsPerHost is used.</li></ul><p>By default, MaxIdleConns is <strong>100</strong> and MaxIdleConnsPerHost is <strong>2</strong>.</p><p>In our demo case, ten goroutines send requests to the same host (which is localhost:8080). Although MaxIdleConns is 100, but <strong>only 2 idle connections can be cached</strong> for this host because MaxIdleConnsPerHost is 2. That’s why you saw much more TCP connections are established. </p><p>Based on this analysis, let’s refactor the code as follows: </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line"><span class="string">&quot;fmt&quot;</span></span><br><span class="line"><span class="string">&quot;io&quot;</span></span><br><span class="line"><span class="string">&quot;io/ioutil&quot;</span></span><br><span class="line"><span class="string">&quot;log&quot;</span></span><br><span class="line"><span class="string">&quot;net/http&quot;</span></span><br><span class="line"><span class="string">&quot;sync&quot;</span></span><br><span class="line"><span class="string">&quot;time&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> (</span><br><span class="line">httpClient *http.Client</span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">init</span><span class="params">()</span></span> &#123;</span><br><span class="line">httpClient = &amp;http.Client&#123;</span><br><span class="line">Transport: &amp;http.Transport&#123;</span><br><span class="line">MaxIdleConnsPerHost: <span class="number">10</span>, <span class="comment">// set connection pool size for each host</span></span><br><span class="line">MaxIdleConns:        <span class="number">100</span>,</span><br><span class="line">&#125;,</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">startHTTPserver</span><span class="params">()</span></span> &#123;</span><br><span class="line"></span><br><span class="line">http.HandleFunc(<span class="string">&quot;/&quot;</span>, <span class="function"><span class="keyword">func</span><span class="params">(w http.ResponseWriter, r *http.Request)</span></span> &#123;</span><br><span class="line">time.Sleep(time.Duration(<span class="number">50</span>) * time.Microsecond)</span><br><span class="line">fmt.Fprintf(w, <span class="string">&quot;Hello world&quot;</span>)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="keyword">go</span> <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">http.ListenAndServe(<span class="string">&quot;:8080&quot;</span>, <span class="literal">nil</span>)</span><br><span class="line">&#125;()</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">startHTTPRequest</span><span class="params">(index <span class="type">int</span>, wg *sync.WaitGroup)</span></span> &#123;</span><br><span class="line">counter := <span class="number">0</span></span><br><span class="line"><span class="keyword">for</span> i := <span class="number">0</span>; i &lt; <span class="number">10</span>; i++ &#123;</span><br><span class="line">resp, err := httpClient.Get(<span class="string">&quot;http://localhost:8080/&quot;</span>)</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="built_in">panic</span>(fmt.Sprintf(<span class="string">&quot;Error: %v&quot;</span>, err))</span><br><span class="line">&#125;</span><br><span class="line">io.Copy(ioutil.Discard, resp.Body) <span class="comment">// fully read the response body</span></span><br><span class="line">resp.Body.Close()                  <span class="comment">// close the response body</span></span><br><span class="line">log.Printf(<span class="string">&quot;HTTP request #%v in Goroutine #%v&quot;</span>, counter, index)</span><br><span class="line">counter += <span class="number">1</span></span><br><span class="line">time.Sleep(time.Duration(<span class="number">1</span>) * time.Second)</span><br><span class="line">&#125;</span><br><span class="line">wg.Done()</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">startHTTPserver()</span><br><span class="line"><span class="keyword">var</span> wg sync.WaitGroup</span><br><span class="line"><span class="keyword">for</span> i := <span class="number">0</span>; i &lt; <span class="number">10</span>; i++ &#123;</span><br><span class="line">wg.Add(<span class="number">1</span>)</span><br><span class="line"><span class="keyword">go</span> startHTTPRequest(i, &amp;wg)</span><br><span class="line">&#125;</span><br><span class="line">wg.Wait()</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>This time we don’t use the default httpClient, instead we create a customized client which sets MaxIdleConnsPerHost to be <strong>10</strong>. This means the size of the connection pool is changed to 10, which can cache 10 idle TCP connections for each host.</p><p>Verify the behavior with <code>netstat</code> again: </p><img src="/images/netstat-concurrent-persistent.png" title="tcp termination" width="600px" height="400px"><p>Now the result is what we expect. </p><h3 id="Summary"><a href="#Summary" class="headerlink" title="Summary"></a>Summary</h3><p>In this article, we discussed how to make HTTP/1.1 persistent connection work in a concurrent case by tunning the parameters for the connection pool. In the next article, let’s review the source code to study how to implement HTTP client.</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;Background&quot;&gt;&lt;a href=&quot;#Background&quot; class=&quot;headerlink&quot; title=&quot;Background&quot;&gt;&lt;/a&gt;Background&lt;/h3&gt;&lt;p&gt;In the &lt;a href=&quot;https://baoqger.github</summary>
      
    
    
    
    
    <category term="HTTP/1.1, concurrent" scheme="https://baoqger.github.io/tags/HTTP-1-1-concurrent/"/>
    
  </entry>
  
  <entry>
    <title>Understand how HTTP/1.1 persistent connection works based on Golang: part one - sequential requests</title>
    <link href="https://baoqger.github.io/2021/10/25/understand-http1-1-persistent-connection-golang/"/>
    <id>https://baoqger.github.io/2021/10/25/understand-http1-1-persistent-connection-golang/</id>
    <published>2021-10-25T03:11:28.000Z</published>
    <updated>2021-12-23T12:34:34.800Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Background"><a href="#Background" class="headerlink" title="Background"></a>Background</h3><p>Initially, <code>HTTP</code> was a single request-and-response model. An <code>HTTP</code> client opens the <code>TCP</code> connection, requests a resource, gets the response, and the connection is closed. And establishing and terminating each <code>TCP</code> connection is a resource-consuming operation (in detail, you can refer to my previous <a href="https://baoqger.github.io/2019/07/14/why-tcp-four-way-handshake/">article</a>). As the web application becomes more and more complex, displaying a single page may require several HTTP requests, too many TCP connection operations will have a bad impact on the performance. </p><img src="/images/short-lived-connection.png" title="tcp termination" width="400px" height="300px"><p>So <code>persistent-connection</code> (which is also called <code>keep-alive</code>) model is created in <code>HTTP/1.1</code> protocol. In this model, TCP connections keep open between several successive requests, and in this way, the time needed to open new connections will be reduced. </p><img src="/images/persistent-http.png" title="tcp termination" width="400px" height="300px"><p>In this article, I will show you how <code>persistent connection</code> works based on a Golang application. We will do some experiments based on the demo app, and verify the TCP connection behavior with some popular network packet analysis tools. In short, After reading this article, you will learn:</p><ul><li>Golang <code>http.Client</code> usage (and a little bit source code analysis)</li><li>network analysis with <code>netstat</code> and <code>tcpdump</code></li></ul><p>You can find the demo Golang application in this Github <a href="https://github.com/baoqger/http-persistent-connection-golang">repo</a>.</p><h3 id="Sequential-requests"><a href="#Sequential-requests" class="headerlink" title="Sequential requests"></a>Sequential requests</h3><p>Let’s start from the simple case where the client keeps sending <code>sequential</code> requests to the server. The <a href="https://github.com/baoqger/http-persistent-connection-golang/blob/master/sequence/non-persistent-connection/non-persistent-connection.go">code</a> goes as follows: </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line"><span class="string">&quot;fmt&quot;</span></span><br><span class="line"><span class="string">&quot;log&quot;</span></span><br><span class="line"><span class="string">&quot;net/http&quot;</span></span><br><span class="line"><span class="string">&quot;time&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">startHTTPserver</span><span class="params">()</span></span> &#123;</span><br><span class="line"></span><br><span class="line">http.HandleFunc(<span class="string">&quot;/&quot;</span>, <span class="function"><span class="keyword">func</span><span class="params">(w http.ResponseWriter, r *http.Request)</span></span> &#123;</span><br><span class="line">time.Sleep(time.Duration(<span class="number">50</span>) * time.Microsecond)</span><br><span class="line">fmt.Fprintf(w, <span class="string">&quot;Hello world&quot;</span>)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="keyword">go</span> <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">http.ListenAndServe(<span class="string">&quot;:8080&quot;</span>, <span class="literal">nil</span>)</span><br><span class="line">&#125;()</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">startHTTPRequest</span><span class="params">()</span></span> &#123;</span><br><span class="line">counter := <span class="number">0</span></span><br><span class="line"><span class="keyword">for</span> i := <span class="number">0</span>; i &lt; <span class="number">10</span>; i++ &#123;</span><br><span class="line">_, err := http.Get(<span class="string">&quot;http://localhost:8080/&quot;</span>)</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="built_in">panic</span>(fmt.Sprintf(<span class="string">&quot;Error: %v&quot;</span>, err))</span><br><span class="line">&#125;</span><br><span class="line">log.Printf(<span class="string">&quot;HTTP request #%v&quot;</span>, counter)</span><br><span class="line">counter += <span class="number">1</span></span><br><span class="line">time.Sleep(time.Duration(<span class="number">1</span>) * time.Second)</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">startHTTPserver()</span><br><span class="line"></span><br><span class="line">startHTTPRequest()</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>We start an HTTP server in a Goroutine, and keep sending ten sequential requests to it. Right? Let’s run the application and check the numbers and status of TCP connections.</p><p>After running the above code, you can see the following output: </p><img src="/images/sequential-request.png" title="tcp termination" width="800px" height="600px"><p>When the application stops running, we can run the following <code>netstat</code> command: </p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">netstat -n  | grep 8080</span><br></pre></td></tr></table></figure><p>The TCP connections are listed as follows:</p><img src="/images/sequential-request-netstat.png" title="tcp termination" width="800px" height="600px"><p>Obviously, the 10 HTTP requests are not persistent since 10 TCP connections are opened. </p><p><strong>Note</strong>: the last column of <code>netstat</code> shows the state of TCP connection. The state of TCP connection termination process can be explained with the following image: </p><img src="/images/state-tcp-connection.png" title="state tcp termination" width="600px" height="400px"><p>I will not cover the details in this article. But we need to understand the meaning of <code>TIME-WAIT</code>. </p><p>In the <code>four-way handshake</code> process, the client will send the <code>ACK</code> packet to terminate the connection, but the state of TCP can’t immediately go to <code>CLOSED</code>. The client has to wait for some time and the state in this waiting process is called <code>TIME-WAIT</code>. The TCP connection needs this <code>TIME-WAIT</code> state for two main reasons. </p><ul><li>The first is to provide enough time that the <code>ACK</code> is received by the other peer. </li><li>The second is to provide a buffer period between the end of current connection and any subsequent ones. If not for this period, it’s possible that packets from different connections could be mixed. In detail, you can refer to this <a href="http://www.tcpipguide.com/free/t_TCPConnectionTermination-3.htm">book</a>.</li></ul><p>In our demo application case, if you wait for a while after the program stops, and run the <code>netstat</code> command again then no TCP connection will be listed in the output since they’re all closed. </p><p>Another tool to verify the TCP connections is <code>tcpdump</code>, which can capture every network packet send to your machine. In our case, you can run the following <code>tcpdump</code> command: </p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo tcpdump -i any -n host localhost</span><br></pre></td></tr></table></figure><p>It will capture all the network packets send from or to the localhost (we’re running the server in localhost, right?). <code>tcpdump</code> is a great tool to help you understand the network, you can refer to its <a href="https://www.tcpdump.org/">document</a> for more help.</p><p><strong>Note</strong>: in our demo code above, we send 10 HTTP requests in sequence, which will make the capture result from <code>tcpdump</code> too long. So I modified the for loop to only send 2 sequential requests, which is enough to verify the behavior of <code>persistent connection</code>. The result goes as follows: </p><img src="/images/tcpdump-non-persistent.png" title="tcpdump" width="1200px" height="1000px"><p>In <code>tcpdump</code> output, the <code>Flag [S]</code> represents <code>SYN</code> flag, which is used to establish the TCP connection. The above snapshot contains two <code>Flag [S]</code> packets. The first <code>Flag [S]</code> is triggered by the first HTTP call, and the following packets are HTTP request and response. Then you can see the second <code>Flag [S]</code> packet to open a new TCP connection, which means the second HTTP request is not <code>persistent connection</code> as we hope. </p><p>Next step, let’s see how to make HTTP work as a persistent connection in Golang. </p><p>In fact,this is a well known issue in Golang ecosystem, you can find the information in the <a href="https://pkg.go.dev/net/http#Client">official document</a>:</p><ul><li>If the returned error is nil, the Response will contain a non-nil Body which the user is expected to close. If the Body is not both read to EOF and closed, the Client’s underlying RoundTripper (typically Transport) may not be able to re-use a persistent TCP connection to the server for a subsequent “keep-alive” request.</li></ul><p>The fix will be straightforward by just adding two more lines of code as follows: </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line"><span class="string">&quot;fmt&quot;</span></span><br><span class="line"><span class="string">&quot;io&quot;</span></span><br><span class="line"><span class="string">&quot;io/ioutil&quot;</span></span><br><span class="line"><span class="string">&quot;log&quot;</span></span><br><span class="line"><span class="string">&quot;net/http&quot;</span></span><br><span class="line"><span class="string">&quot;time&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">startHTTPServer</span><span class="params">()</span></span> &#123;</span><br><span class="line"></span><br><span class="line">http.HandleFunc(<span class="string">&quot;/&quot;</span>, <span class="function"><span class="keyword">func</span><span class="params">(w http.ResponseWriter, r *http.Request)</span></span> &#123;</span><br><span class="line">time.Sleep(time.Duration(<span class="number">50</span>) * time.Microsecond)</span><br><span class="line">fmt.Fprintf(w, <span class="string">&quot;Hello world&quot;</span>)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="keyword">go</span> <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">http.ListenAndServe(<span class="string">&quot;:8080&quot;</span>, <span class="literal">nil</span>)</span><br><span class="line">&#125;()</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">startHTTPRequest</span><span class="params">()</span></span> &#123;</span><br><span class="line">counter := <span class="number">0</span></span><br><span class="line"><span class="keyword">for</span> i := <span class="number">0</span>; i &lt; <span class="number">10</span>; i++ &#123;</span><br><span class="line">resp, err := http.Get(<span class="string">&quot;http://localhost:8080/&quot;</span>)</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="built_in">panic</span>(fmt.Sprintf(<span class="string">&quot;Error: %v&quot;</span>, err))</span><br><span class="line">&#125;</span><br><span class="line">io.Copy(ioutil.Discard, resp.Body) <span class="comment">// read the response body</span></span><br><span class="line">resp.Body.Close() <span class="comment">// close the response body</span></span><br><span class="line">log.Printf(<span class="string">&quot;HTTP request #%v&quot;</span>, counter)</span><br><span class="line">counter += <span class="number">1</span></span><br><span class="line">time.Sleep(time.Duration(<span class="number">1</span>) * time.Second)</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">startHTTPServer()</span><br><span class="line"></span><br><span class="line">startHTTPRequest()</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>let’s verify by running <code>netstat</code> command, the result goes as follows: </p><img src="/images/netstat-persistent.png" title="tcpdump" width="800px" height="600px"><p>This time 10 sequential HTTP requests establish only one TCP connection. This behavior is just what we hope: <code>persistent connection</code>.  </p><p>We can double verify it by doing the same experiment as above: run two HTTP requests in sequence and capture packets with <code>tcpdump</code>: </p><img src="/images/tcpdump-persistent.png" title="tcpdump" width="1200px" height="1000px"><p>This time, only one <code>Flag [S]</code> packet is there! The two sequential HTTP request re-use the same underlying TCP connection. </p><h3 id="Summary"><a href="#Summary" class="headerlink" title="Summary"></a>Summary</h3><p>In this article, we showed how HTTP <code>persistent connection</code> works in the case of sequential requests. In the next article, we can show you the case of concurrent requests. </p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;Background&quot;&gt;&lt;a href=&quot;#Background&quot; class=&quot;headerlink&quot; title=&quot;Background&quot;&gt;&lt;/a&gt;Background&lt;/h3&gt;&lt;p&gt;Initially, &lt;code&gt;HTTP&lt;/code&gt; was a sin</summary>
      
    
    
    
    
    <category term="HTTP/1.1, persistent connection, keep-alive, TCP, netstat, tcpdump, Golang, connection pool" scheme="https://baoqger.github.io/tags/HTTP-1-1-persistent-connection-keep-alive-TCP-netstat-tcpdump-Golang-connection-pool/"/>
    
  </entry>
  
  <entry>
    <title>why-only-13-dns-root-server</title>
    <link href="https://baoqger.github.io/2021/10/12/why-only-13-dns-root-server/"/>
    <id>https://baoqger.github.io/2021/10/12/why-only-13-dns-root-server/</id>
    <published>2021-10-12T05:48:41.000Z</published>
    <updated>2021-12-23T12:34:34.801Z</updated>
    
    
    
    
    
  </entry>
  
  <entry>
    <title>packet-sniffer-golang</title>
    <link href="https://baoqger.github.io/2021/10/08/packet-sniffer-golang/"/>
    <id>https://baoqger.github.io/2021/10/08/packet-sniffer-golang/</id>
    <published>2021-10-08T03:37:36.000Z</published>
    <updated>2021-12-23T12:34:34.798Z</updated>
    
    
    
    
    
  </entry>
  
  <entry>
    <title>how-to-build-packet-sniffer</title>
    <link href="https://baoqger.github.io/2021/10/08/how-to-build-packet-sniffer/"/>
    <id>https://baoqger.github.io/2021/10/08/how-to-build-packet-sniffer/</id>
    <published>2021-10-08T03:36:45.000Z</published>
    <updated>2021-12-23T12:34:34.794Z</updated>
    
    
    
    
    
  </entry>
  
  <entry>
    <title>cgo-golang</title>
    <link href="https://baoqger.github.io/2021/08/25/cgo-golang/"/>
    <id>https://baoqger.github.io/2021/08/25/cgo-golang/</id>
    <published>2021-08-25T08:14:36.000Z</published>
    <updated>2021-12-23T12:34:34.791Z</updated>
    
    
    
    
    
  </entry>
  
  <entry>
    <title>New way to set up Linux development environment in Windows with WSL</title>
    <link href="https://baoqger.github.io/2021/08/06/win-wsl/"/>
    <id>https://baoqger.github.io/2021/08/06/win-wsl/</id>
    <published>2021-08-06T01:19:41.000Z</published>
    <updated>2021-12-23T12:34:34.801Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Background"><a href="#Background" class="headerlink" title="Background"></a>Background</h3><p>I like system programming which can allow you to touch more software development skills in the bottom level.  </p><p>Linux is the perfect platform when you want to do system programming. But if you’re using a computer running Windows on it, then you have to spend some time to set up the Linux development environment. Generally speaking there are two traditional ways to do that: <code>virtual machine</code> and <code>dualboot</code>, both need some effort. Or you can try to do that with <code>container</code> technology, for example, I once shared one <a href="https://baoqger.github.io/2020/07/28/linux-cpp-docker/">article</a> about how to do it with <code>Docker</code>. </p><p>In this article, I will introduce a new and easier way to do this without too much overhead. </p><h3 id="Windows-Subsystem-for-Linux"><a href="#Windows-Subsystem-for-Linux" class="headerlink" title="Windows Subsystem for Linux"></a>Windows Subsystem for Linux</h3><p>The new way is <code>Windows Subsystem for Linux (WSL)</code>. I have to admit that the operating system is complex and difficult so for now I don’t know how Microsoft make <code>WSL</code> works. In details, you can refer to this <a href="https://devblogs.microsoft.com/commandline/a-deep-dive-into-how-wsl-allows-windows-to-access-linux-files/">article</a> to learn how <code>WSL</code> allows Windows to access Linux files. In this article let’s focus on how to set it up and what kind of benefits it can provide to developers.</p><p>Based on the <a href="https://docs.microsoft.com/en-us/windows/wsl/about">official document</a>, with <code>WSL</code> you can</p><ul><li>Run common command-line tools such as <code>grep</code>, <code>sed</code>, <code>awk</code>.</li><li>Run Bash shell scripts and GNU/Linux command-line applications including:<ul><li>Tools: vim, emacs, tmux.</li><li>Languages: NodeJS, Javascript, Python, Ruby, C/C++, C# &amp; F#, Rust, Go, etc.</li><li>Services: SSHD, MySQL, Apache, lighttpd, MongoDB, PostgreSQL.</li></ul></li><li>Install additional software using your own GNU/Linux distribution package manager.</li></ul><p>With these conditions, you can set up a completed Linux development environment. </p><h3 id="Install-WSL"><a href="#Install-WSL" class="headerlink" title="Install WSL"></a>Install WSL</h3><p>For detail steps to install <code>WSL</code>, you can find it on the official document. Based on my experience, I follow the document to download and install Linux Ubuntu distribution smoothly, which is much easier than settig the virtual machine.</p><h3 id="File-mount"><a href="#File-mount" class="headerlink" title="File mount"></a>File mount</h3><p>By default, you can also access your local machine’s file system from within the Linux Bash shell. Since your local drives are mounted under the <strong>/mnt</strong> folder of the subsystem. </p><p>In this way, you can develop the code with the productivity tools in Windows and build it in Linux environment.</p><h3 id="Network"><a href="#Network" class="headerlink" title="Network"></a>Network</h3><p>This is another convenient point. <code>WSL</code> shares the IP address of Windows, as it is running on Windows.<br>As such you can access any ports on localhost e.g. if you had a web server running on port 8080, you could access it just by visiting <strong><a href="http://localhost:8080">http://localhost:8080</a></strong> into your Windows browser.</p><h3 id="Set-up-the-development-environment"><a href="#Set-up-the-development-environment" class="headerlink" title="Set up the development environment"></a>Set up the development environment</h3><p>After install the Ubuntu system, I also install tools to prepare the development environment. For example, <code>GCC</code> to develop C language program as below. </p><img src="/images/linux-gcc.png" title="gcc in Linux" width="800px" height="600px"><h3 id="Summary"><a href="#Summary" class="headerlink" title="Summary"></a>Summary</h3><p>Based on my testing and experience, <code>WSL</code> can save developers’ time to set up Linux environment.  </p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;Background&quot;&gt;&lt;a href=&quot;#Background&quot; class=&quot;headerlink&quot; title=&quot;Background&quot;&gt;&lt;/a&gt;Background&lt;/h3&gt;&lt;p&gt;I like system programming which can al</summary>
      
    
    
    
    
    <category term="Linux, system programming, Windows Subsystem for Linux" scheme="https://baoqger.github.io/tags/Linux-system-programming-Windows-Subsystem-for-Linux/"/>
    
  </entry>
  
  <entry>
    <title>How to write a Golang HTTP server with Linux system calls</title>
    <link href="https://baoqger.github.io/2021/07/31/how-to-implement-simple-http-server-golang/"/>
    <id>https://baoqger.github.io/2021/07/31/how-to-implement-simple-http-server-golang/</id>
    <published>2021-07-31T02:15:25.000Z</published>
    <updated>2021-12-23T12:34:34.795Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Background"><a href="#Background" class="headerlink" title="Background"></a>Background</h3><p><code>HTTP</code> is everywhere. As a software engineer, you’re using the <code>HTTP</code> protocol every day. Starting an <code>HTTP</code> server will be an easy task if you’re using any modern language or framework. For example, in Golang you can do that with the following lines of code:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">    <span class="string">&quot;fmt&quot;</span></span><br><span class="line">    <span class="string">&quot;net/http&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">    http.HandleFunc(<span class="string">&quot;/hi&quot;</span>, <span class="function"><span class="keyword">func</span><span class="params">(w http.ResponseWriter, r *http.Request)</span></span>&#123;</span><br><span class="line">        fmt.Fprintf(w, <span class="string">&quot;Hi&quot;</span>)</span><br><span class="line">    &#125;)</span><br><span class="line"></span><br><span class="line">    log.Fatal(http.ListenAndServe(<span class="string">&quot;:8081&quot;</span>, <span class="literal">nil</span>))</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>You can finish the job easily because <code>net/http</code> package implements the <code>HTTP</code> protocol completely. How can you do that without <code>net/http</code> package ? That’s the target of this article. </p><p><strong>Note</strong>: This article is inspired by <a href="https://joe.schafer.dev/go-server-with-syscalls/">Joe Schafer’s post</a> a lot. My implementation has something different which totally removes dependency on Golang’s <code>net</code> package, but the idea of using <code>system call</code> in Golang to setup the TCP/IP connetion is the same. Thanks very much for Joe Schafer’s interesting post.</p><p>Another thing I need to mention is this article will cover many concepts, but it’s very difficult to discuss all of them in detail. To understand this article smoothly, you need some prerequisite knowledge such as <code>OSI model</code>, <code>TCP/IP stack</code>, <code>socket programming</code>, <code>HTTP protocol</code> and <code>system call</code>. I will add some explanations on these topics to help you understand this article and give some references and links to let you continue exploring more in advanced level. </p><h3 id="OSI-network-model"><a href="#OSI-network-model" class="headerlink" title="OSI network model"></a>OSI network model</h3><p><a href="https://en.wikipedia.org/wiki/OSI_model"><code>OSI model</code></a> partitions the data flow in a communication system into <strong>seven abstraction layers</strong>. These layers form a protocol stack, with each layer communicating with the layer above and the layer below as follows: </p><img src="/images/osi_model.png" title="network" width="400px" height="300px"><p>For example, <code>HTTP</code> is in <strong>layer 7</strong>, <code>TCP</code> is in <strong>layer 4</strong> and <code>IP</code> is in <strong>layer 3</strong>. </p><p>OSI is a general model, which was first specified in the early 1980s. <strong>But neither traditional nor modern networking protocols fit into this model neatly</strong>. For example, <code>TCP/IP</code> stack does not define the three upper layers: session, presentation, and application. In fact, it does not define anything above the transport layer. From the viewpoint of <code>TCP/IP</code>, everything above the transport layer is part of<br>the application. So the layered network model more  consistent with Linux (TCP/IP stack is implemented in Linux kernel) is as follows: </p><ul><li>Application Layer (telnet, ftp, http)</li><li>Host-to-Host Transport Layer (TCP, UDP)</li><li>Internet Layer (IP and routing)</li><li>Network Access Layer (Ethernet, wi-fi)</li></ul><p>Once again, <strong>it is important to point out that the upper layers—Layers 5, 6, and 7—are not part of the TCP/IP stack</strong>. </p><p>Another critical point to understand is <code>data encapsulation</code>.  The data flow goes from the bottom physical level to the highest-level representation of data in an application.</p><p>Each layer has administrative information that it has to keep about its own layer. It does this by adding header information to the packet it receives from the layer above, as the packet passes down. Each header contains information regarding the message contents. For example, one <code>HTTP</code> server sends data from one host to another. It uses the <code>TCP</code> protocol on top of the <code>IP</code> protocol, which may be sent over <code>Ethernet</code>. This looks like: </p><img src="/images/data_encapsulation.png" title="network" width="400px" height="300px"><p>The packet transmitted over ethernet, is the bottom one. On the receiving side, these headers are removed as the packet moves up.</p><p>Next let’s see how <code>TCP/IP</code> stack encapsulates <code>HTTP</code> message and send it over the network through <code>socket</code>. The idea can be illustrated with the following image: </p><img src="/images/socket_network.png" title="network" width="600px" height="400px"><p>I will explain how it works by writing a HTTP server from scratch, you can refer to this <a href="https://github.com/baoqger/http-server-scratch">Github repo</a> to get all the code. </p><h3 id="TCP-IP"><a href="#TCP-IP" class="headerlink" title="TCP/IP"></a>TCP/IP</h3><p><code>TCP/IP</code> stack is originated from <a href="https://en.wikipedia.org/wiki/ARPANET"><code>ARPANET</code></a> project, which is integrated into Unix BSD OS as the first implementation of <code>TCP/IP</code> protocols.</p><p>Nowadays, <code>TCP/IP</code> is still implemented in the operating system level. For Linux system, you can find the source code inside the kernel. The detailed implementation is outside the scope of this article. You can study it in this Github <a href="https://github.com/torvalds/linux/tree/master/net/ipv4">link</a>. </p><h3 id="Socket"><a href="#Socket" class="headerlink" title="Socket"></a>Socket</h3><p>As I mentioned in the above sections, HTTP server is running in the application level. How it can work with <code>TCP/IP</code> stack which lives in the kernel? The answer is <code>socket</code>. </p><p>The <code>socket</code> interface was originally developed as part of the BSD operating system. Sockets provide an interface between the application level programs and the TCP/IP stack. Linux (or other OS) provides an API and sockets, and applications use this API to access the networking facilities in the kernel. </p><p>The socket interface is really TCP/IP’s window on the world. In most modern systems incorporating TCP/IP, the socket interface is the only way that applications make use of the TCP/IP suite of protocols. </p><p>One main advantage of sockets in Unix or Linux system is that the socket is treated as a <code>file descriptor</code>, and all the standard I/O functions work on sockets in the same way they work on a local file. File descriptor is simply an integer associated with an open file. </p><p>You may heard <strong>everything in Unix is a file</strong>. The file can be a network connection, a pipe, a real file in the disk, a device or anything else. So when you want to send data to another program over the Interent you will do it through a file descriptor.   </p><p>In our HTTP server case, <strong>it will get the request by reading data from the socket and send the response by writing data to the socket</strong>.  </p><p>Next, let’s review the source code to see how the HTTP server is implemented.</p><p>First, we need setup the TCP connection through socket, the process can be described in the following image: </p><img src="/images/socket_tcp.png" title="network" width="600px" height="400px"><p>In Golang, <code>net</code> package provides all the socket related functionalities. Since this article’s purpose is writing a HTTP server from scratch, so I create a package named <strong>simplenet</strong> to provide the very basic implementation. </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> simplenet</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line"><span class="string">&quot;os&quot;</span></span><br><span class="line"><span class="string">&quot;syscall&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="keyword">type</span> netSocket <span class="keyword">struct</span> &#123;</span><br><span class="line">fd <span class="type">int</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">NewNetSocket</span><span class="params">(ip IP, port <span class="type">int</span>)</span></span> (*netSocket, <span class="type">error</span>) &#123;</span><br><span class="line"><span class="comment">// ForkLock docs state that socket syscall requires the lock.</span></span><br><span class="line">syscall.ForkLock.Lock()</span><br><span class="line"><span class="comment">// AF_INET = Address Family for IPv4</span></span><br><span class="line"><span class="comment">// SOCK_STREAM = virtual circuit service</span></span><br><span class="line"><span class="comment">// 0: the protocol for SOCK_STREAM, there&#x27;s only 1.</span></span><br><span class="line">fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_STREAM, <span class="number">0</span>)</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, os.NewSyscallError(<span class="string">&quot;socket&quot;</span>, err)</span><br><span class="line">&#125;</span><br><span class="line">syscall.ForkLock.Unlock()</span><br><span class="line"></span><br><span class="line"><span class="comment">// Allow reuse of recently-used addresses.</span></span><br><span class="line"><span class="keyword">if</span> err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, <span class="number">1</span>); err != <span class="literal">nil</span> &#123;</span><br><span class="line">syscall.Close(fd)</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, os.NewSyscallError(<span class="string">&quot;setsockopt&quot;</span>, err)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Bind the socket to a port</span></span><br><span class="line">sa := &amp;syscall.SockaddrInet4&#123;Port: port&#125;</span><br><span class="line"><span class="built_in">copy</span>(sa.Addr[:], ip)</span><br><span class="line"><span class="keyword">if</span> err = syscall.Bind(fd, sa); err != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, os.NewSyscallError(<span class="string">&quot;bind&quot;</span>, err)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Listen for incoming connections.</span></span><br><span class="line"><span class="keyword">if</span> err = syscall.Listen(fd, syscall.SOMAXCONN); err != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, os.NewSyscallError(<span class="string">&quot;listen&quot;</span>, err)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> &amp;netSocket&#123;fd: fd&#125;, <span class="literal">nil</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(ns netSocket)</span></span> Read(p []<span class="type">byte</span>) (<span class="type">int</span>, <span class="type">error</span>) &#123;</span><br><span class="line"><span class="keyword">if</span> <span class="built_in">len</span>(p) == <span class="number">0</span> &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>, <span class="literal">nil</span></span><br><span class="line">&#125;</span><br><span class="line">n, err := syscall.Read(ns.fd, p) <span class="comment">// read from socket file descriptor</span></span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">n = <span class="number">0</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> n, err</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(ns netSocket)</span></span> Write(p []<span class="type">byte</span>) (<span class="type">int</span>, <span class="type">error</span>) &#123;</span><br><span class="line">n, err := syscall.Write(ns.fd, p) <span class="comment">// write to socket file descriptor</span></span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">n = <span class="number">0</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> n, err</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Creates a new netSocket for the next pending connection request.</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(ns *netSocket)</span></span> Accept() (*netSocket, <span class="type">error</span>) &#123;</span><br><span class="line"><span class="comment">// syscall.ForkLock doc states lock not needed for blocking accept.</span></span><br><span class="line">nfd, _, err := syscall.Accept(ns.fd)</span><br><span class="line"><span class="keyword">if</span> err == <span class="literal">nil</span> &#123;</span><br><span class="line">syscall.CloseOnExec(nfd)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, err</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> &amp;netSocket&#123;nfd&#125;, <span class="literal">nil</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(ns *netSocket)</span></span> Close() <span class="type">error</span> &#123;</span><br><span class="line"><span class="keyword">return</span> syscall.Close(ns.fd)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>netSocket</strong> data model is created to represent the socket, which contains only one field <strong>fd</strong> means file descriptor. And all the socket related APIs: <strong>Read</strong>, <strong>Write</strong>,  <strong>Accept</strong> and <strong>Close</strong>, are defined. The usage of socket API is not in this article’s scope, you can easily find a lot of great documents about it online. </p><p>The logic of <strong>netSocket</strong> is not complicated, because it delegates the job to the kernel by <code>system call</code>. A system call is a programmatic way a program requests a service from the kernel, in detail you can refer to this <a href="https://opensource.com/article/19/10/strace">article</a>. In Golang, all the system calls are wrapped inside the <code>syscall</code> standard package.  </p><p>One thing need to mention is different platform have different <code>syscall</code> usages, so the demo code shown in this article can only be compiled and build on Linux system. </p><p>Now we setup the TCP server and wait for connection request from client side. Next, let’s see how to read or write HTTP request and response through socket. </p><h3 id="HTTP"><a href="#HTTP" class="headerlink" title="HTTP"></a>HTTP</h3><p>The main workflow is as follows: </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> (</span><br><span class="line"><span class="string">&quot;flag&quot;</span></span><br><span class="line"><span class="string">&quot;http-server-scratch/simplenet&quot;</span></span><br><span class="line"><span class="string">&quot;log&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">ipFlag := flag.String(<span class="string">&quot;ip_addr&quot;</span>, <span class="string">&quot;127.0.0.1&quot;</span>, <span class="string">&quot;The IP address to use&quot;</span>)</span><br><span class="line">portFlag := flag.Int(<span class="string">&quot;port&quot;</span>, <span class="number">8080</span>, <span class="string">&quot;The port to use.&quot;</span>)</span><br><span class="line">flag.Parse()</span><br><span class="line"></span><br><span class="line">ip := simplenet.ParseIP(*ipFlag)</span><br><span class="line">port := *portFlag</span><br><span class="line">socket, err := simplenet.NewNetSocket(ip, port)</span><br><span class="line"><span class="keyword">defer</span> socket.Close()</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="built_in">panic</span>(err)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">log.Print(<span class="string">&quot;===============&quot;</span>)</span><br><span class="line">log.Print(<span class="string">&quot;Server Started!&quot;</span>)</span><br><span class="line">log.Print(<span class="string">&quot;===============&quot;</span>)</span><br><span class="line">log.Print()</span><br><span class="line">log.Printf(<span class="string">&quot;addr: http://%s:%d&quot;</span>, ip, port)</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> &#123;</span><br><span class="line"><span class="comment">// Block until incoming connection</span></span><br><span class="line">rw, e := socket.Accept()</span><br><span class="line">log.Print()</span><br><span class="line">log.Print()</span><br><span class="line">log.Printf(<span class="string">&quot;Incoming connection&quot;</span>)</span><br><span class="line"><span class="keyword">if</span> e != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="built_in">panic</span>(e)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Read request</span></span><br><span class="line">log.Print(<span class="string">&quot;Reading request&quot;</span>)</span><br><span class="line">req, err := simplenet.ParseRequest(rw)</span><br><span class="line">log.Print(<span class="string">&quot;request: &quot;</span>, req)</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="built_in">panic</span>(err)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Write response</span></span><br><span class="line">log.Print(<span class="string">&quot;Writing response&quot;</span>)</span><br><span class="line">simplenet.WriteString(rw, <span class="string">&quot;HTTP/1.1 200 OK\r\n&quot;</span>+</span><br><span class="line"><span class="string">&quot;Content-Type: text/html; charset=utf-8\r\n&quot;</span>+</span><br><span class="line"><span class="string">&quot;Content-Length: 20\r\n&quot;</span>+</span><br><span class="line"><span class="string">&quot;\r\n&quot;</span>+</span><br><span class="line"><span class="string">&quot;&lt;h1&gt;hello world&lt;/h1&gt;&quot;</span>)</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">log.Print(err.Error())</span><br><span class="line"><span class="keyword">continue</span></span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>As you can see, the HTTP request parsing logic is defined in the <strong>ParseRequest</strong> method in <strong>simplenet</strong> package. </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> simplenet</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line"><span class="string">&quot;bufio&quot;</span></span><br><span class="line"><span class="string">&quot;errors&quot;</span></span><br><span class="line"><span class="string">&quot;http-server-scratch/simplenet/simpleTextProto&quot;</span></span><br><span class="line"><span class="string">&quot;io&quot;</span></span><br><span class="line"><span class="string">&quot;strconv&quot;</span></span><br><span class="line"><span class="string">&quot;strings&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="keyword">type</span> request <span class="keyword">struct</span> &#123;</span><br><span class="line">method <span class="type">string</span> <span class="comment">// GET, POST, etc.</span></span><br><span class="line">header simpleTextProto.MIMEHeader</span><br><span class="line">body   []<span class="type">byte</span></span><br><span class="line">uri    <span class="type">string</span> <span class="comment">// The raw URI from the request</span></span><br><span class="line">proto  <span class="type">string</span> <span class="comment">// &quot;HTTP/1.1&quot;</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">ParseRequest</span><span class="params">(c *netSocket)</span></span> (*request, <span class="type">error</span>) &#123;</span><br><span class="line">b := bufio.NewReader(*c)</span><br><span class="line">tp := simpleTextProto.NewReader(b) <span class="comment">// need replace</span></span><br><span class="line">req := <span class="built_in">new</span>(request)</span><br><span class="line"></span><br><span class="line"><span class="comment">// Parse request line: parse &quot;GET /index.html HTTP/1.0&quot;</span></span><br><span class="line"><span class="keyword">var</span> s <span class="type">string</span></span><br><span class="line">s, _ = tp.ReadLine() <span class="comment">// need replace</span></span><br><span class="line">sp := strings.Split(s, <span class="string">&quot; &quot;</span>)</span><br><span class="line">req.method, req.uri, req.proto = sp[<span class="number">0</span>], sp[<span class="number">1</span>], sp[<span class="number">2</span>]</span><br><span class="line"></span><br><span class="line"><span class="comment">// Parse request headers</span></span><br><span class="line">mimeHeader, _ := tp.ReadMIMEHeader() <span class="comment">// need replace</span></span><br><span class="line">req.header = mimeHeader</span><br><span class="line"></span><br><span class="line"><span class="comment">// Parse request body</span></span><br><span class="line"><span class="keyword">if</span> req.method == <span class="string">&quot;GET&quot;</span> || req.method == <span class="string">&quot;HEAD&quot;</span> &#123;</span><br><span class="line"><span class="keyword">return</span> req, <span class="literal">nil</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> <span class="built_in">len</span>(req.header[<span class="string">&quot;Content-Length&quot;</span>]) == <span class="number">0</span> &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, errors.New(<span class="string">&quot;no content length&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line">length, err := strconv.Atoi(req.header[<span class="string">&quot;Content-Length&quot;</span>][<span class="number">0</span>])</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, err</span><br><span class="line">&#125;</span><br><span class="line">body := <span class="built_in">make</span>([]<span class="type">byte</span>, length)</span><br><span class="line"><span class="keyword">if</span> _, err = io.ReadFull(b, body); err != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, err</span><br><span class="line">&#125;</span><br><span class="line">req.body = body</span><br><span class="line"><span class="keyword">return</span> req, <span class="literal">nil</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>The HTTP request message can be divided into three parts <code>request line</code>, <code>request headers</code> and <code>request body</code> as follows: </p><img src="/images/http_message_format.png" title="network" width="600px" height="400px"><p>The logic inside <strong>ParseRequest</strong> handles these 3 parts step by step. You can refer to the comments in the demo code. </p><p>One thing need to emphasis is that <strong>ParseRequest</strong> method doesn’t depends on <code>net</code> package. Because I want to show how HTTP server works in the bottom level, so I copy the request parsing logics from <code>net</code> package into my <code>simplenet</code> package. The parsing for request header part is kind of complex, but it doesn’t influence your understanding about the main concept of HTTP server. If you want to know the details, you can refer to the <code>simplenet/simpleTextProto</code> package. The important thing to understand is HTTP server reads the request message with <strong>Read</strong> method of <strong>netSocket</strong> . And the <strong>Read</strong> method makes socket read system call to get network data from TCP stack: </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">syscall.Read(ns.fd, p)</span><br></pre></td></tr></table></figure><p>On the other side,  HTTP response is sent back by calling <code>WriteString</code> method of <code>simplenet</code> package</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">WriteString</span><span class="params">(c *netSocket, s <span class="type">string</span>)</span></span> (n <span class="type">int</span>, err <span class="type">error</span>) &#123;</span><br><span class="line"><span class="keyword">return</span> c.Write([]<span class="type">byte</span>(s))</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>WriteString</code> simply calls <strong>Write</strong> method of <strong>netsocket</strong>, which makes socket write system call to send data over Interent with TCP stack:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">syscall.Write(ns.fd, p)</span><br></pre></td></tr></table></figure><p>That’s all for the code part. Next let’s try to run this simple HTTP server we build from scratch.</p><h3 id="Demo"><a href="#Demo" class="headerlink" title="Demo"></a>Demo</h3><p>Build (need Linux platform) and run this HTTP server with default options setting and send request to it with <code>curl</code>. The result goes as follows: </p><img src="/images/golang_http_server_demo.png" title="network" width="600px" height="400px"><p>the server works as expected. </p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;Background&quot;&gt;&lt;a href=&quot;#Background&quot; class=&quot;headerlink&quot; title=&quot;Background&quot;&gt;&lt;/a&gt;Background&lt;/h3&gt;&lt;p&gt;&lt;code&gt;HTTP&lt;/code&gt; is everywhere. As a </summary>
      
    
    
    
    
    <category term="HTTP, system call, Linux, Golang" scheme="https://baoqger.github.io/tags/HTTP-system-call-Linux-Golang/"/>
    
  </entry>
  
  <entry>
    <title>how-to-collect-metrics-k8s</title>
    <link href="https://baoqger.github.io/2021/07/14/how-to-collect-metrics-k8s/"/>
    <id>https://baoqger.github.io/2021/07/14/how-to-collect-metrics-k8s/</id>
    <published>2021-07-14T02:37:52.000Z</published>
    <updated>2021-12-23T12:34:34.794Z</updated>
    
    
    
    
    
  </entry>
  
  <entry>
    <title>how-to-implement-graphql-spec</title>
    <link href="https://baoqger.github.io/2021/07/14/how-to-implement-graphql-spec/"/>
    <id>https://baoqger.github.io/2021/07/14/how-to-implement-graphql-spec/</id>
    <published>2021-07-14T02:37:13.000Z</published>
    <updated>2021-12-23T12:34:34.795Z</updated>
    
    
    
    
    
  </entry>
  
  <entry>
    <title>How to write a load performance test CLI tool</title>
    <link href="https://baoqger.github.io/2021/07/04/how-to-deisgn-a-load-test-tool/"/>
    <id>https://baoqger.github.io/2021/07/04/how-to-deisgn-a-load-test-tool/</id>
    <published>2021-07-04T02:18:43.000Z</published>
    <updated>2021-12-23T12:34:34.794Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Background"><a href="#Background" class="headerlink" title="Background"></a>Background</h3><p>When you want to do the load performance test to your HTTP backend service, a handy and powerful tool can make your job much easier. For example, <code>ApacheBench</code> (short for <a href="https://en.wikipedia.org/wiki/ApacheBench">ab</a>) is widely used in this field. But it is not today’s topic. Instead, I want to introduce <a href="https://github.com/rakyll/hey">Hey</a> written in <code>Golang</code> and supports the same functionality as <code>ab</code>.  </p><p><code>Hey</code> usage goes as follows:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">Usage: hey [options...] &lt;url&gt;</span><br><span class="line"></span><br><span class="line">Options:</span><br><span class="line">  -n  Number of requests to run. Default is <span class="number">200.</span></span><br><span class="line">  -c  Number of workers to run concurrently. Total number of requests cannot</span><br><span class="line">      be smaller than the concurrency level. Default is <span class="number">50.</span></span><br><span class="line">  -q  Rate limit, in queries per second (QPS) per worker. Default is no rate limit.</span><br><span class="line">  -z  Duration of application to send requests. When duration is reached,</span><br><span class="line">      application stops and exits. If duration is specified, n is ignored.</span><br><span class="line">      Examples: -z <span class="number">10</span>s -z <span class="number">3</span>m.</span><br><span class="line">  ...</span><br><span class="line"><span class="comment">// other options are hidden</span></span><br></pre></td></tr></table></figure><p>I didn’t list all of the options but only show several related to this article’s content. As you can see in the above list, <code>Hey</code> can support different practical features, such as <strong>multiple workers</strong> to run in the <strong>concurrent</strong> style and <strong>rate limit</strong> by <strong>queries per second (QPS)</strong>. It can also support <strong>run by duration</strong> and <strong>run by request number</strong> two modes.</p><p>In this article, we can review the design and implementation of <code>Hey</code> to see how to make a load performance testing tool.</p><h3 id="Architecture-Design"><a href="#Architecture-Design" class="headerlink" title="Architecture Design"></a>Architecture Design</h3><p>The design of <code>Hey</code> is not complex, and the architecture can be divided into the following three parts:</p><ul><li>Control logic: the main workflow like how to set up multiple concurrent workers, how to control QPS rate limiter, and how to exit the process when duration is reached; </li><li>HTTP request configuration: the headers or parameters needed to send  request;   </li><li>Test report: print or save the result after the load testing finish. </li></ul><p>The architecture diagram goes as follows, after reading this article you’ll understand every element in this diagram: </p><img src="/images/hey.png" title="hey architecture" width="800px" height="400px"><p>This article will focus on the first item (since it is the real interesting part) to show how to use <code>Golang</code>‘s concurrent programming techniques to realize these features.</p><h3 id="Exit-the-process"><a href="#Exit-the-process" class="headerlink" title="Exit the process"></a>Exit the process</h3><p>In the <code>hey.go</code> file, you can find the entry point <strong>main</strong> function. Let’s hide the boilerplate code and review  the core logic in the <strong>main</strong> function as follows:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">   w := &amp;requester.Work&#123;</span><br><span class="line">N:  num,  <span class="comment">// number of request</span></span><br><span class="line">C:  conc, <span class="comment">// number of concurrent works</span></span><br><span class="line">QPS: q,   <span class="comment">// QPS setting </span></span><br><span class="line">results  <span class="keyword">chan</span> *result, <span class="comment">// channel for request response</span></span><br><span class="line">stopCh   <span class="keyword">chan</span> <span class="keyword">struct</span>&#123;&#125;, <span class="comment">// channle for stop the worker     </span></span><br><span class="line">       <span class="comment">//  hide the other fields</span></span><br><span class="line">   &#125;</span><br><span class="line">w.Init()</span><br><span class="line"></span><br><span class="line">c := <span class="built_in">make</span>(<span class="keyword">chan</span> os.Signal, <span class="number">1</span>)</span><br><span class="line">signal.Notify(c, os.Interrupt)</span><br><span class="line"><span class="keyword">go</span> <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">&lt;-c</span><br><span class="line">w.Stop()</span><br><span class="line">&#125;()</span><br><span class="line">   <span class="comment">// if the duration is set, then launch another goroutine</span></span><br><span class="line"><span class="keyword">if</span> dur &gt; <span class="number">0</span> &#123; </span><br><span class="line"><span class="keyword">go</span> <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">time.Sleep(dur)</span><br><span class="line">w.Stop()</span><br><span class="line">&#125;()</span><br><span class="line">&#125;</span><br><span class="line">w.Run()</span><br></pre></td></tr></table></figure><p><strong>requester.Work</strong> struct contains all the option settings, including request numbers, concurrent workers, and QPS (it also contains the test result report). </p><p>After creating an instance of <strong>requester.Work</strong>, then call the <strong>Init()</strong> method. </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(b *Work)</span></span> Init() &#123;</span><br><span class="line">b.initOnce.Do(<span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">b.results = <span class="built_in">make</span>(<span class="keyword">chan</span> *result, min(b.C*<span class="number">1000</span>, maxResult))</span><br><span class="line">b.stopCh = <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="keyword">struct</span>&#123;&#125;, b.C)</span><br><span class="line">&#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>Init()</strong> method will initialize two <code>channel</code>: <strong>results</strong> and <strong>stopCh</strong>. <strong>results</strong> channel is used for request response communication. And <strong>stopCh</strong> channel is used for signal to stop the concurrent workers.</p><p>Note that there are two ways to exit from the program. The first one is the user manually stops the program, for example, by pressing <strong>ctrl + c</strong>. In this case, the <code>signal.Notify()</code> method from the std library can catch the signal to terminate the process. The second one is by the time <strong>duration</strong> option. Both of the process exiting logics are running in a <code>Goroutine</code>. </p><p>To stop the worker, <strong>Stop()</strong> method will be called:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(b *Work)</span></span> Stop() &#123;</span><br><span class="line"><span class="comment">// Send stop signal so that workers can stop gracefully.</span></span><br><span class="line"><span class="keyword">for</span> i := <span class="number">0</span>; i &lt; b.C; i++ &#123;</span><br><span class="line">b.stopCh &lt;- <span class="keyword">struct</span>&#123;&#125;&#123;&#125;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>What it does is sending several values to the <strong>stopCh</strong> channel. Note that it sends <strong>b.C</strong> values to the channel, which is the same as the number of concurrent workers. </p><p>You can imagine that each worker should wait for the value from the <strong>stopCh</strong> channel. When the worker receives one value, it should stop sending requests. Right? Then in this way, I can stop all the concurrent workers.  Let’s check our guess in the following sections.</p><h3 id="Concurrent-Workers"><a href="#Concurrent-Workers" class="headerlink" title="Concurrent Workers"></a>Concurrent Workers</h3><p>In the above <strong>main</strong> function, you can see that <strong>Run()</strong> is called:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(b *Work)</span></span> Run() &#123;</span><br><span class="line">b.Init()</span><br><span class="line">b.start = now()</span><br><span class="line">b.report = newReport(b.writer(), b.results, b.Output, b.N)</span><br><span class="line"><span class="comment">// Run the reporter first, it polls the result channel until it is closed.</span></span><br><span class="line"><span class="keyword">go</span> <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">runReporter(b.report)</span><br><span class="line">&#125;()</span><br><span class="line">b.runWorkers()</span><br><span class="line">b.Finish()</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>There are several points worthy of discussion. In this section, let’s review <strong>runWorkers()</strong>. And <strong>runReporter()</strong> and <strong>Finish()</strong> are related to test result reports, and we will revisit them later in this article. </p><p><strong>runWorkers()</strong> goes as follows: </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(b *Work)</span></span> runWorkers() &#123;</span><br><span class="line"><span class="keyword">var</span> wg sync.WaitGroup</span><br><span class="line">wg.Add(b.C)</span><br><span class="line"></span><br><span class="line">client := &amp;http.Client&#123;</span><br><span class="line"><span class="comment">// hide details</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> i := <span class="number">0</span>; i &lt; b.C; i++ &#123;</span><br><span class="line"><span class="keyword">go</span> <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">b.runWorker(client, b.N/b.C)</span><br><span class="line">wg.Done()</span><br><span class="line">&#125;()</span><br><span class="line">&#125;</span><br><span class="line">wg.Wait() <span class="comment">// block here before all workers stop</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>This is a very typical pattern to launch multiple <code>goroutine</code> via <code>sync.WaitGroup</code>. Each worker is created by calling <strong>b.runWorker</strong> in a goroutine. In this way, multiple concurrent workers can run together. </p><p>Note that before all workers finish their tasks, <strong>wg.Wait()</strong> will block <strong>Finish()</strong> to run, which is used to report test results. And we will talk about it in the following sections.</p><p>Next step, the logic goes into <strong>runWorker</strong> method, and let’s review how <strong>QPS</strong> rate limit works? </p><h3 id="QPS"><a href="#QPS" class="headerlink" title="QPS"></a>QPS</h3><p>The core code of <strong>runWorker</strong> goes as follows:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(b *Work)</span></span> runWorker(client *http.Client, n <span class="type">int</span>) &#123;</span><br><span class="line"><span class="keyword">var</span> throttle &lt;-<span class="keyword">chan</span> time.Time</span><br><span class="line"><span class="keyword">if</span> b.QPS &gt; <span class="number">0</span> &#123;</span><br><span class="line">throttle = time.Tick(time.Duration(<span class="number">1e6</span>/(b.QPS)) * time.Microsecond)</span><br><span class="line">&#125;</span><br><span class="line">... <span class="comment">// hide some detail codes</span></span><br><span class="line"><span class="keyword">for</span> i := <span class="number">0</span>; i &lt; n; i++ &#123;</span><br><span class="line"><span class="keyword">select</span> &#123;</span><br><span class="line"><span class="keyword">case</span> &lt;-b.stopCh: <span class="comment">// receive worker stop signal from stopCh channel</span></span><br><span class="line"><span class="keyword">return</span></span><br><span class="line"><span class="keyword">default</span>:</span><br><span class="line"><span class="keyword">if</span> b.QPS &gt; <span class="number">0</span> &#123;</span><br><span class="line">&lt;-throttle <span class="comment">// receive timer signal from QPS rate limite channel</span></span><br><span class="line">&#125;</span><br><span class="line">b.makeRequest(client)</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>The first parameter of method <strong>runWorker</strong> is <strong>client</strong> for sending requests. We need more analysis about the second parameter <strong>n</strong> denoting the number of requests this worker needs to send out. When <strong>runWorker</strong> is called, <strong>b.N/b.C</strong> is passed to it. <strong>b.N</strong> is the total number of request need to be sent out, and <strong>b.C</strong> is the number of concurrent workers. <strong>b.N</strong> divided by <strong>b.C</strong> is just the number of requests for each worker. Right? </p><p>But if the user sets the <strong>duration</strong> option, what is the number of requests? You can find the following logic in the <strong>main</strong> entry function:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> dur &gt; <span class="number">0</span> &#123;</span><br><span class="line">num = math.MaxInt32 <span class="comment">// use MaxInt32</span></span><br><span class="line"><span class="keyword">if</span> conc &lt;= <span class="number">0</span> &#123;</span><br><span class="line">usageAndExit(<span class="string">&quot;-c cannot be smaller than 1.&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>When the user sets <strong>duration</strong> option, the request number will be <code>math.MaxInt32</code>. In this method, <strong>Hey</strong> can combine <strong>run by duration</strong> and <strong>run by request number</strong> two modes together. </p><p>As we mentioned in the introduction part, <code>Hey</code> can support <strong>QPS</strong> rate limit, and this strategy is written inside the <strong>runWorker</strong> method. Note that a <code>receive-only channel</code> <strong>throttle</strong> is created with <code>time.Tick</code>, which sends out a value in each time period. And the time period is defined by </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">time.Duration(<span class="number">1e6</span>/(b.QPS)) * time.Microsecond</span><br></pre></td></tr></table></figure><p>For example, <strong>QPS = 1000</strong>, then the time period is 100ms, every 100ms <strong>throttle</strong> channel will receive a value.  </p><p><strong>throttle</strong> is placed before <strong>makeRequest()</strong> call, and in this way, we can realize the rate limit effect. </p><h3 id="Stop-Worker"><a href="#Stop-Worker" class="headerlink" title="Stop Worker"></a>Stop Worker</h3><p>In the <strong>runWorker</strong> method, you can also see the <code>select and case</code> usage. </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">select</span> &#123;</span><br><span class="line"><span class="keyword">case</span> &lt;-b.stopCh: <span class="comment">// receive worker stop signal from stopCh channel</span></span><br><span class="line"><span class="keyword">return</span></span><br><span class="line"><span class="comment">// hide other code</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>As we mentioned in the above section, <strong>stopCh</strong> channel is used to stop the worker. Right? Now you can see how it is implemented. It maps to the <strong>Stop</strong> method we reviewed above as follows:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Send stop signal so that workers can stop gracefully.</span></span><br><span class="line"><span class="keyword">for</span> i := <span class="number">0</span>; i &lt; b.C; i++ &#123;</span><br><span class="line">b.stopCh &lt;- <span class="keyword">struct</span>&#123;&#125;&#123;&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>b.C</code> numbers of value are sent to <strong>stopCh</strong> channel, and there are <code>b.C</code> numbers of concurrent workers as well. Each worker can receive one value from the channel and stop running. </p><h3 id="Result-Report"><a href="#Result-Report" class="headerlink" title="Result Report"></a>Result Report</h3><p>Let’s also have a quick review of how the result report work. Firstly in the <strong>makeRequest</strong> method, each request’s result is sent to the <strong>results</strong> channel as follows: </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(b *Work)</span></span> makeRequest(c *http.Client) &#123;</span><br><span class="line"><span class="comment">// hide details</span></span><br><span class="line">b.results &lt;- &amp;result&#123;</span><br><span class="line"><span class="comment">// hide details</span></span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>And in the <code>runReporter</code> method, you can see the logic like this:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">runReporter</span><span class="params">(r *report)</span></span> &#123;</span><br><span class="line"><span class="comment">// b.results is assign to r.results in newReport() constructor</span></span><br><span class="line"><span class="keyword">for</span> res := <span class="keyword">range</span> r.results &#123; <span class="comment">// receive result from results channel</span></span><br><span class="line"><span class="comment">// append result to report struct</span></span><br><span class="line"><span class="comment">// hide details</span></span><br><span class="line">  &#125;</span><br><span class="line">  r.done &lt;- <span class="literal">true</span> <span class="comment">// send value done channel</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>In this case, a <code>for</code> is used to receive all the values from the channel. Note that <strong>the loop will continue until the channel is closed</strong>. It is another very typical concurrent programming pattern in <code>Golang</code>. We can realize the same functionality by using <code>select case</code> pattern, as long as we can add one more channel to send the exit signal. But on the syntax level, <code>for</code> loop pattern is much more cleaner.  </p><p>So there must be one place where the channel is closed, or else the <code>deadlock</code> issue will occur. In detail, you can refer to my previous <a href="https://baoqger.github.io/2020/10/26/golang-concurrent-twoways/">article</a> for more advanced explanations.  </p><p>The channel is closed in the <strong>Finish</strong> method like this: </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(b *Work)</span></span> Finish() &#123;</span><br><span class="line"><span class="built_in">close</span>(b.results)</span><br><span class="line">total := now() - b.start</span><br><span class="line"><span class="comment">// Wait until the reporter is done.</span></span><br><span class="line">&lt;-b.report.done</span><br><span class="line">b.report.finalize(total)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Please also note that how the <strong>done</strong> channel works. <strong>Finish</strong> method firstly <code>close</code> the <strong>results</strong> channel, then the <strong>for</strong> loop will break and <code>r.done &lt;- true</code> can have chance to run. Finally <strong>b.report.finalize()</strong> can print the result since <strong>&lt;-b.report.done</strong> is not blocked.  t</p><h3 id="Summary"><a href="#Summary" class="headerlink" title="Summary"></a>Summary</h3><p>In this article, I show you how to write a load performance testing CLI tool by reviewing <strong>Hey</strong> as an example. In the code level we discussed several concurrent programming patterns provided by Golang. Concurrent(or parallel) programming is difficult, and Golang is build just for that. Keep practice. </p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;Background&quot;&gt;&lt;a href=&quot;#Background&quot; class=&quot;headerlink&quot; title=&quot;Background&quot;&gt;&lt;/a&gt;Background&lt;/h3&gt;&lt;p&gt;When you want to do the load performan</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>Circuit breaker and Hystrix: part four - error rate</title>
    <link href="https://baoqger.github.io/2021/06/29/hystrix-circuit-breaker-part4/"/>
    <id>https://baoqger.github.io/2021/06/29/hystrix-circuit-breaker-part4/</id>
    <published>2021-06-29T09:19:53.000Z</published>
    <updated>2021-12-23T12:34:34.797Z</updated>
    
    
    
    
    
  </entry>
  
  <entry>
    <title>Circuit breaker and Hystrix: part three - timeout</title>
    <link href="https://baoqger.github.io/2021/06/18/hystrix-circuit-breaker-part3/"/>
    <id>https://baoqger.github.io/2021/06/18/hystrix-circuit-breaker-part3/</id>
    <published>2021-06-18T07:54:02.000Z</published>
    <updated>2021-12-23T12:34:34.796Z</updated>
    
    <content type="html"><![CDATA[<p>In the <a href="https://baoqger.github.io/2021/05/30/hystrix-circuit-breaker-part2/">previous article</a>, we reviewed the <code>max concurrent request number</code> service degradation strategy. But some detailed techniques are not explained very clearly, which will be talked about in this article. And we will analyze <code>timeout</code> strategy as well.</p><h3 id="Timeout"><a href="#Timeout" class="headerlink" title="Timeout"></a>Timeout</h3><p>Compared with <code>max concurrent request number</code> strategy, <code>timeout</code> is very straightforward to understand. </p><p>As we mentioned in the previous article, the core logic of <code>hystrix</code> is inside the <code>GoC</code> function. <code>GoC</code> function internally runs two goroutines. You already see that the first goroutine contains the logic to send request to the target service and the strategy of <code>max concurrent request number</code>. How about the second goroutine? Let’s review it as follows:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">go</span> <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">timer := time.NewTimer(getSettings(name).Timeout)</span><br><span class="line"><span class="keyword">defer</span> timer.Stop()</span><br><span class="line"></span><br><span class="line"><span class="keyword">select</span> &#123;</span><br><span class="line"><span class="keyword">case</span> &lt;-cmd.finished:</span><br><span class="line"><span class="comment">// returnOnce has been executed in another goroutine</span></span><br><span class="line"><span class="keyword">case</span> &lt;-ctx.Done():</span><br><span class="line">returnOnce.Do(<span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">returnTicket()</span><br><span class="line">cmd.errorWithFallback(ctx, ctx.Err())</span><br><span class="line">reportAllEvent()</span><br><span class="line">&#125;)</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line"><span class="keyword">case</span> &lt;-timer.C:</span><br><span class="line">returnOnce.Do(<span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">returnTicket()</span><br><span class="line">cmd.errorWithFallback(ctx, ErrTimeout)</span><br><span class="line">reportAllEvent()</span><br><span class="line">&#125;)</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">&#125;</span><br><span class="line">&#125;()</span><br></pre></td></tr></table></figure><p>Note that A <strong>Timer</strong> is created with the timeout duration value from the settings. And a <code>select</code> statement lets this goroutine wait until one <code>case</code> condition receives value from the channel. The <strong>timeout</strong> case is just the 3nd one (when the first two cases are not triggered), which will run fallback logic with <strong>ErrTimeout</strong> error message. </p><p>So far you should be clear about the main structure and functionalities of these two goroutines. But in detail, there are two Golang techniques need your attention: <code>sync.Once</code> and <code>sync.Cond</code>.  </p><h3 id="sync-Once"><a href="#sync-Once" class="headerlink" title="sync.Once"></a>sync.Once</h3><p>You may already notice the following code block, which is repeated several times inside <code>GoC</code> function. </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">returnOnce.Do(<span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">returnTicket()</span><br><span class="line">cmd.errorWithFallback(ctx, ErrTimeout) <span class="comment">// with various error types </span></span><br><span class="line">reportAllEvent()</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p><strong>returnOnce</strong> is type of <code>sync.Once</code>, which makes sure that the callback function of <code>Do</code> method only runs once among different goroutines. </p><p>In this specific case, it can guarantee that both <strong>returnTicket()</strong> and <strong>reportAllEvent()</strong> execute only once. This really makes sense, because if <strong>returnTicket()</strong> runs multiple times for one <code>GoC</code> call, then the current concurrent request number will not be correct, right? </p><p>I wrote another article about <code>sync.Once</code> in detail, you can refer to <a href="https://baoqger.github.io/2021/05/11/golang-sync-once/">that article</a> for more in-depth explanation. </p><h3 id="sync-Cond"><a href="#sync-Cond" class="headerlink" title="sync.Cond"></a>sync.Cond</h3><p>The implementation of <strong>returnTicket</strong> function goes as follows:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">ticketCond := sync.NewCond(cmd)</span><br><span class="line">ticketChecked := <span class="literal">false</span></span><br><span class="line">returnTicket := <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">cmd.Lock()</span><br><span class="line"><span class="keyword">for</span> !ticketChecked &#123;</span><br><span class="line">ticketCond.Wait() <span class="comment">// hang the current goroutine</span></span><br><span class="line">&#125;</span><br><span class="line">cmd.circuit.executorPool.Return(cmd.ticket)</span><br><span class="line">cmd.Unlock()</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>ticketCond</strong> is a condition variable, and in Golang it is type of <code>sync.Cond</code>. </p><p>Condition variable is useful in communication between different goroutines. Concretely, <code>Wait</code> method of <code>sync.Cond</code>will hung the current goroutine, and <code>Signal</code> method will wake up the blocking goroutine to continue executing. </p><p>In <code>hystrix</code> case , when <strong>ticketChecked</strong> is <strong>false</strong>, which means the current <code>GoC</code> call is not finished and the <strong>ticket</strong> should not be returned yet. So <strong>ticketCond.Wait()</strong> is called to block this goroutine and wait until the <code>GoC</code> call is completed which is notified by <code>Signal</code> method. </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">ticketChecked = <span class="literal">true</span></span><br><span class="line">ticketCond.Signal()</span><br></pre></td></tr></table></figure><p>Note that the above two lines of code are always called together. <strong>ticketChecked</strong> is set to <strong>true</strong> means that the current <code>GoC</code> call is finished and the <strong>ticket</strong> is ready to return. Moreover, the <code>Wait</code> method to hang the goroutine is placed inside a <strong>for</strong> loop, which is also a best practise technique. </p><p>For more explanation about <code>sync.Cond</code>, please refer to my <a href="https://baoqger.github.io/2021/05/14/golang-sync-cond/">another article</a>.</p><h3 id="Fallback"><a href="#Fallback" class="headerlink" title="Fallback"></a>Fallback</h3><p>Finally, let’s see how <strong>fallback</strong> function is called when the target service is not responsive. </p><p>Let’s recall that each <code>GoC</code> call will create a new <strong>command</strong> instance. And <strong>fallback</strong> function will be assigned to the field with the same name, which will be used later. </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">cmd := &amp;command&#123;</span><br><span class="line">run:      run,</span><br><span class="line">fallback: fallback, <span class="comment">// fallback logic here</span></span><br><span class="line">start:    time.Now(),</span><br><span class="line">errChan:  <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="type">error</span>, <span class="number">1</span>),</span><br><span class="line">finished: <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="type">bool</span>, <span class="number">1</span>),</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>As we see in above sections, <strong>errorWithFallback</strong> method is triggered when <code>timeout</code> or <code>max concurrent request number</code> threshold is met.   </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(c *command)</span></span> errorWithFallback(ctx context.Context, err <span class="type">error</span>) &#123;</span><br><span class="line">eventType := <span class="string">&quot;failure&quot;</span></span><br><span class="line"><span class="keyword">if</span> err == ErrCircuitOpen &#123;</span><br><span class="line">eventType = <span class="string">&quot;short-circuit&quot;</span></span><br><span class="line">&#125; <span class="keyword">else</span> <span class="keyword">if</span> err == ErrMaxConcurrency &#123;</span><br><span class="line">eventType = <span class="string">&quot;rejected&quot;</span></span><br><span class="line">&#125; <span class="keyword">else</span> <span class="keyword">if</span> err == ErrTimeout &#123;</span><br><span class="line">eventType = <span class="string">&quot;timeout&quot;</span></span><br><span class="line">&#125; <span class="keyword">else</span> <span class="keyword">if</span> err == context.Canceled &#123;</span><br><span class="line">eventType = <span class="string">&quot;context_canceled&quot;</span></span><br><span class="line">&#125; <span class="keyword">else</span> <span class="keyword">if</span> err == context.DeadlineExceeded &#123;</span><br><span class="line">eventType = <span class="string">&quot;context_deadline_exceeded&quot;</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">c.reportEvent(eventType)</span><br><span class="line">fallbackErr := c.tryFallback(ctx, err)</span><br><span class="line"><span class="keyword">if</span> fallbackErr != <span class="literal">nil</span> &#123;</span><br><span class="line">c.errChan &lt;- fallbackErr</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>errorWithFallback</strong> method will run the fallback by calling <strong>tryFallback</strong> and report the metric events such as <strong>fallback-failure</strong> and <strong>fallback-success</strong>(will discuss metric collection in next article).</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(c *command)</span></span> tryFallback(ctx context.Context, err <span class="type">error</span>) <span class="type">error</span> &#123;</span><br><span class="line"><span class="keyword">if</span> c.fallback == <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span> err</span><br><span class="line">&#125;</span><br><span class="line">fallbackErr := c.fallback(ctx, err) <span class="comment">// execute the fallback logic here</span></span><br><span class="line"><span class="keyword">if</span> fallbackErr != <span class="literal">nil</span> &#123;</span><br><span class="line">c.reportEvent(<span class="string">&quot;fallback-failure&quot;</span>)</span><br><span class="line"><span class="keyword">return</span> fmt.Errorf(<span class="string">&quot;fallback failed with &#x27;%v&#x27;. run error was &#x27;%v&#x27;&quot;</span>, fallbackErr, err)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">c.reportEvent(<span class="string">&quot;fallback-success&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="Summary"><a href="#Summary" class="headerlink" title="Summary"></a>Summary</h3><p>In this article, we talked about the <code>timeout</code> strategy which is the simplest one among all the strategies provided by <code>hystrix</code>. Some detailed Golang techniques are reviewed as well to have a better understand the complex code logic. </p><p>In the next article let’s see how to collect metrics in <code>hystrix</code> to realize the <code>error rate</code> strategy. </p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;In the &lt;a href=&quot;https://baoqger.github.io/2021/05/30/hystrix-circuit-breaker-part2/&quot;&gt;previous article&lt;/a&gt;, we reviewed the &lt;code&gt;max conc</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>Circuit breaker and Hystrix: part two - max concurrent requests</title>
    <link href="https://baoqger.github.io/2021/05/30/hystrix-circuit-breaker-part2/"/>
    <id>https://baoqger.github.io/2021/05/30/hystrix-circuit-breaker-part2/</id>
    <published>2021-05-30T08:41:20.000Z</published>
    <updated>2021-12-23T12:34:34.796Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Background"><a href="#Background" class="headerlink" title="Background"></a>Background</h3><p>In the second article of this series, I will review the source code of <code>hystrix-go</code> project to understand how to design a <code>circuit breaker</code> and how to implement it with Golang. </p><p>If you’re not familiar with <code>circuit breaker</code> pattern or <code>hystrix-go</code> project, please check my previous <a href="https://baoqger.github.io/2021/05/21/hystric-circuit-breaker-part1/">article</a> about it.  </p><h3 id="Three-service-degradation-strategies"><a href="#Three-service-degradation-strategies" class="headerlink" title="Three service degradation strategies"></a>Three service degradation strategies</h3><p><code>Hystrix</code> provides three different service degradation strategies to avoid the <code>cascading failure</code> happening in the entire system: <code>timeout</code>, <code>maximum concurrent request numbers</code> and <code>request error rate</code>. </p><ul><li><strong>timeout</strong>: if the service call doesn’t return response successfully within a predefined time duration, then the fallback logic will run. This strategy is the simplest one. </li><li><strong>maximum concurrent request numbers</strong>: when the number of concurrent requests is beyond the threshold, then the fallback logic will handle the following request. </li><li><strong>request error rate</strong>: <code>hystrix</code> will record the response status of each service call, after the error rate reaches the threshold, the breaker will be open, and the fallback logic will execute before the breaker status changes back to closed. <code>error rate</code> strategy is the most complex one. </li></ul><p>This can be seen from the basic usage of <code>hystrix</code> as follows:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> (</span><br><span class="line">    <span class="string">&quot;github.com/afex/hystrix-go/hystrix&quot;</span></span><br><span class="line">    <span class="string">&quot;time&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line">hystrix.ConfigureCommand(<span class="string">&quot;my_command&quot;</span>, hystrix.CommandConfig&#123;</span><br><span class="line">Timeout:               <span class="type">int</span>(<span class="number">10</span> * time.Second),</span><br><span class="line">MaxConcurrentRequests: <span class="number">100</span>,</span><br><span class="line">ErrorPercentThreshold: <span class="number">25</span>,</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">hystrix.Go(<span class="string">&quot;my_command&quot;</span>, <span class="function"><span class="keyword">func</span><span class="params">()</span></span> <span class="type">error</span> &#123;</span><br><span class="line"><span class="comment">// talk to dependency services</span></span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span></span><br><span class="line">&#125;, <span class="function"><span class="keyword">func</span><span class="params">(err <span class="type">error</span>)</span></span> <span class="type">error</span> &#123;</span><br><span class="line"><span class="comment">// fallback logic when services are down</span></span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span></span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>In the above usage case, you can see that <code>timeout</code> is set to 10 seconds, the maximum request number is 100, and the error rate threshold is 25 percentages.</p><p>In the consumer application level, that’s nearly all of the configuration you need to setup. <code>hystrix</code> will make the magin happen internally. </p><p>In this series of articles, I plan to show you the internals of <code>hystrix</code> by reviewing the source code. </p><p>Let’s start from the easy ones: <code>max concurrent requests</code> and <code>timeout</code>. Then move on to explore the complex strategy <code>request error rate</code>. </p><h3 id="GoC"><a href="#GoC" class="headerlink" title="GoC"></a>GoC</h3><p>Based on the above example, you can see <code>Go</code> function is the door to the source code of <code>hystrix</code>, so let’s start from it as follows: </p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">Go</span><span class="params">(name <span class="type">string</span>, run runFunc, fallback fallbackFunc)</span></span> <span class="keyword">chan</span> <span class="type">error</span> &#123;</span><br><span class="line">runC := <span class="function"><span class="keyword">func</span><span class="params">(ctx context.Context)</span></span> <span class="type">error</span> &#123;</span><br><span class="line"><span class="keyword">return</span> run()</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">var</span> fallbackC fallbackFuncC</span><br><span class="line"><span class="keyword">if</span> fallback != <span class="literal">nil</span> &#123;</span><br><span class="line">fallbackC = <span class="function"><span class="keyword">func</span><span class="params">(ctx context.Context, err <span class="type">error</span>)</span></span> <span class="type">error</span> &#123;</span><br><span class="line"><span class="keyword">return</span> fallback(err)</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> GoC(context.Background(), name, runC, fallbackC)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>Go</code> function accept three parameters: </p><ul><li><strong>name</strong>: the command name, which is bound to the <code>circuit</code> created inside hystrix. </li><li><strong>run</strong>: a function contains the normal logic which send request to the dependency service.</li><li><strong>fallback</strong>: a function contains the fallback logic.</li></ul><p><code>Go</code> function just wraps <code>run</code> and <code>fallback</code> with <code>Context</code>, which is used to control and cancel goroutine, if you’re not familiar with it then refer to my previous <a href="https://baoqger.github.io/2021/04/26/golang-context-source-code/">article</a>. Finally it will call <code>GoC</code> function.</p><p><code>GoC</code> function goes as follows: </p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">GoC</span><span class="params">(ctx context.Context, name <span class="type">string</span>, run runFuncC, fallback fallbackFuncC)</span></span> <span class="keyword">chan</span> <span class="type">error</span> &#123;</span><br><span class="line"><span class="comment">// construct a new command instance</span></span><br><span class="line">cmd := &amp;command&#123;</span><br><span class="line">run:      run,</span><br><span class="line">fallback: fallback,</span><br><span class="line">start:    time.Now(),</span><br><span class="line">errChan:  <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="type">error</span>, <span class="number">1</span>),</span><br><span class="line">finished: <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="type">bool</span>, <span class="number">1</span>),</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// get circuit by command name</span></span><br><span class="line">circuit, _, err := GetCircuit(name)</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">cmd.errChan &lt;- err</span><br><span class="line"><span class="keyword">return</span> cmd.errChan</span><br><span class="line">&#125;</span><br><span class="line">cmd.circuit = circuit</span><br><span class="line"><span class="comment">//declare a condition variable sync.Cond: ticketCond, to synchronize among goroutines</span></span><br><span class="line"><span class="comment">//declare a flag variable: ticketChecked, work together with ticketCond</span></span><br><span class="line">ticketCond := sync.NewCond(cmd)</span><br><span class="line">ticketChecked := <span class="literal">false</span></span><br><span class="line"><span class="comment">// declare a function: returnTicket, will execute when a concurrent request is done to return `ticket`</span></span><br><span class="line">returnTicket := <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">cmd.Lock()</span><br><span class="line"><span class="keyword">for</span> !ticketChecked &#123;</span><br><span class="line">ticketCond.Wait()</span><br><span class="line">&#125;</span><br><span class="line">cmd.circuit.executorPool.Return(cmd.ticket)</span><br><span class="line">cmd.Unlock()</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// declare a sync.Once instance: returnOnce, make sure the returnTicket function execute only once</span></span><br><span class="line">returnOnce := &amp;sync.Once&#123;&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// declare another function: reportAllEvent, used to collect the metrics</span></span><br><span class="line">reportAllEvent := <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">err := cmd.circuit.ReportEvent(cmd.events, cmd.start, cmd.runDuration)</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">log.Printf(err.Error())</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// launch a goroutine which executes the `run` logic</span></span><br><span class="line"><span class="keyword">go</span> <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line"><span class="keyword">defer</span> <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123; cmd.finished &lt;- <span class="literal">true</span> &#125;()</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> !cmd.circuit.AllowRequest() &#123;</span><br><span class="line">cmd.Lock()</span><br><span class="line">ticketChecked = <span class="literal">true</span></span><br><span class="line">ticketCond.Signal()</span><br><span class="line">cmd.Unlock()</span><br><span class="line">returnOnce.Do(<span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">returnTicket()</span><br><span class="line">cmd.errorWithFallback(ctx, ErrCircuitOpen)</span><br><span class="line">reportAllEvent()</span><br><span class="line">&#125;)</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">cmd.Lock()</span><br><span class="line"><span class="keyword">select</span> &#123;</span><br><span class="line"><span class="keyword">case</span> cmd.ticket = &lt;-circuit.executorPool.Tickets:</span><br><span class="line">ticketChecked = <span class="literal">true</span></span><br><span class="line">ticketCond.Signal()</span><br><span class="line">cmd.Unlock()</span><br><span class="line"><span class="keyword">default</span>:</span><br><span class="line">ticketChecked = <span class="literal">true</span></span><br><span class="line">ticketCond.Signal()</span><br><span class="line">cmd.Unlock()</span><br><span class="line">returnOnce.Do(<span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">returnTicket()</span><br><span class="line">cmd.errorWithFallback(ctx, ErrMaxConcurrency)</span><br><span class="line">reportAllEvent()</span><br><span class="line">&#125;)</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">runStart := time.Now()</span><br><span class="line">runErr := run(ctx)</span><br><span class="line">returnOnce.Do(<span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line"><span class="keyword">defer</span> reportAllEvent()</span><br><span class="line">cmd.runDuration = time.Since(runStart)</span><br><span class="line">returnTicket()</span><br><span class="line"><span class="keyword">if</span> runErr != <span class="literal">nil</span> &#123;</span><br><span class="line">cmd.errorWithFallback(ctx, runErr)</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">&#125;</span><br><span class="line">cmd.reportEvent(<span class="string">&quot;success&quot;</span>)</span><br><span class="line">&#125;)</span><br><span class="line">&#125;()</span><br><span class="line"><span class="comment">// launch the second goroutine for timeout strategy</span></span><br><span class="line"><span class="keyword">go</span> <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">timer := time.NewTimer(getSettings(name).Timeout)</span><br><span class="line"><span class="keyword">defer</span> timer.Stop()</span><br><span class="line"></span><br><span class="line"><span class="keyword">select</span> &#123;</span><br><span class="line"><span class="keyword">case</span> &lt;-cmd.finished:</span><br><span class="line"><span class="keyword">case</span> &lt;-ctx.Done():</span><br><span class="line">returnOnce.Do(<span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">returnTicket()</span><br><span class="line">cmd.errorWithFallback(ctx, ctx.Err())</span><br><span class="line">reportAllEvent()</span><br><span class="line">&#125;)</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line"><span class="keyword">case</span> &lt;-timer.C:</span><br><span class="line">returnOnce.Do(<span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">returnTicket()</span><br><span class="line">cmd.errorWithFallback(ctx, ErrTimeout)</span><br><span class="line">reportAllEvent()</span><br><span class="line">&#125;)</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">&#125;</span><br><span class="line">&#125;()</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> cmd.errChan</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>I admit it’s complex, but it’s also the core of the entire <code>hystrix</code> project. Be patient, let’s review it bit by bit carefully. </p><p>First of all, the code structure of <code>GoC</code> function is as follows:</p><p><img src="/images/GoC-hystrix.png" alt="GoC"></p><ol><li>Construct a new <code>Command</code> object, which contains all the information for each call to <code>GoC</code> function.</li><li>Get the <code>circuit breaker</code> by name (create it if it doesn’t exist) by calling <code>GetCircuit(name)</code> function.</li><li>Declare condition variable <strong>ticketCond</strong> and <strong>ticketChecked</strong> with <code>sync.Cond</code> which is used to communicate between goroutines. </li><li>Declare function <strong>returnTicket</strong>. What is a <strong>ticket</strong>? What does it mean by <strong>returnTicket</strong>? Let’s discuss it in detail later.</li><li>Declare another function <strong>reportAllEvent</strong>. This function is critical to <code>error rate</code> strategy, and we can leave it for detailed review in the following articles. </li><li>Declare an instance of <code>sync.Once</code>, which is another interesting <code>synchronization primitives</code> provided by golang.</li><li>Launch two goroutines, each of which contains many logics too. Simply speaking, the first one contains the logic of sending requests to the target service and the strategy of <code>max concurrent request number</code>, and the second one contains the <code>timeout</code> strategy. </li><li>Return a <code>channel</code> type value</li></ol><p>Let’s review each of them one by one. </p><h3 id="command"><a href="#command" class="headerlink" title="command"></a>command</h3><p><code>command</code> struct goes as follows, which embeds <strong>sync.Mutex</strong> and defines several fields: </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> command <span class="keyword">struct</span> &#123;</span><br><span class="line">sync.Mutex</span><br><span class="line"></span><br><span class="line">ticket      *<span class="keyword">struct</span>&#123;&#125;</span><br><span class="line">start       time.Time</span><br><span class="line">errChan     <span class="keyword">chan</span> <span class="type">error</span></span><br><span class="line">finished    <span class="keyword">chan</span> <span class="type">bool</span></span><br><span class="line">circuit     *CircuitBreaker</span><br><span class="line">run         runFuncC</span><br><span class="line">fallback    fallbackFuncC</span><br><span class="line">runDuration time.Duration</span><br><span class="line">events      []<span class="type">string</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Note that <code>command</code> object iteself doesn’t contain command name information, and its lifecycle is just inside the scope of one <code>GoC</code> call. It means that the statistic metrics about the service request like <code>error rate</code> and <code>concurrent request number</code> are not stored inside command object. Instead, such metrics are stored inside <strong>circuit</strong> field which is <code>CircuitBreaker</code> type. </p><h3 id="CircuitBreaker"><a href="#CircuitBreaker" class="headerlink" title="CircuitBreaker"></a>CircuitBreaker</h3><p>As we mentioned in the workflow of <code>GoC</code> function, <code>GetCircuit(name)</code> is called to get or create the <code>circuit breaker</code>. It is implemented inside <code>circuit.go</code> file as follows:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">init</span><span class="params">()</span></span> &#123;</span><br><span class="line">circuitBreakersMutex = &amp;sync.RWMutex&#123;&#125;</span><br><span class="line">circuitBreakers = <span class="built_in">make</span>(<span class="keyword">map</span>[<span class="type">string</span>]*CircuitBreaker)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">GetCircuit</span><span class="params">(name <span class="type">string</span>)</span></span> (*CircuitBreaker, <span class="type">bool</span>, <span class="type">error</span>) &#123;</span><br><span class="line">circuitBreakersMutex.RLock()</span><br><span class="line">_, ok := circuitBreakers[name]</span><br><span class="line"><span class="keyword">if</span> !ok &#123;</span><br><span class="line">circuitBreakersMutex.RUnlock()</span><br><span class="line">circuitBreakersMutex.Lock()</span><br><span class="line"><span class="keyword">defer</span> circuitBreakersMutex.Unlock()</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> cb, ok := circuitBreakers[name]; ok &#123;</span><br><span class="line"><span class="keyword">return</span> cb, <span class="literal">false</span>, <span class="literal">nil</span></span><br><span class="line">&#125;</span><br><span class="line">circuitBreakers[name] = newCircuitBreaker(name)</span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line"><span class="keyword">defer</span> circuitBreakersMutex.RUnlock()</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> circuitBreakers[name], !ok, <span class="literal">nil</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>The logic is very straightforward. All the circuit breakers are stored in a map object <strong>circuitBreakers</strong> with the <strong>command name</strong> as the key. </p><p>The <code>newCircuitBreaker</code> constructor function and <code>CircuitBreaker</code> struct are as follows: </p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> CircuitBreaker <span class="keyword">struct</span> &#123;</span><br><span class="line">Name                   <span class="type">string</span></span><br><span class="line">open                   <span class="type">bool</span></span><br><span class="line">forceOpen              <span class="type">bool</span></span><br><span class="line">mutex                  *sync.RWMutex</span><br><span class="line">openedOrLastTestedTime <span class="type">int64</span></span><br><span class="line"></span><br><span class="line">executorPool *executorPool   <span class="comment">// used in the strategy of max concurrent request number </span></span><br><span class="line">metrics      *metricExchange <span class="comment">// used in the strategy of request error rate</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">newCircuitBreaker</span><span class="params">(name <span class="type">string</span>)</span></span> *CircuitBreaker &#123;</span><br><span class="line">c := &amp;CircuitBreaker&#123;&#125;</span><br><span class="line">c.Name = name</span><br><span class="line">c.metrics = newMetricExchange(name)</span><br><span class="line">c.executorPool = newExecutorPool(name)</span><br><span class="line">c.mutex = &amp;sync.RWMutex&#123;&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> c</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>All the fields of <code>CircuitBreaker</code> are important to understand how the breaker works.</p><img src="/images/circuitbreakstruct.png" title="circuitbreak" width="300px" height="400px"><p>There are two fields that are not simple type need more analysis, include <code>executorPool</code> and <code>metrics</code>. </p><ul><li><strong>executorPool</strong>: used for <code>max concurrent request number</code> strategy, which is just this article’s topic.</li><li><strong>metrics</strong>: used for <code>request error rate</code> strategy, which will be discussed in the next article, all right? </li></ul><h3 id="executorPool"><a href="#executorPool" class="headerlink" title="executorPool"></a>executorPool</h3><p>We can find <code>executorPool</code> logics inside the <code>pool.go</code> file:</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> executorPool <span class="keyword">struct</span> &#123;</span><br><span class="line">Name    <span class="type">string</span></span><br><span class="line">Metrics *poolMetrics</span><br><span class="line">Max     <span class="type">int</span></span><br><span class="line">Tickets <span class="keyword">chan</span> *<span class="keyword">struct</span>&#123;&#125; <span class="comment">// Tickets channel </span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">newExecutorPool</span><span class="params">(name <span class="type">string</span>)</span></span> *executorPool &#123;</span><br><span class="line">p := &amp;executorPool&#123;&#125;</span><br><span class="line">p.Name = name</span><br><span class="line">p.Metrics = newPoolMetrics(name)</span><br><span class="line">p.Max = getSettings(name).MaxConcurrentRequests</span><br><span class="line"></span><br><span class="line">p.Tickets = <span class="built_in">make</span>(<span class="keyword">chan</span> *<span class="keyword">struct</span>&#123;&#125;, p.Max)</span><br><span class="line"><span class="comment">// send Max numbers of value into the Tickets channel</span></span><br><span class="line"><span class="keyword">for</span> i := <span class="number">0</span>; i &lt; p.Max; i++ &#123;</span><br><span class="line">p.Tickets &lt;- &amp;<span class="keyword">struct</span>&#123;&#125;&#123;&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> p</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>It makes use of golang <code>channel</code> to realize <code>max concurrent request number</code> strategy. Note that <code>Tickets</code> field, which is a buffered channel with capicity of <strong>MaxConcurrentRequests</strong> is created. And in the following <strong>for</strong> loop, make the buffered channel full by sending value into the channel until reaching the capacity. </p><p>As we have shown above, in the first goroutine of <code>GoC</code> function, the <code>Tickets</code> channel is used as follows:</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">go</span> <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">...</span><br><span class="line"><span class="keyword">select</span> &#123;</span><br><span class="line"><span class="keyword">case</span> cmd.ticket = &lt;-circuit.executorPool.Tickets: <span class="comment">// receive ticket from Tickets channel</span></span><br><span class="line">ticketChecked = <span class="literal">true</span></span><br><span class="line">ticketCond.Signal()</span><br><span class="line">cmd.Unlock()</span><br><span class="line"><span class="keyword">default</span>:</span><br><span class="line">ticketChecked = <span class="literal">true</span></span><br><span class="line">ticketCond.Signal()</span><br><span class="line">cmd.Unlock()</span><br><span class="line">returnOnce.Do(<span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">returnTicket()</span><br><span class="line">cmd.errorWithFallback(ctx, ErrMaxConcurrency) <span class="comment">// run fallback logic when concurrent requests reach threshold</span></span><br><span class="line">reportAllEvent()</span><br><span class="line">&#125;)</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">&#125;</span><br><span class="line">...</span><br><span class="line">&#125;()</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>Each call to <code>GoC</code> function will get a <strong>ticket</strong> from <strong>circuit.executorPool.Tickets</strong> channel until no <strong>ticket</strong> is left, which means the number of concurrent requests reaches the threshold. In that case, the <code>default</code> case will execute , and the service will be gracefully degraded with fallback logic.</p><p>On the other side, after each call to <code>GoC</code> is done, the <strong>ticket</strong> need to be sent back to the <strong>circuit.executorPool.Tickets</strong>, right? Do you remember the <code>returnTicket</code> function mentioned in above section. Yes, it is just used for this purpose. The <code>returnTicket</code> function defined in <code>GoC</code> function goes as follows:</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">returnTicket := <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">cmd.Lock()</span><br><span class="line"><span class="keyword">for</span> !ticketChecked &#123;</span><br><span class="line">ticketCond.Wait()</span><br><span class="line">&#125;</span><br><span class="line">cmd.circuit.executorPool.Return(cmd.ticket) <span class="comment">// return ticket to the executorPool</span></span><br><span class="line">cmd.Unlock()</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>It calls <code>executorPool.Return</code> function: </p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Return function in pool.go file</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(p *executorPool)</span></span> Return(ticket *<span class="keyword">struct</span>&#123;&#125;) &#123;</span><br><span class="line"><span class="keyword">if</span> ticket == <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">p.Metrics.Updates &lt;- poolMetricsUpdate&#123;</span><br><span class="line">activeCount: p.ActiveCount(),</span><br><span class="line">&#125;</span><br><span class="line">p.Tickets &lt;- ticket <span class="comment">// send ticket back to Tickets channel</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>The design and implementation of <strong>Tickets</strong> is a great example of <code>golang channel</code> in the real-world application.  </p><p>In summary, the <code>max concurrent request number</code> strategy can be illustrated as follows:</p><img src="/images/hystrix-concurrent-architecture.png" title="circuitbreak" width="800px" height="400px"><h3 id="Summary"><a href="#Summary" class="headerlink" title="Summary"></a>Summary</h3><p>In this article, <code>max concurrent requests</code> strategy in <code>hystrix</code> is reviewed carefully, and I hope you can learn something interesting from it.</p><p>But I didn’t cover the detailed logics inside <code>GoC</code> function, including <code>sync.Cond</code>, <code>sync.Once</code> and fallback logics. Let’s review them and <code>timeout</code> strategy together in the next article. </p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;Background&quot;&gt;&lt;a href=&quot;#Background&quot; class=&quot;headerlink&quot; title=&quot;Background&quot;&gt;&lt;/a&gt;Background&lt;/h3&gt;&lt;p&gt;In the second article of this series, </summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>Circuit breaker and Hystrix: part one - introduction</title>
    <link href="https://baoqger.github.io/2021/05/21/hystric-circuit-breaker-part1/"/>
    <id>https://baoqger.github.io/2021/05/21/hystric-circuit-breaker-part1/</id>
    <published>2021-05-21T07:25:19.000Z</published>
    <updated>2021-12-23T12:34:34.796Z</updated>
    
    <content type="html"><![CDATA[<p>In this series of articles, I want to talk about <code>circuit breaker</code> pattern based on an popular open source project <code>hystrix</code> (in fact, I will take a look at the golang version <a href="https://github.com/afex/hystrix-go">hystrix-go</a>, instead of the <a href="https://github.com/Netflix/Hystrix">original version</a> which is written in Java).</p><p>As the first article of this series, I will give a general introduction to <code>circuit breaker</code>, let you know what it is and why it is important. Moreover, let’s review the background about the project <code>hystrix-go</code> and <code>hystrix</code>, and understand the basic usage with a small demo example. </p><h3 id="Circuit-breaker"><a href="#Circuit-breaker" class="headerlink" title="Circuit breaker"></a>Circuit breaker</h3><p>Software in distributed architectures generally have many dependencies, and the failure at some point for each dependency(even the most reliable service) is inevitable. </p><p>What happens if our failing service becomes unresponsive? All services that rely on it have risks to become unresponsive, too. This is called <code>catastrophic cascading failure.</code></p><p>The basic idea behind the circuit breaker is very simple. A circuit breaker works by wrapping calls to a target service and keeps monitoring the failure rates. Once the failures reach a certain threshold, the circuit breaker will trip ，and all the further calls to the circuit return with a fault or error. </p><p>The design philosophy behind the circuit breaker pattern is <code>fail fast</code>: when a service becomes unresponsive, other services relying on it should stop waiting for it and start dealing with the fact that the failing service may be unavailable. By preventing a single service’s failure cascading through the entire system, the circuit breaker pattern contributes to the <code>stability</code> and <code>resilience</code> of the whole system.  </p><p>The circuit breaker pattern can be implemented as a finite-state machine shown below:</p><p><img src="/images/circuit-breaker.png" alt="circuit-breaker"></p><p>There are three statuses: <code>open</code>, <code>closed</code> and <code>half-open</code></p><ul><li><strong>closed</strong>: Requests are passed to the target service. Keep monitoring the metrics like error rate, request numbers and timeout. When these metrics exceed a specific threshold(which is set by the developer), the breaker is tripped and transitions into <code>open</code> status.   </li><li><strong>open</strong>: Requests are not passed to the target service, instead the <code>fallback</code> logic(which is defined by developer as well) will be called to handle the failure. The breaker will stay <code>open</code> status for a period of time called <code>sleeping window</code>, after which the breaker can transition from <code>open</code> to <code>half-open</code>.  </li><li><strong>half-open</strong>: In this status, a limited number of requests are passed to the target service, which is aims at resetting the status. If the target service can response successfully then the break is <code>reset</code> back to <code>closed</code> status. Or else the breaker transitions back to <code>open</code> status. </li></ul><p>That’s basic background about circuit breaker, you can find much more <a href="https://martinfowler.com/bliki/CircuitBreaker.html">information</a> about it on line. </p><p>Next, let’s investigate the project <code>hystrix</code>. </p><h3 id="hystrix"><a href="#hystrix" class="headerlink" title="hystrix"></a>hystrix</h3><p><code>hystrix</code> is a very popular open source project. You can find everything about it in this <a href="https://github.com/Netflix/Hystrix/wiki">link</a>. </p><p>I want to quote several important points from the above link. Hystrix is designed to do the following:</p><ul><li>Give protection from and control over latency and failure from dependencies accessed (typically over the network) via third-party client libraries.</li><li>Stop cascading failures in a complex distributed system.</li><li>Fail fast and rapidly recover.</li><li>Fallback and gracefully degrade when possible.</li><li>Enable near real-time monitoring, alerting, and operational control.</li></ul><p>You can see <code>hystrix</code> perfectly implements the idea of circuit breaker pattern we talked about in the last section, right? </p><p>The <code>hystrix</code> project is developed with <code>Java</code>. In this sereis of articles I prefer to use a golang version <code>hystrix-go</code>, which is a simplified version but implements all the main designs and ideas about circuit breaker. </p><p>For the usage of <code>hystrix-go</code>, you can find it in this <a href="https://github.com/afex/hystrix-go">link</a>, which is very straightforward to understand. And you can easily find many other articles online with demo examples to show more usage level stuff. Please go head to read.</p><p>In my articles, I want to go into the source code of <code>hystrix-go</code> and have an advanced investigation about how <code>circuit breaker</code> is implemented. Please follow up to read the next articles in this series. </p><h3 id="Summary"><a href="#Summary" class="headerlink" title="Summary"></a>Summary</h3><p>In this article, I talked about the background of circuit breaker pattern and the basic information of the popular open-source project in this field <code>hystrix-go</code>. Next step, we will take an in-depth look at the source code of this project. </p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;In this series of articles, I want to talk about &lt;code&gt;circuit breaker&lt;/code&gt; pattern based on an popular open source project &lt;code&gt;hystr</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>golang-sync-cond</title>
    <link href="https://baoqger.github.io/2021/05/14/golang-sync-cond/"/>
    <id>https://baoqger.github.io/2021/05/14/golang-sync-cond/</id>
    <published>2021-05-14T02:14:18.000Z</published>
    <updated>2021-12-23T12:34:34.793Z</updated>
    
    
    
    
    
  </entry>
  
  <entry>
    <title> Golang synchronization primitives source code analysis: part one - sync.Once</title>
    <link href="https://baoqger.github.io/2021/05/11/golang-sync-once/"/>
    <id>https://baoqger.github.io/2021/05/11/golang-sync-once/</id>
    <published>2021-05-11T12:07:55.000Z</published>
    <updated>2021-12-23T12:34:34.794Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Background"><a href="#Background" class="headerlink" title="Background"></a>Background</h3><p>In the following series of posts, I will take an in-depth look at the <code>synchronization primitives</code> provided by Golang. </p><p>Although the recommended synchronization mechanism in Golang is <code>channel</code>, there are several powerful <code>synchronization primitives</code> provided in Golang <code>sync</code> package. Based on the official document, <strong>Other than the Once and WaitGroup types, most are intended for use by low-level library routines</strong>. If you read the code of low-level open source projects or the standard packages, you will see synchronization primitives in <code>sync</code> package frequently. </p><p>As the first post in this series, let’s check the source code of <code>sync.Once</code>, which is also the simplest one.</p><h3 id="sync-Once"><a href="#sync-Once" class="headerlink" title="sync.Once"></a>sync.Once</h3><p>If you have several logics running in various go-routines, and you want only one of the logics will execute finally. For this kind of scenario, <code>sync.Once</code> is a perfect option for you. </p><p>Let’s review the source code of <code>sync.Once</code> defined inside the <code>once.go</code> file: </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> sync</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line"><span class="string">&quot;sync/atomic&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="keyword">type</span> Once <span class="keyword">struct</span> &#123;</span><br><span class="line">done <span class="type">uint32</span></span><br><span class="line">m    Mutex</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(o *Once)</span></span> Do(f <span class="function"><span class="keyword">func</span><span class="params">()</span></span>) &#123;</span><br><span class="line"><span class="keyword">if</span> atomic.LoadUint32(&amp;o.done) == <span class="number">0</span> &#123;</span><br><span class="line">o.doSlow(f)</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(o *Once)</span></span> doSlow(f <span class="function"><span class="keyword">func</span><span class="params">()</span></span>) &#123;</span><br><span class="line">o.m.Lock()</span><br><span class="line"><span class="keyword">defer</span> o.m.Unlock()</span><br><span class="line"><span class="keyword">if</span> o.done == <span class="number">0</span> &#123;</span><br><span class="line"><span class="keyword">defer</span> atomic.StoreUint32(&amp;o.done, <span class="number">1</span>)</span><br><span class="line">f()</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Struct <code>Once</code> has a status flag <code>done</code> whose value is <code>0</code> when initialized. Wrap the logic you want to execute in a function <code>f</code>, and pass this function <code>f</code> to the <code>Do()</code> method. When <code>Do</code> is called for the first time, the logic in <code>f</code> executes after that <code>done</code> flag is set to <code>1</code>, other calls to <code>Do</code> don’t execute <code>f</code>. </p><p>One misleading point is  <strong>If <code>once.Do(f)</code> is called multiple times, only the first call will invoke <code>f</code>, even if <code>f</code> has a different value in each invocation</strong>. Check the following example:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line"><span class="string">&quot;fmt&quot;</span></span><br><span class="line"><span class="string">&quot;sync&quot;</span></span><br><span class="line"><span class="string">&quot;time&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> doOnce sync.Once</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line"><span class="keyword">go</span> TaskOne()</span><br><span class="line"><span class="keyword">go</span> TaskTwo()</span><br><span class="line">time.Sleep(time.Second)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">PrintTask</span><span class="params">(id <span class="type">int</span>)</span></span> &#123;</span><br><span class="line">fmt.Printf(<span class="string">&quot;Task %d, Run once\n&quot;</span>, id)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">TaskOne</span><span class="params">()</span></span> &#123;</span><br><span class="line">doOnce.Do(<span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">PrintTask(<span class="number">1</span>)</span><br><span class="line">&#125;)</span><br><span class="line">fmt.Println(<span class="string">&quot;Run this every time&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">TaskTwo</span><span class="params">()</span></span> &#123;</span><br><span class="line">doOnce.Do(<span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">PrintTask(<span class="number">2</span>)</span><br><span class="line">&#125;)</span><br><span class="line">fmt.Println(<span class="string">&quot;Run this every time&quot;</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Even <code>Do</code> is called twice with different <code>f</code> logic, but only the first call is invoked since they are bound to the same instance of <code>Once</code>. </p><h3 id="fast-path-and-slow-path"><a href="#fast-path-and-slow-path" class="headerlink" title="fast path and slow path"></a>fast path and slow path</h3><p>As you saw above, the implementation of <code>sync.Once</code> is not complex. But one question comes to my mind when I double check the code. Why do we need split the logics into two functions <code>Do</code> and <code>doSlow</code>? Why the second function name is <code>doSlow</code>, and what does <code>slow</code> mean here?</p><p>Do you have similar questions? </p><p>I found the answer in the comments of <code>once.go</code> file. </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> atomic.LoadUint32(&amp;o.done) == <span class="number">0</span> &#123;</span><br><span class="line"><span class="comment">// Outlined slow-path to allow inlining of the fast-path.</span></span><br><span class="line">o.doSlow(f)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Note that it mentioned two words: <code>fast path</code> and <code>slow path</code>. </p><ul><li>Fast path is a term used in computer science to describe a path with shorter instruction path length through a program compared to the ‘normal’ path. For a fast path to be effective it must handle the most commonly occurring tasks more efficiently than the ‘normal’ path, leaving the latter to handle uncommon cases, corner cases, error handling, and other anomalies. <strong>Fast paths are a form of optimization</strong>. </li></ul><p>In the <code>Once</code> case, since the first call to <code>Do</code> function will set <code>done</code> to 1, so the most common case or status for <code>Once</code> is the <code>done</code> flag equals to 1. The <code>fast path</code> in <code>Do</code> function is just for this common case. While the <code>done</code> flag equals to initial status 0 can be regarded as uncommon case, which is specially handled in the <code>doSlow</code> function. The performance can be optimized in this way.</p><h3 id="hot-path"><a href="#hot-path" class="headerlink" title="hot path"></a>hot path</h3><p>Another very interesting concept worth mentioning is <code>hot path</code>, and it occurs in the <code>Once</code> struct design.</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> Once <span class="keyword">struct</span> &#123;</span><br><span class="line"><span class="comment">// done indicates whether the action has been performed.</span></span><br><span class="line"><span class="comment">// It is first in the struct because it is used in the hot path.</span></span><br><span class="line"><span class="comment">// The hot path is inlined at every call site.</span></span><br><span class="line"><span class="comment">// Placing done first allows more compact instructions on some architectures (amd64/x86),</span></span><br><span class="line"><span class="comment">// and fewer instructions (to calculate offset) on other architectures.</span></span><br><span class="line">done <span class="type">uint32</span></span><br><span class="line">m    Mutex</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>At first glance, it’s just plain and ordinary struct, but the comments emphasize that <code>done</code> <strong>is first in the struct because it is used in the hot path</strong>. It means that <code>done</code> is defined as the first field in <code>Once</code> struct on purpose. And the purpose is also described in the comment <strong>Placing done first allows more compact instructions on some architectures (amd64/x86), and fewer instructions (to calculate offset) on other architectures.</strong></p><p>What does that mean? I found a great answer in this <a href="https://stackoverflow.com/questions/59174176/what-does-hot-path-mean-in-the-context-of-sync-once">post</a>. The conclusion is:</p><ul><li><p>A <code>hot path</code> is a sequence of instructions executed very frequently.</p></li><li><p>When accessing the first field of a structure, we can directly dereference the pointer to the structure to access the first field. To access other fields, we need to provide an <code>offset</code> from the first value in addition to the struct pointer.</p></li><li><p>In machine code, this offset is an additional value to pass with the instruction which makes it longer. The performance impact is that the CPU must perform an addition of the offset to the struct pointer to get the address of the value to access.</p></li><li><p>Thus machine code to <code>access the first field of a struct is more compact and faster</code>.</p></li></ul><p>Simply speaking, accessing the first field of a struct is faster since the CPU doesn’t need to compute the memory offset!</p><p>This is really a good lesson to show the high-level code you programmed can have such a big difference in the bottom level.</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;Background&quot;&gt;&lt;a href=&quot;#Background&quot; class=&quot;headerlink&quot; title=&quot;Background&quot;&gt;&lt;/a&gt;Background&lt;/h3&gt;&lt;p&gt;In the following series of posts, I wi</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>Golang Context package source code analysis: part 2</title>
    <link href="https://baoqger.github.io/2021/04/28/golang-context-source-code-part2/"/>
    <id>https://baoqger.github.io/2021/04/28/golang-context-source-code-part2/</id>
    <published>2021-04-28T05:38:51.000Z</published>
    <updated>2021-12-23T12:34:34.792Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Background"><a href="#Background" class="headerlink" title="Background"></a>Background</h3><p>In the <a href="https://baoqger.github.io/2021/04/26/golang-context-source-code/">last post</a>, I shared the first part about the <code>context</code> package: <code>valueCtx</code> and <code>cancelCtx</code>. Let us continue the journey to discover more in this post. </p><h3 id="WithTimeout-and-WithDeadline"><a href="#WithTimeout-and-WithDeadline" class="headerlink" title="WithTimeout and WithDeadline"></a>WithTimeout and WithDeadline</h3><p>As usual, let us start with an example: </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">    <span class="string">&quot;context&quot;</span></span><br><span class="line">    <span class="string">&quot;fmt&quot;</span></span><br><span class="line">    <span class="string">&quot;time&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">    cancelCtx, cancel := context.WithTimeout(context.Background(), time.Second*<span class="number">3</span>)</span><br><span class="line">    <span class="keyword">defer</span> cancel()</span><br><span class="line">    <span class="keyword">go</span> task(cancelCtx)</span><br><span class="line">    time.Sleep(time.Second * <span class="number">4</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">task</span><span class="params">(ctx context.Context)</span></span> &#123;</span><br><span class="line">    i := <span class="number">1</span></span><br><span class="line">    <span class="keyword">for</span> &#123;</span><br><span class="line">        <span class="keyword">select</span> &#123;</span><br><span class="line">        <span class="keyword">case</span> &lt;-ctx.Done():</span><br><span class="line">            fmt.Println(ctx.Err())</span><br><span class="line">            <span class="keyword">return</span></span><br><span class="line">        <span class="keyword">default</span>:</span><br><span class="line">            fmt.Println(i)</span><br><span class="line">            time.Sleep(time.Second * <span class="number">1</span>)</span><br><span class="line">            i++</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Since we already know the behavior of <code>cancelCtx</code>, it’s quite straightforward to understand how <code>WithTimeout</code> works. It accepts a timeout duration after which the <code>done</code> channel will be closed and context will be canceled. And a cancel function will be returned as well, which can be called in case the context needs to be canceled before timeout. </p><p><code>WithDeadline</code> usage is quite similar to <code>WithTimeout</code>, you can find related example easily. Let us review the source code:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> timerCtx <span class="keyword">struct</span> &#123;</span><br><span class="line">cancelCtx</span><br><span class="line">timer *time.Timer </span><br><span class="line">deadline time.Time</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">WithTimeout</span><span class="params">(parent Context, timeout time.Duration)</span></span> (Context, CancelFunc) &#123;</span><br><span class="line"><span class="keyword">return</span> WithDeadline(parent, time.Now().Add(timeout))</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Since <code>WithTimeout</code> and <code>WithDeadline</code> have many common points between them, so they share the same type of context: <code>timerCtx</code>, which embeds <code>cancelCtx</code> and defines two more properties: <code>timer</code> and <code>deadline</code>. </p><p>Let us review what happens when we create a <code>timerCtx</code>:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">WithDeadline</span><span class="params">(parent Context, d time.Time)</span></span> (Context, CancelFunc) &#123;</span><br><span class="line"><span class="keyword">if</span> parent == <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="built_in">panic</span>(<span class="string">&quot;cannot create context from nil parent&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// Get deadline time of parent context. </span></span><br><span class="line"><span class="keyword">if</span> cur, ok := parent.Deadline(); ok &amp;&amp; cur.Before(d) &#123;</span><br><span class="line"><span class="comment">// The current deadline is already sooner than the new one.</span></span><br><span class="line"><span class="keyword">return</span> WithCancel(parent)</span><br><span class="line">&#125;</span><br><span class="line">c := &amp;timerCtx&#123;</span><br><span class="line">cancelCtx: newCancelCtx(parent),</span><br><span class="line">deadline:  d,</span><br><span class="line">&#125;</span><br><span class="line">propagateCancel(parent, c)</span><br><span class="line">dur := time.Until(d)</span><br><span class="line"><span class="keyword">if</span> dur &lt;= <span class="number">0</span> &#123;</span><br><span class="line">c.cancel(<span class="literal">true</span>, DeadlineExceeded) <span class="comment">// deadline has already passed</span></span><br><span class="line"><span class="keyword">return</span> c, <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123; c.cancel(<span class="literal">false</span>, Canceled) &#125;</span><br><span class="line">&#125;</span><br><span class="line">c.mu.Lock()</span><br><span class="line"><span class="keyword">defer</span> c.mu.Unlock()</span><br><span class="line"><span class="keyword">if</span> c.err == <span class="literal">nil</span> &#123; <span class="comment">// &#x27;err&#x27; field of the embedded cancelCtx is promoted </span></span><br><span class="line">c.timer = time.AfterFunc(dur, <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">c.cancel(<span class="literal">true</span>, DeadlineExceeded)</span><br><span class="line">&#125;)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> c, <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123; c.cancel(<span class="literal">true</span>, Canceled) &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Compared to <code>WithCancle</code> and <code>WithValue</code>, <code>WithDeadline</code> is more complex, let us go through bit by bit.</p><p>Firstly, <code>parent.Deadline</code> will get the deadline time for parent context. The <code>Deadline</code> method signature was defined in the <code>Context</code> interface as below:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> Context <span class="keyword">interface</span> &#123;</span><br><span class="line">Deadline() (deadline time.Time, ok <span class="type">bool</span>)</span><br><span class="line">...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>In the context package, only <code>emptyCtx</code> and <code>timerCtx</code> type implement this method:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(*emptyCtx)</span></span> Deadline() (deadline time.Time, ok <span class="type">bool</span>) &#123;</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(c *timerCtx)</span></span> Deadline() (deadline time.Time, ok <span class="type">bool</span>) &#123;</span><br><span class="line"><span class="keyword">return</span> c.deadline, <span class="literal">true</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>So when we call <code>parent.Deadline()</code>, if the parent context is also type of <code>timerCtx</code> which implements its own <code>Deadline()</code> method, then you can get the deadline time of the parent context. Otherwise if the parent context is type of <code>cancelCtx</code> or <code>valueCtx</code>, then finally the <code>Deadline()</code> method of <code>emptyCtx</code> will be called and you will get the zero value of type <code>time.Time</code> and <code>bool</code> (if you have interest, you can verify by yourself the zero value: <strong>0001-01-01 00:00:00 +0000 UTC</strong> and <strong>false</strong>).  </p><p>If parent’s deadline is earlier than the passed in deadline parameter, then directly return a <code>cancelCtx</code> by calling <code>WithCancel(parent)</code>. Of course when the passed in deadline is reasonable, we need to create a <code>timerCtx</code>: </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//inside WithDeadline() function</span></span><br><span class="line">...</span><br><span class="line">c := &amp;timerCtx&#123;</span><br><span class="line">cancelCtx: newCancelCtx(parent),</span><br><span class="line">deadline:  d,</span><br><span class="line">&#125;</span><br><span class="line">propagateCancel(parent, c)</span><br><span class="line">...</span><br></pre></td></tr></table></figure><p>In the above code, you see <code>propagateCancel</code> method again, I have discussed about it in the last post, if you don’t understand it, please refer <a href="https://baoqger.github.io/2021/04/26/golang-context-source-code/">here</a>.</p><p>Similar to <code>cancelCtx</code>, <code>timerCtx</code> sends the context cancel signal by closing the done channel by calling its own <code>cancel</code> method. There two scenarios when cancelling the context:</p><ul><li>timeout cancel: when the deadline exceeded, automatically close the done channel; </li></ul><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// inside WithDeadline function</span></span><br><span class="line">...</span><br><span class="line"><span class="comment">// timeout cancel</span></span><br><span class="line">c.timer = time.AfterFunc(dur, <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">c.cancel(<span class="literal">true</span>, DeadlineExceeded)</span><br><span class="line">&#125;)</span><br><span class="line">...</span><br></pre></td></tr></table></figure><ul><li>manual cancel: call the returned cancel function to close the done channel before the deadline;<figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// inside WithDeadline function</span></span><br><span class="line">...</span><br><span class="line"><span class="comment">// return the cancel function as the second return value</span></span><br><span class="line"><span class="keyword">return</span> c, <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123; c.cancel(<span class="literal">true</span>, Canceled) &#125;</span><br><span class="line">...</span><br></pre></td></tr></table></figure></li></ul><p>Both scenarios call <code>cancel</code> method: </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(c *timerCtx)</span></span> cancel(removeFromParent <span class="type">bool</span>, err <span class="type">error</span>) &#123;</span><br><span class="line">c.cancelCtx.cancel(<span class="literal">false</span>, err) <span class="comment">// close the done channel and set err field</span></span><br><span class="line"><span class="keyword">if</span> removeFromParent &#123;</span><br><span class="line"><span class="comment">// Remove this timerCtx from its parent cancelCtx&#x27;s children.</span></span><br><span class="line"><span class="comment">// Note: timerCtx c&#x27;s parent is c.cancelCtx.Context</span></span><br><span class="line">removeChild(c.cancelCtx.Context, c)</span><br><span class="line">&#125;</span><br><span class="line">c.mu.Lock()</span><br><span class="line"><span class="comment">// stop and clean the timer</span></span><br><span class="line"><span class="keyword">if</span> c.timer != <span class="literal">nil</span> &#123;</span><br><span class="line">c.timer.Stop()</span><br><span class="line">c.timer = <span class="literal">nil</span></span><br><span class="line">&#125;</span><br><span class="line">c.mu.Unlock()</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>timerCtx</code> implements <code>cancel</code> method to stop and reset the timer then delegate to <code>cancelCtx.cancel</code>. </p><h3 id="Summary"><a href="#Summary" class="headerlink" title="Summary"></a>Summary</h3><p>In the second part of this post series, we discussed how <code>timeout</code> and <code>deadline</code> context are implemented in the source code level. In this part, Golang struct embedding technique is used a lot, you can compare it with traditional OOP solution to have a deep understanding.</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;Background&quot;&gt;&lt;a href=&quot;#Background&quot; class=&quot;headerlink&quot; title=&quot;Background&quot;&gt;&lt;/a&gt;Background&lt;/h3&gt;&lt;p&gt;In the &lt;a href=&quot;https://baoqger.github</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>Golang Context package source code analysis: part 1</title>
    <link href="https://baoqger.github.io/2021/04/26/golang-context-source-code/"/>
    <id>https://baoqger.github.io/2021/04/26/golang-context-source-code/</id>
    <published>2021-04-26T12:44:48.000Z</published>
    <updated>2021-12-23T12:34:34.793Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Background"><a href="#Background" class="headerlink" title="Background"></a>Background</h3><p>As a Golang user and learner, I always think Golang standard package is a great learning resource, which can provide best practices for both the language itself and various software or programming concepts. </p><p>In this post, I will share what I learned about package <code>context</code>.</p><p><code>context</code> is widely used in the Golang ecosystem, and I bet you must often come across it. Many standard packages rely on it. </p><p>There are many good <a href="https://golangbyexample.com/using-context-in-golang-complete-guide/">articles</a> online explaining the background and usage examples of <code>context</code>, I will not spend too much time on that, just add a brief introduction here. </p><p>The problems <code>context</code> plans to solve are：</p><ul><li>Let’s say that you started a function and you need to pass some common parameters to the downstream functions. You cannot pass these common parameters each as an argument to all the downstream functions.</li><li>You started a goroutine which in turn start more goroutines and so on. Suppose the task that you were doing is no longer needed. Then how to inform all child goroutines to gracefully exit so that resources can be freed up</li><li>A task should be finished within a specified timeout of say 2 seconds. If not it should gracefully exit or return.</li><li>A task should be finished within a deadline eg it should end before 5 pm . If not finished then it should gracefully exit and return</li></ul><p>You can refer to this <a href="https://talks.golang.org/2014/gotham-context.slide#1">slide</a> from the author of context package to understand more about the background. </p><p>In this post, I will show you the details of context package source code. You can find all the related source code inside the <code>context.go</code> file. You will notice that <code>context</code> package content is not long, and there are roughly 500 lines of code. Moreover, there are many comments, so the actual code is only half. These 200+ lines of code are a great piece of learning resource in my eyes. </p><h3 id="Source-code-analysis"><a href="#Source-code-analysis" class="headerlink" title="Source code analysis"></a>Source code analysis</h3><h4 id="Context-interface-and-emptyCtx"><a href="#Context-interface-and-emptyCtx" class="headerlink" title="Context interface and emptyCtx"></a>Context interface and emptyCtx</h4><p>The most basic data structure of context is the <code>Context</code> interface as below:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> Context <span class="keyword">interface</span> &#123;</span><br><span class="line">    Deadline() (deadline time.Time, ok <span class="type">bool</span>)</span><br><span class="line">    Done() &lt;-<span class="keyword">chan</span> <span class="keyword">struct</span>&#123;&#125;</span><br><span class="line">    Err() <span class="type">error</span></span><br><span class="line">    Value(key <span class="keyword">interface</span>&#123;&#125;) <span class="keyword">interface</span>&#123;&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>Context</code> is just an interface, which is very hard to imagine how to use it. So let us continue reviewing some types implement such interface. </p><p>When context is used, generally speaking, the first step is creating the root context with <code>context.Background()</code> function(the contexts are chained together one by one and form a tree structure, and the root context is the first one in the chain). Let’s check what it is: </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> background = <span class="built_in">new</span>(emptyCtx)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">Background</span><span class="params">()</span></span> Context &#123;</span><br><span class="line"><span class="keyword">return</span> background</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>Background</code> function return the <code>background</code> which is a global variable declared as <code>new(emptyCtx)</code>. So what is <code>emptyCtx</code>, let continue:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// An emptyCtx is never canceled, has no values, and has no deadline. It is not</span></span><br><span class="line"><span class="comment">// struct&#123;&#125;, since vars of this type must have distinct addresses.</span></span><br><span class="line"><span class="keyword">type</span> emptyCtx <span class="type">int</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(*emptyCtx)</span></span> Deadline() (deadline time.Time, ok <span class="type">bool</span>) &#123;</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(*emptyCtx)</span></span> Done() &lt;-<span class="keyword">chan</span> <span class="keyword">struct</span>&#123;&#125; &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(*emptyCtx)</span></span> Err() <span class="type">error</span> &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(*emptyCtx)</span></span> Value(key <span class="keyword">interface</span>&#123;&#125;) <span class="keyword">interface</span>&#123;&#125; &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(e *emptyCtx)</span></span> String() <span class="type">string</span> &#123;</span><br><span class="line"><span class="keyword">switch</span> e &#123;</span><br><span class="line"><span class="keyword">case</span> background:</span><br><span class="line"><span class="keyword">return</span> <span class="string">&quot;context.Background&quot;</span></span><br><span class="line"><span class="keyword">case</span> todo:</span><br><span class="line"><span class="keyword">return</span> <span class="string">&quot;context.TODO&quot;</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> <span class="string">&quot;unknown empty Context&quot;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>You can see that <code>emptyCtx</code> is declared as a new customized type based on <code>int</code>.  In fact, it’s not important  that <code>emptyCtx</code> is based on <code>int</code>, <code>string</code> or whatever. The important thing is all the four methods defined in interface <code>Context</code> return <code>nil</code>. So the root context <strong>is never canceled, has no values, and has no deadline</strong>. </p><p>Let’s continue to review other data types.</p><h4 id="valueCtx-and-WithValue"><a href="#valueCtx-and-WithValue" class="headerlink" title="valueCtx and WithValue"></a>valueCtx and WithValue</h4><p>As mentioned above, one typical usage of context is passing data. In this case, you need to create a <code>valueCtx</code> with <code>WithValue</code> function. For example, the following example:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">rootCtx := context.Background()</span><br><span class="line"></span><br><span class="line">childCtx := context.WithValue(rootCtx, <span class="string">&quot;msgId&quot;</span>, <span class="string">&quot;someMsgId&quot;</span>)</span><br></pre></td></tr></table></figure><p><code>WithValue</code> is a function has only one return value:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">WithValue</span><span class="params">(parent Context, key, val <span class="keyword">interface</span>&#123;&#125;)</span></span> Context &#123;</span><br><span class="line"><span class="keyword">if</span> parent == <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="built_in">panic</span>(<span class="string">&quot;cannot create context from nil parent&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> key == <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="built_in">panic</span>(<span class="string">&quot;nil key&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> !reflectlite.TypeOf(key).Comparable() &#123;</span><br><span class="line"><span class="built_in">panic</span>(<span class="string">&quot;key is not comparable&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> &amp;valueCtx&#123;parent, key, val&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Please ignore the <code>reflectlite</code> part, I will give a in-depth discussion about it in another post. In this post, we only need to care the return value type is <code>&amp;valueCtx</code>:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> valueCtx <span class="keyword">struct</span> &#123;</span><br><span class="line">Context</span><br><span class="line">key, val <span class="keyword">interface</span>&#123;&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>There is one interesting Golang language feature here: <code>embedding</code>, which realizes <code>composition</code>. In this case, <code>valueCtx</code> has all the four methods defined in <code>Context</code>.<br>In fact, <code>embedding</code> is worthy much more discussion. Simplying speaking, there are 3 types of embedding: <strong>struct in struct</strong>, <strong>interface in interface</strong> and <strong>interface in struct</strong>. <code>valueCtx</code> is the last type, you can refer to this great <a href="https://eli.thegreenplace.net/2020/embedding-in-go-part-1-structs-in-structs/">post</a></p><p>When you want to get the value out, you can use the <code>Value</code> method: </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(c *valueCtx)</span></span> Value(key <span class="keyword">interface</span>&#123;&#125;) <span class="keyword">interface</span>&#123;&#125; &#123;</span><br><span class="line"><span class="keyword">if</span> c.key == key &#123;</span><br><span class="line"><span class="keyword">return</span> c.val</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> c.Context.Value(key)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>If the provided <code>key</code> parameter does not match the current context’s key, then the parent context’s <code>Value</code> method will be called. If we still can’t find the key, the parent context’s will call its parent as well. The search will pass along the chain until the root node which will return <code>nil</code> as we mentioned above:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(*emptyCtx)</span></span> Value(key <span class="keyword">interface</span>&#123;&#125;) <span class="keyword">interface</span>&#123;&#125; &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Next, let’s review another interesting type: <code>cancelCtx</code></p><h4 id="cancelCtx-and-WithCancel"><a href="#cancelCtx-and-WithCancel" class="headerlink" title="cancelCtx and WithCancel"></a>cancelCtx and WithCancel</h4><p>First, let’s see how to use <code>cancelCtx</code> and <code>WithCanel</code> with a simple example:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line"><span class="string">&quot;context&quot;</span></span><br><span class="line"><span class="string">&quot;fmt&quot;</span></span><br><span class="line"><span class="string">&quot;time&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">cancelCtx, cancelFunc := context.WithCancel(context.Background())</span><br><span class="line"><span class="keyword">go</span> task(cancelCtx)</span><br><span class="line">time.Sleep(time.Second * <span class="number">3</span>)</span><br><span class="line">cancelFunc()</span><br><span class="line">time.Sleep(time.Second * <span class="number">3</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">task</span><span class="params">(ctx context.Context)</span></span> &#123;</span><br><span class="line">i := <span class="number">1</span></span><br><span class="line"><span class="keyword">for</span> &#123;</span><br><span class="line"><span class="keyword">select</span> &#123;</span><br><span class="line"><span class="keyword">case</span> &lt;-ctx.Done():</span><br><span class="line">fmt.Println(ctx.Err())</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line"><span class="keyword">default</span>:</span><br><span class="line">fmt.Println(i)</span><br><span class="line">time.Sleep(time.Second * <span class="number">1</span>)</span><br><span class="line">i++</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>When main goroutine wants to cancel <code>task</code> goroutine, it can just call <code>cancelFunc</code>. Then the task goroutine will exit and stop running. In this way, goroutine management will be easy task. Let’s review the code:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> CancelFunc <span class="function"><span class="keyword">func</span><span class="params">()</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">WithCancel</span><span class="params">(parent Context)</span></span> (ctx Context, cancel CancelFunc) &#123;</span><br><span class="line"><span class="keyword">if</span> parent == <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="built_in">panic</span>(<span class="string">&quot;cannot create context from nil parent&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line">c := newCancelCtx(parent)</span><br><span class="line">propagateCancel(parent, &amp;c)</span><br><span class="line"><span class="keyword">return</span> &amp;c, <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123; c.cancel(<span class="literal">true</span>, Canceled) &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>cancelCtx</code> is complex, let’s go through bit by bit. </p><p><code>WithCancel</code> returns two values, the first one <code>&amp;c</code> is type <code>cancelCtx</code> which is created with <code>newCancelCtx</code>, the second one <code>func() &#123; c.cancel(true, Canceled) &#125;</code> is type <code>CancenlFunc</code>(just a general function). </p><p>Let’s review <code>cancelCtx</code> firstly:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">newCancelCtx</span><span class="params">(parent Context)</span></span> cancelCtx &#123;</span><br><span class="line"><span class="keyword">return</span> cancelCtx&#123;Context: parent&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">type</span> cancelCtx <span class="keyword">struct</span> &#123;</span><br><span class="line">Context</span><br><span class="line"></span><br><span class="line">mu       sync.Mutex            <span class="comment">// protects following fields</span></span><br><span class="line">done     <span class="keyword">chan</span> <span class="keyword">struct</span>&#123;&#125;         <span class="comment">// created lazily, closed by first cancel call</span></span><br><span class="line">children <span class="keyword">map</span>[canceler]<span class="keyword">struct</span>&#123;&#125; <span class="comment">// set to nil by the first cancel call</span></span><br><span class="line">err      <span class="type">error</span>                 <span class="comment">// set to non-nil by the first cancel call</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>Context</code> is embedded inside <code>cancelCtx</code> as well. Also it defines several other fields. Let’s see how it works by checking the receiver methods:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(c *cancelCtx)</span></span> Done() &lt;-<span class="keyword">chan</span> <span class="keyword">struct</span>&#123;&#125; &#123;</span><br><span class="line">c.mu.Lock()</span><br><span class="line"><span class="keyword">if</span> c.done == <span class="literal">nil</span> &#123;</span><br><span class="line">c.done = <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="keyword">struct</span>&#123;&#125;)</span><br><span class="line">&#125;</span><br><span class="line">d := c.done</span><br><span class="line">c.mu.Unlock()</span><br><span class="line"><span class="keyword">return</span> d</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>Done</code> method returns channel <code>done</code>. In the above demo, <strong>task</strong> goroutine listen for cancel signal from this done channel like this:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">select</span> &#123;</span><br><span class="line"><span class="keyword">case</span> &lt;-ctx.Done():</span><br><span class="line">fmt.Println(ctx.Err())</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">...</span><br></pre></td></tr></table></figure><p>The signal is trigger by calling the cancle function, so let’s review what happens inside it and how the signals are sent to the channel. All the logic is inside <code>cancel</code> method of <code>cancelCtx</code>:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(c *cancelCtx)</span></span> cancel(removeFromParent <span class="type">bool</span>, err <span class="type">error</span>) &#123;</span><br><span class="line"><span class="keyword">if</span> err == <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="built_in">panic</span>(<span class="string">&quot;context: internal error: missing cancel error&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line">c.mu.Lock()</span><br><span class="line"><span class="keyword">if</span> c.err != <span class="literal">nil</span> &#123;</span><br><span class="line">c.mu.Unlock()</span><br><span class="line"><span class="keyword">return</span> <span class="comment">// already canceled</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// set the err property when cancel is called for the first time</span></span><br><span class="line">c.err = err</span><br><span class="line"><span class="keyword">if</span> c.done == <span class="literal">nil</span> &#123;</span><br><span class="line">c.done = closedchan</span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line"><span class="built_in">close</span>(c.done)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">for</span> child := <span class="keyword">range</span> c.children &#123;</span><br><span class="line"><span class="comment">// <span class="doctag">NOTE:</span> acquiring the child&#x27;s lock while holding parent&#x27;s lock.</span></span><br><span class="line">child.cancel(<span class="literal">false</span>, err)</span><br><span class="line">&#125;</span><br><span class="line">c.children = <span class="literal">nil</span></span><br><span class="line">c.mu.Unlock()</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> removeFromParent &#123;</span><br><span class="line">removeChild(c.Context, c)</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>As shown above, <code>cancelCtx</code> has four properties, we can understand their purpose clearly in this <code>cancel</code>: </p><ul><li><code>mu</code>: a general lock to make sure goroutine safe and avoid race condition;</li><li><code>err</code>: a flag representing whether the cancelCtx is cancelled or not. When the cancelCtx is created, <code>err</code> value is <code>nil</code>. When <code>cancel</code> is called for the first time, it will be set by <code>c.err = err</code>;</li><li><code>done</code>: a channel which sends cancel signal. To realize this, context just <code>close</code> the done channel instead of send data into it. This is an <strong>interesting point</strong> which is different from my initial imagination before I review the source code. Yes, after a channel is closed, the receiver can still get <code>zero value</code> from the closed channel based on the channel type. Context just make use of this feature.</li><li><code>children</code>: a <code>Map</code> containing all its child contexts. When current context is cancelled, the cancel action will be propogated to the children by calling <code>child.cancel(false, err)</code> in the for loop. Then next question is when the parent-child relationship is established? The secret is inside the <code>propagateCancel()</code> function;</li></ul><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">propagateCancel</span><span class="params">(parent Context, child canceler)</span></span> &#123;</span><br><span class="line">done := parent.Done()</span><br><span class="line"><span class="keyword">if</span> done == <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="comment">// parent is never canceled</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">select</span> &#123;</span><br><span class="line"><span class="keyword">case</span> &lt;-done:</span><br><span class="line"><span class="comment">// parent is already canceled</span></span><br><span class="line">child.cancel(<span class="literal">false</span>, parent.Err())</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line"><span class="keyword">default</span>:</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> p, ok := parentCancelCtx(parent); ok &#123;</span><br><span class="line">p.mu.Lock()</span><br><span class="line"><span class="keyword">if</span> p.err != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="comment">// parent has already been canceled</span></span><br><span class="line">child.cancel(<span class="literal">false</span>, p.err)</span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line"><span class="keyword">if</span> p.children == <span class="literal">nil</span> &#123;</span><br><span class="line">p.children = <span class="built_in">make</span>(<span class="keyword">map</span>[canceler]<span class="keyword">struct</span>&#123;&#125;)</span><br><span class="line">&#125;</span><br><span class="line">p.children[child] = <span class="keyword">struct</span>&#123;&#125;&#123;&#125;</span><br><span class="line">&#125;</span><br><span class="line">p.mu.Unlock()</span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">atomic.AddInt32(&amp;goroutines, +<span class="number">1</span>)</span><br><span class="line"><span class="keyword">go</span> <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line"><span class="keyword">select</span> &#123;</span><br><span class="line"><span class="keyword">case</span> &lt;-parent.Done():</span><br><span class="line">child.cancel(<span class="literal">false</span>, parent.Err())</span><br><span class="line"><span class="keyword">case</span> &lt;-child.Done():</span><br><span class="line">&#125;</span><br><span class="line">&#125;()</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>propagateCancel</code> contains many logics, and some of them can’t be understood easily, I will write another post for those parts. But in this post, we only need to understand how to establish the relationship between parent and child for genernal cases. </p><p>The key point is function <code>parentCancelCtx</code>, which is used to find the innermost cancellable ancestor context:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">parentCancelCtx</span><span class="params">(parent Context)</span></span> (*cancelCtx, <span class="type">bool</span>) &#123;</span><br><span class="line">done := parent.Done()</span><br><span class="line"><span class="keyword">if</span> done == closedchan || done == <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, <span class="literal">false</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// Value() will propagate to the root context</span></span><br><span class="line">p, ok := parent.Value(&amp;cancelCtxKey).(*cancelCtx)</span><br><span class="line"><span class="keyword">if</span> !ok &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, <span class="literal">false</span></span><br><span class="line">&#125;</span><br><span class="line">p.mu.Lock()</span><br><span class="line">ok = p.done == done</span><br><span class="line">p.mu.Unlock()</span><br><span class="line"><span class="keyword">if</span> !ok &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span>, <span class="literal">false</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> p, <span class="literal">true</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>You can notice that <code>Value</code> method is called, since we analyzed in the above section, <code>Value</code> will pass the search until the root context. Great. </p><p>Back to the <code>propagateCancel</code> function, if cancellable ancestor context is found, then current context is added into the <code>children</code> hash map as below:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> p.children == <span class="literal">nil</span> &#123;</span><br><span class="line">p.children = <span class="built_in">make</span>(<span class="keyword">map</span>[canceler]<span class="keyword">struct</span>&#123;&#125;)</span><br><span class="line">&#125;</span><br><span class="line">p.children[child] = <span class="keyword">struct</span>&#123;&#125;&#123;&#125;</span><br></pre></td></tr></table></figure><p>The relationship is established. </p><h3 id="Summary"><a href="#Summary" class="headerlink" title="Summary"></a>Summary</h3><p>In this article, we review the source code of <code>Context</code> package and understand how <code>Context</code>,  <code>valueCtx</code> and <code>cancelCtx</code> works. </p><p><code>Context</code> contains the other two types of context: <code>timeOut</code> context and <code>deadLine</code> context, Let’s work on that in the second part of this post series. </p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;Background&quot;&gt;&lt;a href=&quot;#Background&quot; class=&quot;headerlink&quot; title=&quot;Background&quot;&gt;&lt;/a&gt;Background&lt;/h3&gt;&lt;p&gt;As a Golang user and learner, I always</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>Golang bytes.Buffer and bufio</title>
    <link href="https://baoqger.github.io/2021/04/04/golang-bytes-buffer/"/>
    <id>https://baoqger.github.io/2021/04/04/golang-bytes-buffer/</id>
    <published>2021-04-04T09:50:14.000Z</published>
    <updated>2024-08-30T08:47:30.148Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Background"><a href="#Background" class="headerlink" title="Background"></a>Background</h3><p>In this post, I will show you the usage and implementation of two Golang standard packages’ : <code>bytes</code> (especially <code>bytes.Buffer</code>) and <code>bufio</code>.</p><p>These two packages are widely used in the Golang ecosystem especially works related to networking, files and other IO tasks. </p><h3 id="Demo-application"><a href="#Demo-application" class="headerlink" title="Demo application"></a>Demo application</h3><p>One good way to learn new programming knowledge is checking how to use it in real-world applications. The following great demo application is from the open source book <code>Network Programming with Go by Jan Newmarch</code>.</p><p>For your convenience, I paste the code here. This demo consists of two parts: client side and server side, which together form a simple directory browsing protocol. The client would be at the user end, talking to a server somewhere else. The client sends commands to the server side that allows you to list files in a directory and print the directory on the server. </p><p>First is the client side program: </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">    <span class="string">&quot;fmt&quot;</span></span><br><span class="line">    <span class="string">&quot;net&quot;</span></span><br><span class="line">    <span class="string">&quot;os&quot;</span></span><br><span class="line">    <span class="string">&quot;bufio&quot;</span></span><br><span class="line">    <span class="string">&quot;strings&quot;</span></span><br><span class="line">    <span class="string">&quot;bytes&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="comment">// strings used by the user interface</span></span><br><span class="line"><span class="keyword">const</span> (</span><br><span class="line">    uiDir  = <span class="string">&quot;dir&quot;</span></span><br><span class="line">    uiCd   = <span class="string">&quot;cd&quot;</span></span><br><span class="line">    uiPwd  = <span class="string">&quot;pwd&quot;</span></span><br><span class="line">    uiQuit = <span class="string">&quot;quit&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="comment">// strings used across the network</span></span><br><span class="line"><span class="keyword">const</span> (</span><br><span class="line">    DIR = <span class="string">&quot;DIR&quot;</span></span><br><span class="line">    CD  = <span class="string">&quot;CD&quot;</span></span><br><span class="line">    PWD = <span class="string">&quot;PWD&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">    <span class="keyword">if</span> <span class="built_in">len</span>(os.Args) != <span class="number">2</span> &#123;</span><br><span class="line">        fmt.Println(<span class="string">&quot;Usage: &quot;</span>, os.Args[<span class="number">0</span>], <span class="string">&quot;host&quot;</span>)</span><br><span class="line">        os.Exit(<span class="number">1</span>)</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    host := os.Args[<span class="number">1</span>]</span><br><span class="line"></span><br><span class="line">    conn, err := net.Dial(<span class="string">&quot;tcp&quot;</span>, host+<span class="string">&quot;:1202&quot;</span>)</span><br><span class="line">    checkError(err)</span><br><span class="line"></span><br><span class="line">    reader := bufio.NewReader(os.Stdin)</span><br><span class="line">    <span class="keyword">for</span> &#123;</span><br><span class="line">        line, err := reader.ReadString(<span class="string">&#x27;\n&#x27;</span>)</span><br><span class="line">        <span class="comment">// lose trailing whitespace</span></span><br><span class="line">        line = strings.TrimRight(line, <span class="string">&quot; \t\r\n&quot;</span>)</span><br><span class="line">        <span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">            <span class="keyword">break</span></span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// split into command + arg</span></span><br><span class="line">        strs := strings.SplitN(line, <span class="string">&quot; &quot;</span>, <span class="number">2</span>)</span><br><span class="line">        <span class="comment">// decode user request</span></span><br><span class="line">        <span class="keyword">switch</span> strs[<span class="number">0</span>] &#123;</span><br><span class="line">        <span class="keyword">case</span> uiDir:</span><br><span class="line">            dirRequest(conn)</span><br><span class="line">        <span class="keyword">case</span> uiCd:</span><br><span class="line">            <span class="keyword">if</span> <span class="built_in">len</span>(strs) != <span class="number">2</span> &#123;</span><br><span class="line">                fmt.Println(<span class="string">&quot;cd &lt;dir&gt;&quot;</span>)</span><br><span class="line">                <span class="keyword">continue</span></span><br><span class="line">            &#125;</span><br><span class="line">            fmt.Println(<span class="string">&quot;CD \&quot;&quot;</span>, strs[<span class="number">1</span>], <span class="string">&quot;\&quot;&quot;</span>)</span><br><span class="line">            cdRequest(conn, strs[<span class="number">1</span>])</span><br><span class="line">        <span class="keyword">case</span> uiPwd:</span><br><span class="line">            pwdRequest(conn)</span><br><span class="line">        <span class="keyword">case</span> uiQuit:</span><br><span class="line">            conn.Close()</span><br><span class="line">            os.Exit(<span class="number">0</span>)</span><br><span class="line">        <span class="keyword">default</span>:</span><br><span class="line">            fmt.Println(<span class="string">&quot;Unknown command&quot;</span>)</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">dirRequest</span><span class="params">(conn net.Conn)</span></span> &#123;</span><br><span class="line">    conn.Write([]<span class="type">byte</span>(DIR + <span class="string">&quot; &quot;</span>))</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> buf [<span class="number">512</span>]<span class="type">byte</span></span><br><span class="line">    result := bytes.NewBuffer(<span class="literal">nil</span>)</span><br><span class="line">    <span class="keyword">for</span> &#123;</span><br><span class="line">        <span class="comment">// read till we hit a blank line</span></span><br><span class="line">        n, _ := conn.Read(buf[<span class="number">0</span>:])</span><br><span class="line">        result.Write(buf[<span class="number">0</span>:n])</span><br><span class="line">        length := result.Len()</span><br><span class="line">        contents := result.Bytes()</span><br><span class="line">        <span class="keyword">if</span> <span class="type">string</span>(contents[length<span class="number">-4</span>:]) == <span class="string">&quot;\r\n\r\n&quot;</span> &#123;</span><br><span class="line">            fmt.Println(<span class="type">string</span>(contents[<span class="number">0</span> : length<span class="number">-4</span>]))</span><br><span class="line">            <span class="keyword">return</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">cdRequest</span><span class="params">(conn net.Conn, dir <span class="type">string</span>)</span></span> &#123;</span><br><span class="line">    conn.Write([]<span class="type">byte</span>(CD + <span class="string">&quot; &quot;</span> + dir))</span><br><span class="line">    <span class="keyword">var</span> response [<span class="number">512</span>]<span class="type">byte</span></span><br><span class="line">    n, _ := conn.Read(response[<span class="number">0</span>:])</span><br><span class="line">    s := <span class="type">string</span>(response[<span class="number">0</span>:n])</span><br><span class="line">    <span class="keyword">if</span> s != <span class="string">&quot;OK&quot;</span> &#123;</span><br><span class="line">        fmt.Println(<span class="string">&quot;Failed to change dir&quot;</span>)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">pwdRequest</span><span class="params">(conn net.Conn)</span></span> &#123;</span><br><span class="line">    conn.Write([]<span class="type">byte</span>(PWD))</span><br><span class="line">    <span class="keyword">var</span> response [<span class="number">512</span>]<span class="type">byte</span></span><br><span class="line">    n, _ := conn.Read(response[<span class="number">0</span>:])</span><br><span class="line">    s := <span class="type">string</span>(response[<span class="number">0</span>:n])</span><br><span class="line">    fmt.Println(<span class="string">&quot;Current dir \&quot;&quot;</span> + s + <span class="string">&quot;\&quot;&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">checkError</span><span class="params">(err <span class="type">error</span>)</span></span> &#123;</span><br><span class="line">    <span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">        fmt.Println(<span class="string">&quot;Fatal error &quot;</span>, err.Error())</span><br><span class="line">        os.Exit(<span class="number">1</span>)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h5 id="client-go"><a href="#client-go" class="headerlink" title="client.go"></a><strong><code>client.go</code></strong></h5><p>Then is server side code: </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">    <span class="string">&quot;fmt&quot;</span></span><br><span class="line">    <span class="string">&quot;net&quot;</span></span><br><span class="line">    <span class="string">&quot;os&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> (</span><br><span class="line">    DIR = <span class="string">&quot;DIR&quot;</span></span><br><span class="line">    CD  = <span class="string">&quot;CD&quot;</span></span><br><span class="line">    PWD = <span class="string">&quot;PWD&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line"></span><br><span class="line">    service := <span class="string">&quot;0.0.0.0:1202&quot;</span></span><br><span class="line">    tcpAddr, err := net.ResolveTCPAddr(<span class="string">&quot;tcp&quot;</span>, service)</span><br><span class="line">    checkError(err)</span><br><span class="line"></span><br><span class="line">    listener, err := net.ListenTCP(<span class="string">&quot;tcp&quot;</span>, tcpAddr)</span><br><span class="line">    checkError(err)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> &#123;</span><br><span class="line">        conn, err := listener.Accept()</span><br><span class="line">        <span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">            <span class="keyword">continue</span></span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">go</span> handleClient(conn)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">handleClient</span><span class="params">(conn net.Conn)</span></span> &#123;</span><br><span class="line">    <span class="keyword">defer</span> conn.Close()</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> buf [<span class="number">512</span>]<span class="type">byte</span></span><br><span class="line">    <span class="keyword">for</span> &#123;</span><br><span class="line">        n, err := conn.Read(buf[<span class="number">0</span>:])</span><br><span class="line">        <span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">            conn.Close()</span><br><span class="line">            <span class="keyword">return</span></span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        s := <span class="type">string</span>(buf[<span class="number">0</span>:n])</span><br><span class="line">        <span class="comment">// decode request</span></span><br><span class="line">        <span class="keyword">if</span> s[<span class="number">0</span>:<span class="number">2</span>] == CD &#123;</span><br><span class="line">            chdir(conn, s[<span class="number">3</span>:])</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> s[<span class="number">0</span>:<span class="number">3</span>] == DIR &#123;</span><br><span class="line">            dirList(conn)</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> s[<span class="number">0</span>:<span class="number">3</span>] == PWD &#123;</span><br><span class="line">            pwd(conn)</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">chdir</span><span class="params">(conn net.Conn, s <span class="type">string</span>)</span></span> &#123;</span><br><span class="line">    <span class="keyword">if</span> os.Chdir(s) == <span class="literal">nil</span> &#123;</span><br><span class="line">        conn.Write([]<span class="type">byte</span>(<span class="string">&quot;OK&quot;</span>))</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        conn.Write([]<span class="type">byte</span>(<span class="string">&quot;ERROR&quot;</span>))</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">pwd</span><span class="params">(conn net.Conn)</span></span> &#123;</span><br><span class="line">    s, err := os.Getwd()</span><br><span class="line">    <span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">        conn.Write([]<span class="type">byte</span>(<span class="string">&quot;&quot;</span>))</span><br><span class="line">        <span class="keyword">return</span></span><br><span class="line">    &#125;</span><br><span class="line">    conn.Write([]<span class="type">byte</span>(s))</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">dirList</span><span class="params">(conn net.Conn)</span></span> &#123;</span><br><span class="line">    <span class="keyword">defer</span> conn.Write([]<span class="type">byte</span>(<span class="string">&quot;\r\n&quot;</span>))</span><br><span class="line"></span><br><span class="line">    dir, err := os.Open(<span class="string">&quot;.&quot;</span>)</span><br><span class="line">    <span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">        <span class="keyword">return</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    names, err := dir.Readdirnames(<span class="number">-1</span>)</span><br><span class="line">    <span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">        <span class="keyword">return</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">for</span> _, nm := <span class="keyword">range</span> names &#123;</span><br><span class="line">        conn.Write([]<span class="type">byte</span>(nm + <span class="string">&quot;\r\n&quot;</span>))</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">checkError</span><span class="params">(err <span class="type">error</span>)</span></span> &#123;</span><br><span class="line">    <span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">        fmt.Println(<span class="string">&quot;Fatal error &quot;</span>, err.Error())</span><br><span class="line">        os.Exit(<span class="number">1</span>)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h5 id="server-go"><a href="#server-go" class="headerlink" title="server.go"></a><strong><code>server.go</code></strong></h5><h3 id="Bytes-Buffer"><a href="#Bytes-Buffer" class="headerlink" title="Bytes.Buffer"></a>Bytes.Buffer</h3><p>Based on the above demo, let’s review how <code>Bytes.Buffer</code> is used. </p><p>According to Go official document:  </p><blockquote><p>Package bytes implements functions for the manipulation of byte slices.<br>A Buffer is a variable-sized buffer of bytes with Read and Write methods.</p></blockquote><p>The <code>bytes</code> package itself is easy to understand, which provides functionalities to manipulate byte slice. The concern is <code>bytes.Buffer</code>, what benefits can we get by using it? Let’s review the demo code where it is used.</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">dirRequest</span><span class="params">(conn net.Conn)</span></span> &#123;</span><br><span class="line">    conn.Write([]<span class="type">byte</span>(DIR + <span class="string">&quot; &quot;</span>))</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> buf [<span class="number">512</span>]<span class="type">byte</span></span><br><span class="line">    result := bytes.NewBuffer(<span class="literal">nil</span>)</span><br><span class="line">    <span class="keyword">for</span> &#123;</span><br><span class="line">        <span class="comment">// read till we hit a blank line</span></span><br><span class="line">        n, _ := conn.Read(buf[<span class="number">0</span>:])</span><br><span class="line">        result.Write(buf[<span class="number">0</span>:n])</span><br><span class="line">        length := result.Len()</span><br><span class="line">        contents := result.Bytes()</span><br><span class="line">        <span class="keyword">if</span> <span class="type">string</span>(contents[length<span class="number">-4</span>:]) == <span class="string">&quot;\r\n\r\n&quot;</span> &#123;</span><br><span class="line">            fmt.Println(<span class="type">string</span>(contents[<span class="number">0</span> : length<span class="number">-4</span>]))</span><br><span class="line">            <span class="keyword">return</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>The above code block is from <code>client.go</code> part. And the scenario is: the client send <code>DIR</code> command to server side, server run this <code>DIR</code> command which will return contents of current directory. Client and server use <code>conn.Read</code> and <code>conn.Write</code> to communicate with each other. The client keeps reading data in a <code>for</code> loop until all the data is consumed which is marked by two continuous <code>\r\n</code> strings. </p><p>In this case, a new <code>bytes.Buffer</code> object is created by calling <code>NewBuffer</code> method and three other member methods are called: <code>Write</code>, <code>Len</code> and <code>Bytes</code>. Let’s review their source code: </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> Buffer <span class="keyword">struct</span> &#123;</span><br><span class="line">buf      []<span class="type">byte</span> </span><br><span class="line">off      <span class="type">int</span>    </span><br><span class="line">lastRead readOp </span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(b *Buffer)</span></span> Write(p []<span class="type">byte</span>) (n <span class="type">int</span>, err <span class="type">error</span>) &#123;</span><br><span class="line">b.lastRead = opInvalid</span><br><span class="line">m, ok := b.tryGrowByReslice(<span class="built_in">len</span>(p))</span><br><span class="line"><span class="keyword">if</span> !ok &#123;</span><br><span class="line">m = b.grow(<span class="built_in">len</span>(p))</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> <span class="built_in">copy</span>(b.buf[m:], p), <span class="literal">nil</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(b *Buffer)</span></span> Len() <span class="type">int</span> &#123; </span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">len</span>(b.buf) - b.off </span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(b *Buffer)</span></span> Bytes() []<span class="type">byte</span> &#123; </span><br><span class="line">    <span class="keyword">return</span> b.buf[b.off:] </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>The implementation is easy to understand and no need to add more explanation. One interesting point is inside the <code>Write</code> function. It will first check whether the buffer has enough room for new bytes, if no then it will call   internal <code>grow</code> method to add more space. </p><p>In fact, this is the biggest benefit you can get from <code>Buffer</code>. You don’t need to manage the dynamic change of buffer length manually, <code>bytes.Buffer</code> will help you to do that. In this way you won’t waste memory by setting the possible maximum length just for providing enough space. To some extend, it is similar to the <strong>vector</strong> in C++ language.   </p><h3 id="Bufio"><a href="#Bufio" class="headerlink" title="Bufio"></a>Bufio</h3><p>Next, let’s review how <code>Bufio</code> pacakge works. In our demo, it is used as following: </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">reader := bufio.NewReader(os.Stdin)</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> &#123;</span><br><span class="line">    line, err := reader.ReadString(<span class="string">&#x27;\n&#x27;</span>)</span><br><span class="line">    <span class="comment">// hide other code below</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Before we dive into the details about the demo code, let’s first understand what is the purpose of <code>bufio</code> package. </p><p>First we need to understand that when applications run IO operations like read or write data from or to files, network and database. It will trigger <code>system call</code> in the bottom level, which is heavy in the performance point of view.  </p><p>Buffer IO is a technique used to temporarily accumulate the results for an IO operation before transmitting it forward. This technique can increase the speed of a program by reducing the number of system calls. For example, in case you want to read data from disk byte by byte. Instead of directly reading each byte from the disk every time, with buffer IO technique, we can read a block of data into buffer once, then consumers can read data from the buffer in whatever way you want. Performance will be improved by reducing heavy system calls.</p><p>Concretely, let’s review how <code>bufio</code> package do this. The Go official document goes like this:</p><blockquote><p>Package bufio implements buffered I/O. It wraps an io.Reader or io.Writer object, creating another object (Reader or Writer) that also implements the interface but provides buffering and some help for textual I/O.</p></blockquote><p>Let’s understand the definition by reading the source code: </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// NewReader and NewReaderSize in bufio.go</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">NewReader</span><span class="params">(rd io.Reader)</span></span> *Reader &#123;</span><br><span class="line"><span class="keyword">return</span> NewReaderSize(rd, defaultBufSize)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">NewReaderSize</span><span class="params">(rd io.Reader, size <span class="type">int</span>)</span></span> *Reader &#123;</span><br><span class="line">b, ok := rd.(*Reader)</span><br><span class="line"><span class="keyword">if</span> ok &amp;&amp; <span class="built_in">len</span>(b.buf) &gt;= size &#123;</span><br><span class="line"><span class="keyword">return</span> b</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> size &lt; minReadBufferSize &#123;</span><br><span class="line">size = minReadBufferSize</span><br><span class="line">&#125;</span><br><span class="line">r := <span class="built_in">new</span>(Reader)</span><br><span class="line">r.reset(<span class="built_in">make</span>([]<span class="type">byte</span>, size), rd)</span><br><span class="line"><span class="keyword">return</span> r</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>In our demo, we use <code>NewReader</code> which then calls <code>NewReaderSize</code> to create a new <code>Reader</code> instance. One thing need to notice is that the parameter is <code>io.Reader</code> type, which is an important interface implements only one method <code>Read</code>.</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// the Reader interface in io.go file</span></span><br><span class="line"><span class="keyword">type</span> Reader <span class="keyword">interface</span> &#123;</span><br><span class="line">Read(p []<span class="type">byte</span>) (n <span class="type">int</span>, err <span class="type">error</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>In our case, we use <code>os.Stdin</code> as the function argument, which will read data from standard input. </p><p>Then let’s reivew declaration of <code>bufio.Reader</code>  which wraps <code>io.Reader</code>:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Reader implements buffering for an io.Reader object.</span></span><br><span class="line"><span class="keyword">type</span> Reader <span class="keyword">struct</span> &#123;</span><br><span class="line">buf          []<span class="type">byte</span></span><br><span class="line">rd           io.Reader <span class="comment">// reader provided by the client</span></span><br><span class="line">r, w         <span class="type">int</span>       <span class="comment">// buf read and write positions</span></span><br><span class="line">err          <span class="type">error</span></span><br><span class="line">lastByte     <span class="type">int</span> <span class="comment">// last byte read for UnreadByte; -1 means invalid</span></span><br><span class="line">lastRuneSize <span class="type">int</span> <span class="comment">// size of last rune read for UnreadRune; -1 means invalid</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>bufio.Reader</code> has many methods defined, in our case we use <code>ReadString</code>, which will call another low-level method <code>ReadSlice</code>. </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(b *Reader)</span></span> ReadSlice(delim <span class="type">byte</span>) (line []<span class="type">byte</span>, err <span class="type">error</span>) &#123;</span><br><span class="line">s := <span class="number">0</span> </span><br><span class="line"><span class="keyword">for</span> &#123;</span><br><span class="line"><span class="comment">// Search buffer.</span></span><br><span class="line"><span class="keyword">if</span> i := bytes.IndexByte(b.buf[b.r+s:b.w], delim); i &gt;= <span class="number">0</span> &#123;</span><br><span class="line">i += s</span><br><span class="line">line = b.buf[b.r : b.r+i+<span class="number">1</span>]</span><br><span class="line">b.r += i + <span class="number">1</span></span><br><span class="line"><span class="keyword">break</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> b.err != <span class="literal">nil</span> &#123;</span><br><span class="line">line = b.buf[b.r:b.w]</span><br><span class="line">b.r = b.w</span><br><span class="line">err = b.readErr()</span><br><span class="line"><span class="keyword">break</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> b.Buffered() &gt;= <span class="built_in">len</span>(b.buf) &#123;</span><br><span class="line">b.r = b.w</span><br><span class="line">line = b.buf</span><br><span class="line">err = ErrBufferFull</span><br><span class="line"><span class="keyword">break</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">s = b.w - b.r </span><br><span class="line"></span><br><span class="line">b.fill() <span class="comment">// buffer is not full</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> i := <span class="built_in">len</span>(line) - <span class="number">1</span>; i &gt;= <span class="number">0</span> &#123;</span><br><span class="line">b.lastByte = <span class="type">int</span>(line[i])</span><br><span class="line">b.lastRuneSize = <span class="number">-1</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>When <code>buf</code> byte slice contains data, it will search the target value inside it. But initially <code>buf</code> is empty, it need firstly load some data, right? That is the most interesting part. The <code>b.fill()</code> is just for that. </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(b *Reader)</span></span> fill() &#123;</span><br><span class="line"><span class="keyword">if</span> b.r &gt; <span class="number">0</span> &#123;</span><br><span class="line"><span class="built_in">copy</span>(b.buf, b.buf[b.r:b.w])</span><br><span class="line">b.w -= b.r</span><br><span class="line">b.r = <span class="number">0</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> b.w &gt;= <span class="built_in">len</span>(b.buf) &#123;</span><br><span class="line"><span class="built_in">panic</span>(<span class="string">&quot;bufio: tried to fill full buffer&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Read new data: try a limited number of times.</span></span><br><span class="line"><span class="keyword">for</span> i := maxConsecutiveEmptyReads; i &gt; <span class="number">0</span>; i-- &#123;</span><br><span class="line">n, err := b.rd.Read(b.buf[b.w:]) <span class="comment">// call the underlying Reader</span></span><br><span class="line"><span class="keyword">if</span> n &lt; <span class="number">0</span> &#123;</span><br><span class="line"><span class="built_in">panic</span>(errNegativeRead)</span><br><span class="line">&#125;</span><br><span class="line">b.w += n</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">b.err = err</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> n &gt; <span class="number">0</span> &#123;</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">b.err = io.ErrNoProgress</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>The data is loaded into <code>buf</code> by calling the underlying Reader,</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">n, err := b.rd.Read(b.buf[b.w:])</span><br></pre></td></tr></table></figure><p>in our case is <code>os.Stdin</code>.</p><h3 id="Customized-Reader"><a href="#Customized-Reader" class="headerlink" title="Customized Reader"></a>Customized Reader</h3><p>To have a better understand about the buffering IO technique, we can define our own customized <code>Reader</code> and pass it <code>bufio.NewReader</code> as follows: </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line"><span class="string">&quot;bufio&quot;</span></span><br><span class="line"><span class="string">&quot;fmt&quot;</span></span><br><span class="line"><span class="string">&quot;io&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="comment">// customized Reader struct</span></span><br><span class="line"><span class="keyword">type</span> Reader <span class="keyword">struct</span> &#123;</span><br><span class="line">counter <span class="type">int</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(r *Reader)</span></span> Read(p []<span class="type">byte</span>) (n <span class="type">int</span>, err <span class="type">error</span>) &#123;</span><br><span class="line">fmt.Println(<span class="string">&quot;Read&quot;</span>)</span><br><span class="line"><span class="keyword">if</span> r.counter &gt;= <span class="number">3</span> &#123; <span class="comment">// simulate EOF</span></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>, io.EOF</span><br><span class="line">&#125;</span><br><span class="line">s := <span class="string">&quot;a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p&quot;</span></span><br><span class="line"><span class="built_in">copy</span>(p, s)</span><br><span class="line">r.counter += <span class="number">1</span></span><br><span class="line"><span class="keyword">return</span> <span class="built_in">len</span>(s), <span class="literal">nil</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">r := <span class="built_in">new</span>(Reader)</span><br><span class="line">br := bufio.NewReader(r)</span><br><span class="line"><span class="keyword">for</span> &#123;</span><br><span class="line">token, err := br.ReadSlice(<span class="string">&#x27;,&#x27;</span>)</span><br><span class="line">fmt.Printf(<span class="string">&quot;Token: %q\n&quot;</span>, token)</span><br><span class="line"><span class="keyword">if</span> err == io.EOF &#123;</span><br><span class="line">fmt.Println(<span class="string">&quot;Read done&quot;</span>)</span><br><span class="line"><span class="keyword">break</span></span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Please run the demo code above, observe the output and think about why it generates such result. </p><h3 id="Summary"><a href="#Summary" class="headerlink" title="Summary"></a>Summary</h3><p>In this post, I only talked about <code>Reader</code> part of bufio, if you understand the behavior explained above clearly, it’s easy to understand <code>Writer</code> quickly as well. </p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;Background&quot;&gt;&lt;a href=&quot;#Background&quot; class=&quot;headerlink&quot; title=&quot;Background&quot;&gt;&lt;/a&gt;Background&lt;/h3&gt;&lt;p&gt;In this post, I will show you the usag</summary>
      
    
    
    
    
    <category term="Golang, bufio, bytes, buffer" scheme="https://baoqger.github.io/tags/Golang-bufio-bytes-buffer/"/>
    
  </entry>
  
  <entry>
    <title>go-module</title>
    <link href="https://baoqger.github.io/2021/03/31/go-module/"/>
    <id>https://baoqger.github.io/2021/03/31/go-module/</id>
    <published>2021-03-31T06:42:49.000Z</published>
    <updated>2021-12-23T12:34:34.791Z</updated>
    
    
    
    
    
  </entry>
  
  <entry>
    <title>Fabio source code study part 2</title>
    <link href="https://baoqger.github.io/2021/02/20/fabio-golang-best-practise/"/>
    <id>https://baoqger.github.io/2021/02/20/fabio-golang-best-practise/</id>
    <published>2021-02-20T03:01:08.000Z</published>
    <updated>2021-12-23T12:34:34.791Z</updated>
    
    <content type="html"><![CDATA[<p>Golang concurrent pattens:</p><p>channels</p><p>sync.Mutex</p><p>sync.Waitgroup</p><p>sync.Once</p><p>sync.Pool</p><p>Select</p><p>atomic.Value</p><p>Others:</p><p>byte.Buffer</p><p>bufferio</p><p>type assertion of interface</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;Golang concurrent pattens:&lt;/p&gt;
&lt;p&gt;channels&lt;/p&gt;
&lt;p&gt;sync.Mutex&lt;/p&gt;
&lt;p&gt;sync.Waitgroup&lt;/p&gt;
&lt;p&gt;sync.Once&lt;/p&gt;
&lt;p&gt;sync.Pool&lt;/p&gt;
&lt;p&gt;Select&lt;/p&gt;
&lt;p</summary>
      
    
    
    
    
    <category term="Best practice," scheme="https://baoqger.github.io/tags/Best-practice/"/>
    
  </entry>
  
  <entry>
    <title>Golang package</title>
    <link href="https://baoqger.github.io/2021/02/06/golang-package-module/"/>
    <id>https://baoqger.github.io/2021/02/06/golang-package-module/</id>
    <published>2021-02-05T22:55:52.000Z</published>
    <updated>2021-12-23T12:34:34.793Z</updated>
    
    <content type="html"><![CDATA[<h2 id="Background"><a href="#Background" class="headerlink" title="Background"></a>Background</h2><p>In this post, I’ll talk about Golang package based on my learning and use experience. </p><p>You’ll learn the following topics in this post:</p><ul><li>Basics about Go package</li><li>How to use and import a Go package</li><li>Demo with real-world Go package</li></ul><h2 id="Basics-about-Go-package"><a href="#Basics-about-Go-package" class="headerlink" title="Basics about Go package"></a>Basics about Go package</h2><h4 id="What’s-Go-package"><a href="#What’s-Go-package" class="headerlink" title="What’s Go package"></a>What’s Go package</h4><p>Simply speaking, <code>Go package</code> provides a solution to the requirement of <code>code reuse</code>, which is an important part of software engineering. </p><p>In Golang’s official document, the definition of packages goes as following: </p><blockquote><p>Go programs are organized into packages. A package is a collection of source files in the same directory that are compiled together. Functions, types, variables, and constants defined in one source file are visible to all other source files within the same package.</p></blockquote><p>There are several critical points in the definition let’s review them one by one. </p><ul><li><p>First, one package can contain <code>more than one</code> source files. This is different from other languages, for example in <code>Javascript</code> , each source file is an independent module that exports variables to other files to import.</p></li><li><p>Second, all the source files for a package are organized inside a directory. The package name must be the same as the directory name. </p></li><li><p>Third, the files inside the subdirectories should be excluded. Each subdirectory is another package. </p></li></ul><p>To have a better understanding about these three points, let’s check the structure of the <code>net</code> package in the Go standard library. </p><p><img src="/images/go-package-std.png" alt="net-package"></p><p>All the <code>.go</code> source files directly under the <code>net</code> directory contain the following pacakge declaration on the top of the file: </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> net</span><br></pre></td></tr></table></figure><p>This means that it is part of the net package. </p><p>There are several subdirectories under <code>net</code> directoy, and each of these subdirectory is an independant package. For example, the <code>net/http</code> package consists of all the files inside the <code>http</code> subdirectory. If you open the files inside <code>http</code> directory, the package declaration is:  </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> http</span><br></pre></td></tr></table></figure><h4 id="Types-of-Go-package"><a href="#Types-of-Go-package" class="headerlink" title="Types of Go package"></a>Types of Go package</h4><p>Generally speaking, there are two types of packages: <code>library package</code> and <code>main package</code>. After build, the main package will be compiled into an executable file. While a library package is not self-executable, instead, it provides the utility functions.</p><h4 id="Member-visibility-of-Go-package"><a href="#Member-visibility-of-Go-package" class="headerlink" title="Member visibility of Go package"></a>Member visibility of Go package</h4><p>Different from other language like Javascript, Golang package doesn’t provide keyword such as <code>export</code>, <code>public</code>, <code>private</code> and so on to explicitly export members to the outside world. </p><p>Instead, the visibility of member inside one package is determined by the casing of the first letter. If the first letter is upper case then it can be impoted by other packages. </p><h4 id="Lifecycle-of-package"><a href="#Lifecycle-of-package" class="headerlink" title="Lifecycle of package"></a>Lifecycle of package</h4><p>For the library package we mentioned above, when it’s imported the <code>init</code> method will be called automatically. You can do some package initialization work inside it. </p><p>For the main pacakge, it must provide the <code>main</code> method as the entry point when it’s running. </p><h2 id="Use-and-Import-Go-package"><a href="#Use-and-Import-Go-package" class="headerlink" title="Use and Import Go package"></a>Use and Import Go package</h2><p>Before <code>Go Module</code> was introduced, the development of Golang application is based on the <code>Go workspace</code>. In this post, I’ll focus on the solutions based on <code>Go workspace</code>. Go module is another topic I will talk about in a future post. </p><h4 id="Go-workspace"><a href="#Go-workspace" class="headerlink" title="Go workspace"></a>Go workspace</h4><p>By convention, all your Go code and the code(or the packages) you import, must reside in a single workspace. A workspace is nothing but a directory in your file system whose path is stored in the environment variable <code>GOPATH</code>.</p><p>As a new comer into the Golang world, at the beginning the <code>GOPATH</code> workspace configuration confused me a lot. </p><p>For example, you want to use third-party library Consol in your application. After you run </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">go get github.com/hashicorp/consul</span><br></pre></td></tr></table></figure><p>The library is installed on your local machine. The code would be cloned on disk at <code>$GOPATH/src/github.com/hashicorp/consul</code></p><p>In your application, you will import this library in the following way:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> (</span><br><span class="line">    <span class="string">&quot;github.com/hashicorp/consul&quot;</span></span><br><span class="line">)</span><br></pre></td></tr></table></figure><p>Thanks to the GOPATH mechanics, this import can be resolved on disk and Go tool can locate, build and test the code. Simply speaking, the package name maps to the real location of the package on your local machine. </p><p>But of course, this mechanics has many limitation such as package version control, workspace constrains an so on. That’s the motivation why we need Go module. </p><h4 id="Ways-to-import-Golang-package"><a href="#Ways-to-import-Golang-package" class="headerlink" title="Ways to import Golang package"></a>Ways to import Golang package</h4><p>Beside the default way, there are several ways to import a package based on your usage. </p><p><strong>Import as alias</strong>: this is useful when two packages have the same name. You can give any alias for an imported package as below:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> (</span><br><span class="line">consulapi <span class="string">&quot;github.com/hashicorp/consul/api&quot;</span></span><br><span class="line">)</span><br></pre></td></tr></table></figure><p><strong>Import for side effect</strong>: when reading source code of popular open source projects, you can see many package import in the following way:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> (</span><br><span class="line"><span class="string">&quot;database/sql&quot;</span></span><br><span class="line"></span><br><span class="line">_ <span class="string">&quot;github.com/lib/pq&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>It’s widely used when all you need from the imported package is running the <code>init</code> method.</p><p>For example in the above case, library <code>pq</code> is imported in this way. You can check the source code for <code>pq</code> library and its <code>init</code> method call <code>sql.Register</code> method for registration as below:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">init</span><span class="params">()</span></span> &#123;</span><br><span class="line">sql.Register(<span class="string">&quot;postgres&quot;</span>, &amp;Driver&#123;&#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>Internal package</strong>: this is an interesting feature to learn. <code>Internal</code> is a special directory name recognized by the Go tool which will prevent the package from being imported by any other packages unless both share the same ancestor directory. The packages in an <code>internal</code> directory are said to be internal packages. In detail you can refer to <a href="https://dave.cheney.net/2019/10/06/use-internal-packages-to-reduce-your-public-api-surface">this artical</a>.</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;Background&quot;&gt;&lt;a href=&quot;#Background&quot; class=&quot;headerlink&quot; title=&quot;Background&quot;&gt;&lt;/a&gt;Background&lt;/h2&gt;&lt;p&gt;In this post, I’ll talk about Golang p</summary>
      
    
    
    
    
    <category term="Golang, package, workspace, vendor" scheme="https://baoqger.github.io/tags/Golang-package-workspace-vendor/"/>
    
  </entry>
  
  <entry>
    <title>Fabio source code study part 1</title>
    <link href="https://baoqger.github.io/2021/01/29/fabio-source-code-study/"/>
    <id>https://baoqger.github.io/2021/01/29/fabio-source-code-study/</id>
    <published>2021-01-29T14:09:56.000Z</published>
    <updated>2024-08-30T08:47:13.165Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Background"><a href="#Background" class="headerlink" title="Background"></a>Background</h3><p>In this two-part blog series, I want to share the lessons learned from reading the soruce code of the project <code>Fabio</code>. In my previous blog, I shared with you how to use Fabio as a load balancing in the micro services applicatoins, in detail you can refer to this <a href="https://baoqger.github.io/2020/12/30/golang-load-balancing-fabio/">article</a>.  </p><p>Since <code>Fabio</code> is not a tiny project, it’s hard to cover everything inside this project. I will mainly focus on two aspects: firstly in the <strong>architecture design  level</strong>, I will study how it can work as a load balancer without any configuration file (Part one), and secondly in the <strong>language level</strong>, I want to summarize the best practice of writing Golang programs by investigating which features of Golang it uses and how it uses (Part two). </p><h3 id="Fabio-architecture-design"><a href="#Fabio-architecture-design" class="headerlink" title="Fabio architecture design"></a>Fabio architecture design</h3><p>Let’s start by introducing some background about Fabio. Following paragraph is from its official document: </p><blockquote><p>Fabio is an HTTP and TCP reverse proxy that configures itself with data from Consul. Traditional load balancers and reverse proxies need to be configured with a config file. </p></blockquote><p>If you’re familiar with other load balancer service such as <code>Nginx</code>, it will be easy for you to understand how Fabio is different and why it seems interestring. </p><p>For example, if you’re using <code>Nginx</code> as your load balancer, you need to maintain a config file where the routing rules need to be defined as below </p><figure class="highlight nginx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">server</span> &#123;</span><br><span class="line">    <span class="section">location</span> / &#123;</span><br><span class="line">        <span class="attribute">root</span> /data/www;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="section">location</span> /images/ &#123;</span><br><span class="line">        <span class="attribute">root</span> /data;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>But Fabio is a zero-conf load balancer. Cool, right? Let’s review the design and code to uncover the secrets under the hood. </p><p><img src="/images/fabio.png" alt="load-balancing"></p><p>Simply speaking, Fabio’s design can be divided into two parts: <strong>Consul monitor</strong> and <strong>proxy</strong>. Consul monitor forms and updates a <code>route table</code> by watching the data stored in Consul, and proxy distributes the request to target service instance based on the <code>route table</code>.</p><h4 id="main-function"><a href="#main-function" class="headerlink" title="main function"></a>main function</h4><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">logOutput := logger.NewLevelWriter(os.Stderr, <span class="string">&quot;INFO&quot;</span>, <span class="string">&quot;2017/01/01 00:00:00 &quot;</span>)</span><br><span class="line">log.SetOutput(logOutput)</span><br><span class="line"></span><br><span class="line">cfg, err := config.Load(os.Args, os.Environ())</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">exit.Fatalf(<span class="string">&quot;[FATAL] %s. %s&quot;</span>, version, err)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> cfg == <span class="literal">nil</span> &#123;</span><br><span class="line">fmt.Println(version)</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">log.Printf(<span class="string">&quot;[INFO] Setting log level to %s&quot;</span>, logOutput.Level())</span><br><span class="line"><span class="keyword">if</span> !logOutput.SetLevel(cfg.Log.Level) &#123;</span><br><span class="line">log.Printf(<span class="string">&quot;[INFO] Cannot set log level to %s&quot;</span>, cfg.Log.Level)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">log.Printf(<span class="string">&quot;[INFO] Runtime config\n&quot;</span> + toJSON(cfg))</span><br><span class="line">log.Printf(<span class="string">&quot;[INFO] Version %s starting&quot;</span>, version)</span><br><span class="line">log.Printf(<span class="string">&quot;[INFO] Go runtime is %s&quot;</span>, runtime.Version())</span><br><span class="line"></span><br><span class="line">WarnIfRunAsRoot(cfg.Insecure)</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> prof <span class="keyword">interface</span> &#123;</span><br><span class="line">Stop()</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> cfg.ProfileMode != <span class="string">&quot;&quot;</span> &#123;</span><br><span class="line"><span class="keyword">var</span> mode <span class="function"><span class="keyword">func</span><span class="params">(*profile.Profile)</span></span></span><br><span class="line"><span class="keyword">switch</span> cfg.ProfileMode &#123;</span><br><span class="line"><span class="keyword">case</span> <span class="string">&quot;&quot;</span>:</span><br><span class="line"><span class="comment">// do nothing</span></span><br><span class="line"><span class="keyword">case</span> <span class="string">&quot;cpu&quot;</span>:</span><br><span class="line">mode = profile.CPUProfile</span><br><span class="line"><span class="keyword">case</span> <span class="string">&quot;mem&quot;</span>:</span><br><span class="line">mode = profile.MemProfile</span><br><span class="line"><span class="keyword">case</span> <span class="string">&quot;mutex&quot;</span>:</span><br><span class="line">mode = profile.MutexProfile</span><br><span class="line"><span class="keyword">case</span> <span class="string">&quot;block&quot;</span>:</span><br><span class="line">mode = profile.BlockProfile</span><br><span class="line"><span class="keyword">case</span> <span class="string">&quot;trace&quot;</span>:</span><br><span class="line">mode = profile.TraceProfile</span><br><span class="line"><span class="keyword">default</span>:</span><br><span class="line">log.Fatalf(<span class="string">&quot;[FATAL] Invalid profile mode %q&quot;</span>, cfg.ProfileMode)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">prof = profile.Start(mode, profile.ProfilePath(cfg.ProfilePath), profile.NoShutdownHook)</span><br><span class="line">log.Printf(<span class="string">&quot;[INFO] Profile mode %q&quot;</span>, cfg.ProfileMode)</span><br><span class="line">log.Printf(<span class="string">&quot;[INFO] Profile path %q&quot;</span>, cfg.ProfilePath)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">exit.Listen(<span class="function"><span class="keyword">func</span><span class="params">(s os.Signal)</span></span> &#123;</span><br><span class="line">atomic.StoreInt32(&amp;shuttingDown, <span class="number">1</span>)</span><br><span class="line">proxy.Shutdown(cfg.Proxy.ShutdownWait)</span><br><span class="line"><span class="keyword">if</span> prof != <span class="literal">nil</span> &#123;</span><br><span class="line">prof.Stop()</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> registry.Default == <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">&#125;</span><br><span class="line">registry.Default.DeregisterAll()</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">initMetrics(cfg)</span><br><span class="line">initRuntime(cfg)</span><br><span class="line">initBackend(cfg)</span><br><span class="line"></span><br><span class="line">trace.InitializeTracer(&amp;cfg.Tracing)</span><br><span class="line"></span><br><span class="line">startAdmin(cfg)</span><br><span class="line"></span><br><span class="line"><span class="keyword">go</span> watchNoRouteHTML(cfg)</span><br><span class="line"></span><br><span class="line">first := <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="type">bool</span>)</span><br><span class="line"><span class="keyword">go</span> watchBackend(cfg, first)</span><br><span class="line">log.Print(<span class="string">&quot;[INFO] Waiting for first routing table&quot;</span>)</span><br><span class="line">&lt;-first</span><br><span class="line"></span><br><span class="line">startServers(cfg)</span><br><span class="line"></span><br><span class="line">WarnIfRunAsRoot(cfg.Insecure)</span><br><span class="line"></span><br><span class="line">exit.Wait()</span><br><span class="line">log.Print(<span class="string">&quot;[INFO] Down&quot;</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>The <code>main</code> function defines Fabio’s workflow. To understand how Fabio works, we only need to focus on three points: </p><ul><li><strong>initBackend()</strong> and <strong>watchBackend()</strong>: these two functions contain Consul monitoring logic. </li><li><strong>startServers()</strong>: this function is responsible to create the network proxy.</li></ul><h4 id="Consul-monitoring"><a href="#Consul-monitoring" class="headerlink" title="Consul monitoring"></a>Consul monitoring</h4><p>First, let’s review the <code>initBackend</code> function: </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">initBackend</span><span class="params">(cfg *config.Config)</span></span> &#123;</span><br><span class="line"><span class="keyword">var</span> deadline = time.Now().Add(cfg.Registry.Timeout)</span><br><span class="line"><span class="keyword">var</span> err <span class="type">error</span></span><br><span class="line"><span class="keyword">for</span> &#123;</span><br><span class="line"><span class="keyword">switch</span> cfg.Registry.Backend &#123;</span><br><span class="line"><span class="keyword">case</span> <span class="string">&quot;file&quot;</span>:</span><br><span class="line">registry.Default, err = file.NewBackend(&amp;cfg.Registry.File)</span><br><span class="line"><span class="keyword">case</span> <span class="string">&quot;static&quot;</span>:</span><br><span class="line">registry.Default, err = static.NewBackend(&amp;cfg.Registry.Static)</span><br><span class="line"><span class="keyword">case</span> <span class="string">&quot;consul&quot;</span>:</span><br><span class="line">registry.Default, err = consul.NewBackend(&amp;cfg.Registry.Consul)</span><br><span class="line"><span class="keyword">case</span> <span class="string">&quot;custom&quot;</span>:</span><br><span class="line">registry.Default, err = custom.NewBackend(&amp;cfg.Registry.Custom)</span><br><span class="line"><span class="keyword">default</span>:</span><br><span class="line">exit.Fatal(<span class="string">&quot;[FATAL] Unknown registry backend &quot;</span>, cfg.Registry.Backend)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> err == <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">if</span> err = registry.Default.Register(<span class="literal">nil</span>); err == <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">log.Print(<span class="string">&quot;[WARN] Error initializing backend. &quot;</span>, err)</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> time.Now().After(deadline) &#123;</span><br><span class="line">exit.Fatal(<span class="string">&quot;[FATAL] Timeout registering backend.&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">time.Sleep(cfg.Registry.Retry)</span><br><span class="line"><span class="keyword">if</span> atomic.LoadInt32(&amp;shuttingDown) &gt; <span class="number">0</span> &#123;</span><br><span class="line">exit.Exit(<span class="number">1</span>)</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>This function is not hard to understand. Fabio supports various modes: <code>file</code>, <code>static</code>, <code>consul</code> and <code>custom</code>, and will select one mode to use based on the detailed condition inside the <code>cfg</code> parameter. In our case, we only need to focus on the <code>consul</code> mode. </p><p>Next let’s review <code>watchBackend()</code> function to check how it keeps watching consul’s data.</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">watchBackend</span><span class="params">(cfg *config.Config, first <span class="keyword">chan</span> <span class="type">bool</span>)</span></span> &#123;</span><br><span class="line"><span class="keyword">var</span> (</span><br><span class="line">nextTable   <span class="type">string</span></span><br><span class="line">lastTable   <span class="type">string</span></span><br><span class="line">svccfg      <span class="type">string</span></span><br><span class="line">mancfg      <span class="type">string</span></span><br><span class="line">customBE    <span class="type">string</span></span><br><span class="line">once        sync.Once</span><br><span class="line">tableBuffer = <span class="built_in">new</span>(bytes.Buffer) <span class="comment">// fix crash on reset before used (#650)</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="keyword">switch</span> cfg.Registry.Backend &#123;</span><br><span class="line"><span class="keyword">case</span> <span class="string">&quot;custom&quot;</span>:</span><br><span class="line">svc := registry.Default.WatchServices()</span><br><span class="line"><span class="keyword">for</span> &#123;</span><br><span class="line">customBE = &lt;-svc</span><br><span class="line"><span class="keyword">if</span> customBE != <span class="string">&quot;OK&quot;</span> &#123;</span><br><span class="line">log.Printf(<span class="string">&quot;[ERROR] error during update from custom back end - %s&quot;</span>, customBE)</span><br><span class="line">&#125;</span><br><span class="line">once.Do(<span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123; <span class="built_in">close</span>(first) &#125;)</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// all other backend types</span></span><br><span class="line"><span class="keyword">default</span>:</span><br><span class="line">svc := registry.Default.WatchServices()</span><br><span class="line">man := registry.Default.WatchManual()</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> &#123;</span><br><span class="line"><span class="keyword">select</span> &#123;</span><br><span class="line"><span class="keyword">case</span> svccfg = &lt;-svc:</span><br><span class="line"><span class="keyword">case</span> mancfg = &lt;-man:</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// manual config overrides service config - order matters</span></span><br><span class="line">tableBuffer.Reset()</span><br><span class="line">tableBuffer.WriteString(svccfg)</span><br><span class="line">tableBuffer.WriteString(<span class="string">&quot;\n&quot;</span>)</span><br><span class="line">tableBuffer.WriteString(mancfg)</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> nextTable = tableBuffer.String(); nextTable == lastTable &#123;</span><br><span class="line"><span class="keyword">continue</span></span><br><span class="line">&#125;</span><br><span class="line">aliases, err := route.ParseAliases(nextTable)</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">log.Printf(<span class="string">&quot;[WARN]: %s&quot;</span>, err)</span><br><span class="line">&#125;</span><br><span class="line">registry.Default.Register(aliases)</span><br><span class="line">t, err := route.NewTable(tableBuffer)</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">log.Printf(<span class="string">&quot;[WARN] %s&quot;</span>, err)</span><br><span class="line"><span class="keyword">continue</span></span><br><span class="line">&#125;</span><br><span class="line">route.SetTable(t)</span><br><span class="line">logRoutes(t, lastTable, nextTable, cfg.Log.RoutesFormat)</span><br><span class="line">lastTable = nextTable</span><br><span class="line">once.Do(<span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123; <span class="built_in">close</span>(first) &#125;)</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Firstly in line 24, we need to understand <code>registry.Default.WatchServices()</code>. Since <code>initBackend</code> function already decided we’re using Consul mode, so we need to check the <code>WatchServices()</code> function inside the <code>Consul</code> package as following:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> consul</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(b *be)</span></span> WatchServices() <span class="keyword">chan</span> <span class="type">string</span> &#123;</span><br><span class="line">log.Printf(<span class="string">&quot;[INFO] consul: Using dynamic routes&quot;</span>)</span><br><span class="line">log.Printf(<span class="string">&quot;[INFO] consul: Using tag prefix %q&quot;</span>, b.cfg.TagPrefix)</span><br><span class="line"></span><br><span class="line">m := NewServiceMonitor(b.c, b.cfg, b.dc)</span><br><span class="line">svc := <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="type">string</span>)</span><br><span class="line"><span class="keyword">go</span> m.Watch(svc)</span><br><span class="line"><span class="keyword">return</span> svc</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>The return value is <code>svc</code> which is just a string typed <code>channel</code>. And <code>svc</code> channel is passed into goroutine <code>go m.watch()</code> as an argument. This is a very typical usage in Golang programming where two goroutines need to communicate with each other via the channel. Let’s go on and check the <code>Watch</code> function:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(w *ServiceMonitor)</span></span> Watch(updates <span class="keyword">chan</span> <span class="type">string</span>) &#123;</span><br><span class="line"><span class="keyword">var</span> lastIndex <span class="type">uint64</span></span><br><span class="line"><span class="keyword">var</span> q *api.QueryOptions</span><br><span class="line"><span class="keyword">for</span> &#123;</span><br><span class="line"><span class="keyword">if</span> w.config.PollInterval != <span class="number">0</span> &#123;</span><br><span class="line">q = &amp;api.QueryOptions&#123;RequireConsistent: <span class="literal">true</span>&#125;</span><br><span class="line">time.Sleep(w.config.PollInterval)</span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">q = &amp;api.QueryOptions&#123;RequireConsistent: <span class="literal">true</span>, WaitIndex: lastIndex&#125;</span><br><span class="line">&#125;</span><br><span class="line">checks, meta, err := w.client.Health().State(<span class="string">&quot;any&quot;</span>, q)</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">log.Printf(<span class="string">&quot;[WARN] consul: Error fetching health state. %v&quot;</span>, err)</span><br><span class="line">time.Sleep(time.Second)</span><br><span class="line"><span class="keyword">continue</span></span><br><span class="line">&#125;</span><br><span class="line">log.Printf(<span class="string">&quot;[DEBUG] consul: Health changed to #%d&quot;</span>, meta.LastIndex)</span><br><span class="line"><span class="comment">// determine which services have passing health checks</span></span><br><span class="line">passing := passingServices(checks, w.config.ServiceStatus, w.strict)</span><br><span class="line"><span class="comment">// build the config for the passing services</span></span><br><span class="line">updates &lt;- w.makeConfig(passing)</span><br><span class="line"><span class="comment">// remember the last state and wait for the next change</span></span><br><span class="line">lastIndex = meta.LastIndex</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>You can see <code>updates &lt;- w.makeConfig(passing)</code> in Line 21, it just sends a message into the channel.  </p><p>Another interestring point is <code>w.client.Health().State(&quot;any&quot;, q)</code> in line 11. This is one API provided in the <code>consul/api</code> package. If you check the implementation of it, you’ll find out in fact it just sends a HTTP get request to this endpoint <code>/v1/health/state/</code> of Consul service which will return all the health check status for the services registered in Consul. </p><p>And the above logic runs inside a <code>for</code> loop, in this way Fabio keeps sending request to query the latest status from Consul. If new services are discovered, then the status will be updated dynamically as well, no need to restart Fabio. </p><p>So far you should understand how Fabio can work as a load balancer with any hardcoded routing config.  </p><p>Let’s go back to the <code>watchBackend</code> function to continue the analysis. </p><p>After debugging, I find the message passed via the <code>svc</code> channel follows the following format:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[route add demo-service /helloworld http://127.0.0.1:5000/ route add demo-service /foo http://127.0.0.1:5000/]</span><br></pre></td></tr></table></figure><p>Next step is converting this string message into the route table. </p><p>In line 46 and 51 of <code>watchBackend</code> function, you can find these two lines of code:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">t, err := route.NewTable(tableBuffer) <span class="comment">// line 46</span></span><br><span class="line"></span><br><span class="line">...</span><br><span class="line"></span><br><span class="line">route.SetTable(t) <span class="comment">// line 51</span></span><br></pre></td></tr></table></figure><p>Everything will be clear after you check the implementation of the <code>route</code> package. </p><p><code>route.NewTable()</code> function returns a <code>Table</code> type value which is map in fact. And the <code>Table</code> type declaration goes as following: </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Table contains a set of routes grouped by host.</span></span><br><span class="line"><span class="comment">// The host routes are sorted from most to least specific</span></span><br><span class="line"><span class="comment">// by sorting the routes in reverse order by path.</span></span><br><span class="line"><span class="keyword">type</span> Table <span class="keyword">map</span>[<span class="type">string</span>]Routes</span><br><span class="line"></span><br><span class="line"><span class="comment">// Routes stores a list of routes usually for a single host.</span></span><br><span class="line"><span class="keyword">type</span> Routes []*Route</span><br><span class="line"></span><br><span class="line"><span class="comment">// Route maps a path prefix to one or more target URLs.</span></span><br><span class="line"><span class="comment">// routes can have a weight value which describes the</span></span><br><span class="line"><span class="comment">// amount of traffic this route should get. You can specify</span></span><br><span class="line"><span class="comment">// that a route should get a fixed percentage of the traffic</span></span><br><span class="line"><span class="comment">// independent of how many instances are running.</span></span><br><span class="line"><span class="keyword">type</span> Route <span class="keyword">struct</span> &#123;</span><br><span class="line"><span class="comment">// Host contains the host of the route.</span></span><br><span class="line"><span class="comment">// not used for routing but for config generation</span></span><br><span class="line"><span class="comment">// Table has a map with the host as key</span></span><br><span class="line"><span class="comment">// for faster lookup and smaller search space.</span></span><br><span class="line">Host <span class="type">string</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// Path is the path prefix from a request uri</span></span><br><span class="line">Path <span class="type">string</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// Targets contains the list of URLs</span></span><br><span class="line">Targets []*Target</span><br><span class="line"></span><br><span class="line"><span class="comment">// wTargets contains targets distributed according to their weight</span></span><br><span class="line">wTargets []*Target</span><br><span class="line"></span><br><span class="line"><span class="comment">// total contains the total number of requests for this route.</span></span><br><span class="line"><span class="comment">// Used by the RRPicker</span></span><br><span class="line">total <span class="type">uint64</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// Glob represents compiled pattern.</span></span><br><span class="line">Glob glob.Glob</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>That’s all for the consul monitor part. Simply speaking, Fabio keeps looping the latest service status from Consul and process the status information into a routing table. </p><h4 id="Proxy"><a href="#Proxy" class="headerlink" title="Proxy"></a>Proxy</h4><p>The second part is about network proxy, which is easier to understand than the first part. </p><p>Fabio supports various network protocols, but in this post let’s focus on <code>HTTP/HTTPS</code> case. In side the <code>main.go</code> file, you can find the following function:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">newHTTPProxy</span><span class="params">(cfg *config.Config)</span></span> http.Handler &#123;</span><br><span class="line"><span class="keyword">var</span> w io.Writer</span><br><span class="line"></span><br><span class="line"><span class="comment">//Init Glob Cache</span></span><br><span class="line">globCache := route.NewGlobCache(cfg.GlobCacheSize)</span><br><span class="line"></span><br><span class="line"><span class="keyword">switch</span> cfg.Log.AccessTarget &#123;</span><br><span class="line"><span class="keyword">case</span> <span class="string">&quot;&quot;</span>:</span><br><span class="line">log.Printf(<span class="string">&quot;[INFO] Access logging disabled&quot;</span>)</span><br><span class="line"><span class="keyword">case</span> <span class="string">&quot;stdout&quot;</span>:</span><br><span class="line">log.Printf(<span class="string">&quot;[INFO] Writing access log to stdout&quot;</span>)</span><br><span class="line">w = os.Stdout</span><br><span class="line"><span class="keyword">default</span>:</span><br><span class="line">exit.Fatal(<span class="string">&quot;[FATAL] Invalid access log target &quot;</span>, cfg.Log.AccessTarget)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">format := cfg.Log.AccessFormat</span><br><span class="line"><span class="keyword">switch</span> format &#123;</span><br><span class="line"><span class="keyword">case</span> <span class="string">&quot;common&quot;</span>:</span><br><span class="line">format = logger.CommonFormat</span><br><span class="line"><span class="keyword">case</span> <span class="string">&quot;combined&quot;</span>:</span><br><span class="line">format = logger.CombinedFormat</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">l, err := logger.New(w, format)</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">exit.Fatal(<span class="string">&quot;[FATAL] Invalid log format: &quot;</span>, err)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">pick := route.Picker[cfg.Proxy.Strategy]</span><br><span class="line">match := route.Matcher[cfg.Proxy.Matcher]</span><br><span class="line">notFound := metrics.DefaultRegistry.GetCounter(<span class="string">&quot;notfound&quot;</span>)</span><br><span class="line">log.Printf(<span class="string">&quot;[INFO] Using routing strategy %q&quot;</span>, cfg.Proxy.Strategy)</span><br><span class="line">log.Printf(<span class="string">&quot;[INFO] Using route matching %q&quot;</span>, cfg.Proxy.Matcher)</span><br><span class="line"></span><br><span class="line">newTransport := <span class="function"><span class="keyword">func</span><span class="params">(tlscfg *tls.Config)</span></span> *http.Transport &#123;</span><br><span class="line"><span class="keyword">return</span> &amp;http.Transport&#123;</span><br><span class="line">ResponseHeaderTimeout: cfg.Proxy.ResponseHeaderTimeout,</span><br><span class="line">MaxIdleConnsPerHost:   cfg.Proxy.MaxConn,</span><br><span class="line">Dial: (&amp;net.Dialer&#123;</span><br><span class="line">Timeout:   cfg.Proxy.DialTimeout,</span><br><span class="line">KeepAlive: cfg.Proxy.KeepAliveTimeout,</span><br><span class="line">&#125;).Dial,</span><br><span class="line">TLSClientConfig: tlscfg,</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">authSchemes, err := auth.LoadAuthSchemes(cfg.Proxy.AuthSchemes)</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">exit.Fatal(<span class="string">&quot;[FATAL] &quot;</span>, err)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> &amp;proxy.HTTPProxy&#123;</span><br><span class="line">Config:            cfg.Proxy,</span><br><span class="line">Transport:         newTransport(<span class="literal">nil</span>),</span><br><span class="line">InsecureTransport: newTransport(&amp;tls.Config&#123;InsecureSkipVerify: <span class="literal">true</span>&#125;),</span><br><span class="line">Lookup: <span class="function"><span class="keyword">func</span><span class="params">(r *http.Request)</span></span> *route.Target &#123;</span><br><span class="line">t := route.GetTable().Lookup(r, r.Header.Get(<span class="string">&quot;trace&quot;</span>), pick, match, globCache, cfg.GlobMatchingDisabled)</span><br><span class="line"><span class="keyword">if</span> t == <span class="literal">nil</span> &#123;</span><br><span class="line">notFound.Inc(<span class="number">1</span>)</span><br><span class="line">log.Print(<span class="string">&quot;[WARN] No route for &quot;</span>, r.Host, r.URL)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> t</span><br><span class="line">&#125;,</span><br><span class="line">Requests:    metrics.DefaultRegistry.GetTimer(<span class="string">&quot;requests&quot;</span>),</span><br><span class="line">Noroute:     metrics.DefaultRegistry.GetCounter(<span class="string">&quot;notfound&quot;</span>),</span><br><span class="line">Logger:      l,</span><br><span class="line">TracerCfg:   cfg.Tracing,</span><br><span class="line">AuthSchemes: authSchemes,</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>The return value’s type is <code>http.Handler</code>, which is an <strong>interface</strong> defined inside Go standard library as following:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> Handler <span class="keyword">interface</span> &#123;</span><br><span class="line">ServeHTTP(ResponseWriter, *Request)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>And the actual return value’s type is <code>proxy.HTTPProxy</code> which is a <code>struct</code> implementing the <code>ServeHTTP</code> method. You can find the code inside the <code>proxy</code> package in Fabio repo. </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> HTTPProxy <span class="keyword">struct</span> &#123;</span><br><span class="line">...</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(p *HTTPProxy)</span></span> ServeHTTP(w http.ResponseWriter, r *http.Request) &#123;</span><br><span class="line">...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Another point needs to be mentioned is <code>Lookup</code> field of <code>HTTPProxy</code> struct:</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">Lookup: <span class="function"><span class="keyword">func</span><span class="params">(r *http.Request)</span></span> *route.Target &#123;</span><br><span class="line">t := route.GetTable().Lookup(r, r.Header.Get(<span class="string">&quot;trace&quot;</span>), pick, match, globCache, cfg.GlobMatchingDisabled)</span><br><span class="line"><span class="keyword">if</span> t == <span class="literal">nil</span> &#123;</span><br><span class="line">notFound.Inc(<span class="number">1</span>)</span><br><span class="line">log.Print(<span class="string">&quot;[WARN] No route for &quot;</span>, r.Host, r.URL)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> t</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>You don’t need to understand the details, just pay attention to <code>route.GetTable()</code> which is the routing table mentioned above. Consul monitor maintains the table and proxy consumes the table. That’s it.</p><p>In this article which is part one of this blog series , you learned how Fabio can serve as a load balancer without any config files by reviewing the design and reading the source code. </p><p>In part two, let’s review how Golang was used and try to summarize the best practise of wrting Golang programs.</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;Background&quot;&gt;&lt;a href=&quot;#Background&quot; class=&quot;headerlink&quot; title=&quot;Background&quot;&gt;&lt;/a&gt;Background&lt;/h3&gt;&lt;p&gt;In this two-part blog series, I want t</summary>
      
    
    
    
    
    <category term="Fabio, Golang, Source code" scheme="https://baoqger.github.io/tags/Fabio-Golang-Source-code/"/>
    
  </entry>
  
  <entry>
    <title>Load balancing in Golang Cloud-Native microservice with Consul and Fabio</title>
    <link href="https://baoqger.github.io/2020/12/30/golang-load-balancing-fabio/"/>
    <id>https://baoqger.github.io/2020/12/30/golang-load-balancing-fabio/</id>
    <published>2020-12-30T01:56:57.000Z</published>
    <updated>2021-12-23T12:34:34.793Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Background"><a href="#Background" class="headerlink" title="Background"></a>Background</h3><p>In the <a href="https://baoqger.github.io/2020/11/16/golang-service-discovery-consul/">last post</a>, I show you how to do service discovery in a Golang Cloud-Native microservice application based on Consul and Docker with a real demo. In that demo, the simple <code>helloworld-server</code> service is registered in Consul and the <code>helloworld-client</code> can discover the dynamic address of the service via Consul. But the previous demo has one limitation, as I mentioned in the last post, in the real world microservice application, each service may have multiple instances to handle the network requests. </p><p>In this post, I will expand the demo to show you how to do <code>load balancing</code> when multiple instances of one service are registered in Consul. </p><p>Continue with the last post, the new demo will keep using Cloud-Native way with <code>Docker</code> and <code>Docker-compose</code>.</p><h3 id="Fabio-for-load-balancing"><a href="#Fabio-for-load-balancing" class="headerlink" title="Fabio for load balancing"></a>Fabio for load balancing</h3><p>To do load balancing for Consul, there are several strategies are recommended from the Consul official document. In this post I choose to use <a href="https://github.com/fabiolb/fabio">Fabio</a>. </p><blockquote><p>Fabio is an open source tool that provides fast, modern, zero-conf load balancing HTTP(S) and TCP router for services managed by Consul. Users register services in Consul with a health check and fabio will automatically route traffic to them. No additional configuration required.</p></blockquote><p>Fabio is an interesting project, it realizes loading balancing based on the <code>tag</code> information of service registration in Consul. </p><p>Users register a service with a tag beginning with <code>urlprefix-</code>, like:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">urlprefix-/my-service</span><br></pre></td></tr></table></figure><p>Then when a request is made to fabio at <code>/my-service</code>, fabio will automatically route traffic to a healthy service in the cluster. I will show you how to do it in the following demo. And I will also do simple research on how Fabio realizes this load balancing strategy by reviewing the source code and share the findings in the next post. </p><h3 id="Fabio-load-balancing-demo"><a href="#Fabio-load-balancing-demo" class="headerlink" title="Fabio load balancing demo"></a>Fabio load balancing demo</h3><p>Firstly, all the code and config files shown in this post can be found in this <a href="https://github.com/baoqger/service-discovery-demo">github repo</a>, please <code>git checkout</code> the <code>load-balancing</code> branch for this post’s demo. </p><h4 id="Server-side"><a href="#Server-side" class="headerlink" title="Server side"></a>Server side</h4><p>For the <code>helloworld-server</code>, there are two changes:</p><ul><li>First, each service instance should have an unique <code>ID</code>;</li><li>Second, add <code>Tags</code> for service registration and the tag should follow the rule of <code>Fabio</code>. </li></ul><p>Ok, let’s check the new version code. </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line"><span class="string">&quot;fmt&quot;</span></span><br><span class="line"><span class="string">&quot;log&quot;</span></span><br><span class="line"><span class="string">&quot;net/http&quot;</span></span><br><span class="line"><span class="string">&quot;os&quot;</span></span><br><span class="line"><span class="string">&quot;strconv&quot;</span></span><br><span class="line"></span><br><span class="line">consulapi <span class="string">&quot;github.com/hashicorp/consul/api&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">serviceRegistryWithConsul()</span><br><span class="line">log.Println(<span class="string">&quot;Starting Hello World Server...&quot;</span>)</span><br><span class="line">http.HandleFunc(<span class="string">&quot;/helloworld&quot;</span>, helloworld)</span><br><span class="line">http.HandleFunc(<span class="string">&quot;/check&quot;</span>, check)</span><br><span class="line">http.ListenAndServe(getPort(), <span class="literal">nil</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">serviceRegistryWithConsul</span><span class="params">()</span></span> &#123;</span><br><span class="line">config := consulapi.DefaultConfig()</span><br><span class="line">consul, err := consulapi.NewClient(config)</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">log.Println(err)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">port, _ := strconv.Atoi(getPort()[<span class="number">1</span>:<span class="built_in">len</span>(getPort())])</span><br><span class="line">address := getHostname()</span><br><span class="line"><span class="comment">/* Each service instance should have an unique serviceID */</span></span><br><span class="line">serviceID := fmt.Sprintf(<span class="string">&quot;helloworld-server-%s:%v&quot;</span>, address, port)</span><br><span class="line"><span class="comment">/* Tag should follow the rule of Fabio: urlprefix- */</span></span><br><span class="line">tags := []<span class="type">string</span>&#123;<span class="string">&quot;urlprefix-/helloworld&quot;</span>&#125;</span><br><span class="line"></span><br><span class="line">registration := &amp;consulapi.AgentServiceRegistration&#123;</span><br><span class="line">ID:      serviceID,</span><br><span class="line">Name:    <span class="string">&quot;helloworld-server&quot;</span>,</span><br><span class="line">Port:    port,</span><br><span class="line">Address: address,</span><br><span class="line">Tags:    tags, <span class="comment">/* Add Tags for registration */</span></span><br><span class="line">Check: &amp;consulapi.AgentServiceCheck&#123;</span><br><span class="line">HTTP:     fmt.Sprintf(<span class="string">&quot;http://%s:%v/check&quot;</span>, address, port),</span><br><span class="line">Interval: <span class="string">&quot;10s&quot;</span>,</span><br><span class="line">Timeout:  <span class="string">&quot;30s&quot;</span>,</span><br><span class="line">&#125;,</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">regiErr := consul.Agent().ServiceRegister(registration)</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> regiErr != <span class="literal">nil</span> &#123;</span><br><span class="line">log.Printf(<span class="string">&quot;Failed to register service: %s:%v &quot;</span>, address, port)</span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">log.Printf(<span class="string">&quot;successfully register service: %s:%v&quot;</span>, address, port)</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">helloworld</span><span class="params">(w http.ResponseWriter, r *http.Request)</span></span> &#123;</span><br><span class="line">log.Println(<span class="string">&quot;helloworld service is called.&quot;</span>)</span><br><span class="line">w.WriteHeader(http.StatusOK)</span><br><span class="line">fmt.Fprintf(w, <span class="string">&quot;Hello world.&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">check</span><span class="params">(w http.ResponseWriter, r *http.Request)</span></span> &#123;</span><br><span class="line">w.WriteHeader(http.StatusOK)</span><br><span class="line">fmt.Fprintf(w, <span class="string">&quot;Consul check&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">getPort</span><span class="params">()</span></span> (port <span class="type">string</span>) &#123;</span><br><span class="line">port = os.Getenv(<span class="string">&quot;PORT&quot;</span>)</span><br><span class="line"><span class="keyword">if</span> <span class="built_in">len</span>(port) == <span class="number">0</span> &#123;</span><br><span class="line">port = <span class="string">&quot;8080&quot;</span></span><br><span class="line">&#125;</span><br><span class="line">port = <span class="string">&quot;:&quot;</span> + port</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">getHostname</span><span class="params">()</span></span> (hostname <span class="type">string</span>) &#123;</span><br><span class="line">hostname, _ = os.Hostname()</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h5 id="server-go"><a href="#server-go" class="headerlink" title="server.go"></a><strong><code>server.go</code></strong></h5><p>The changes are at Line 30, 32 and 40 and comments are added there to explain the purpose of the change. Simply speaking, now each service instance registers itself with a unique ID, which is consisted of the basic service name (helloworld-server in this case) and the dynamic address. Also, we add <code>urlprefix-/helloworld</code> <strong>Tags</strong> for each registration. <code>urlprefix-</code> is the default config of Fabio, you can set customized prefix if needed. Based on this <strong>Tags</strong>, Fabio can do automatic load balancing for the <code>/helloworld</code> endpoint. </p><p>That’s all for the code change for server side. Let’s review the changes for the client. </p><h4 id="Client-side"><a href="#Client-side" class="headerlink" title="Client side"></a>Client side</h4><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line"><span class="string">&quot;fmt&quot;</span></span><br><span class="line"><span class="string">&quot;io/ioutil&quot;</span></span><br><span class="line"><span class="string">&quot;net/http&quot;</span></span><br><span class="line"><span class="string">&quot;os&quot;</span></span><br><span class="line"><span class="string">&quot;time&quot;</span></span><br><span class="line"></span><br><span class="line">consulapi <span class="string">&quot;github.com/hashicorp/consul/api&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> url <span class="type">string</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">For load balancing, run fabioLoadBalancing();</span></span><br><span class="line"><span class="comment">For simple service discovery, run serviceDiscoveryWithConsul();</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">fabioLoadBalancing()</span><br><span class="line">fmt.Println(<span class="string">&quot;Starting Client.&quot;</span>)</span><br><span class="line"><span class="keyword">var</span> client = &amp;http.Client&#123;</span><br><span class="line">Timeout: time.Second * <span class="number">30</span>,</span><br><span class="line">&#125;</span><br><span class="line">callServerEvery(<span class="number">10</span>*time.Second, client)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* Load balancing with Fabio */</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">fabioLoadBalancing</span><span class="params">()</span></span> &#123;</span><br><span class="line">address := os.Getenv(<span class="string">&quot;FABIO_HTTP_ADDR&quot;</span>)</span><br><span class="line">url = fmt.Sprintf(<span class="string">&quot;http://%s/helloworld&quot;</span>, address)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* Service Discovery with Consul */</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">serviceDiscoveryWithConsul</span><span class="params">()</span></span> &#123;</span><br><span class="line">config := consulapi.DefaultConfig()</span><br><span class="line">consul, <span class="type">error</span> := consulapi.NewClient(config)</span><br><span class="line"><span class="keyword">if</span> <span class="type">error</span> != <span class="literal">nil</span> &#123;</span><br><span class="line">fmt.Println(<span class="type">error</span>)</span><br><span class="line">&#125;</span><br><span class="line">services, <span class="type">error</span> := consul.Agent().Services()</span><br><span class="line"><span class="keyword">if</span> <span class="type">error</span> != <span class="literal">nil</span> &#123;</span><br><span class="line">fmt.Println(<span class="type">error</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">service := services[<span class="string">&quot;helloworld-server&quot;</span>]</span><br><span class="line">address := service.Address</span><br><span class="line">port := service.Port</span><br><span class="line">url = fmt.Sprintf(<span class="string">&quot;http://%s:%v/helloworld&quot;</span>, address, port)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">hello</span><span class="params">(t time.Time, client *http.Client)</span></span> &#123;</span><br><span class="line">response, err := client.Get(url)</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">fmt.Println(err)</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">&#125;</span><br><span class="line">body, _ := ioutil.ReadAll(response.Body)</span><br><span class="line">fmt.Printf(<span class="string">&quot;%s. Time is %v\n&quot;</span>, body, t)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">callServerEvery</span><span class="params">(d time.Duration, client *http.Client)</span></span> &#123;</span><br><span class="line"><span class="keyword">for</span> x := <span class="keyword">range</span> time.Tick(d) &#123;</span><br><span class="line">hello(x, client)</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h5 id="client-go"><a href="#client-go" class="headerlink" title="client.go"></a><strong><code>client.go</code></strong></h5><p>Previously, we need to run <code>serviceDiscoveryWithConsul</code> to discover the service address to call. Now since we have <code>Fabio</code> working as the load balancer, so we send the request to <code>Fabio</code> and our request will be distributed to the service instance by <code>Fabio</code>.</p><p>This part of logic is implemented inside the following method: </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Load balancing with Fabio */</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">fabioLoadBalancing</span><span class="params">()</span></span> &#123;</span><br><span class="line">address := os.Getenv(<span class="string">&quot;FABIO_HTTP_ADDR&quot;</span>)</span><br><span class="line">url = fmt.Sprintf(<span class="string">&quot;http://%s/helloworld&quot;</span>, address)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>To get the address of the Fabio service, we need to config it as an environment variable, which will be set in the <code>yml</code> file of Docker-compose. Let’s review the new <code>yml</code> file now. </p><h4 id="Docker-compose-config"><a href="#Docker-compose-config" class="headerlink" title="Docker-compose config"></a>Docker-compose config</h4><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">version:</span> <span class="string">&#x27;2&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="attr">services:</span> </span><br><span class="line">  <span class="attr">consul:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">consul:0.8.3</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;8500:8500&quot;</span></span><br><span class="line">    <span class="attr">networks:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">my-net</span></span><br><span class="line">      </span><br><span class="line">  <span class="attr">helloworld-server:</span></span><br><span class="line">    <span class="attr">build:</span></span><br><span class="line">      <span class="attr">context:</span> <span class="string">.</span></span><br><span class="line">      <span class="attr">dockerfile:</span> <span class="string">server/Dockerfile</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">helloworld-server:1.0.2</span> <span class="comment"># upgrade to v1.0.2</span></span><br><span class="line">    <span class="attr">environment:</span> </span><br><span class="line">      <span class="bullet">-</span> <span class="string">CONSUL_HTTP_ADDR=consul:8500</span></span><br><span class="line">    <span class="attr">depends_on:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">consul</span></span><br><span class="line">    <span class="attr">networks:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">my-net</span></span><br><span class="line"></span><br><span class="line">  <span class="attr">helloworld-client:</span></span><br><span class="line">    <span class="attr">build:</span></span><br><span class="line">      <span class="attr">context:</span> <span class="string">.</span></span><br><span class="line">      <span class="attr">dockerfile:</span> <span class="string">client/Dockerfile</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">helloworld-client:1.0.2</span> <span class="comment"># upgrade to v1.0.2</span></span><br><span class="line">    <span class="attr">environment:</span> </span><br><span class="line">      <span class="bullet">-</span> <span class="string">CONSUL_HTTP_ADDR=consul:8500</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">FABIO_HTTP_ADDR=fabio:9999</span> <span class="comment"># environment variable for fabio service address</span></span><br><span class="line">    <span class="attr">depends_on:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">consul</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">helloworld-server</span></span><br><span class="line">    <span class="attr">networks:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">my-net</span></span><br><span class="line"></span><br><span class="line">  <span class="attr">fabio:</span> <span class="comment"># add a new service: Fabio as load balancer</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">fabiolb/fabio:latest</span></span><br><span class="line">    <span class="attr">environment:</span> </span><br><span class="line">      <span class="bullet">-</span> <span class="string">registry_consul_addr=consul:8500</span> <span class="comment"># environment variable for consul service address</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">proxy_strategy=rr</span> <span class="comment"># environment variable for load balancing strategy. rr is round-robin      </span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;9998:9998&quot;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;9999:9999&quot;</span></span><br><span class="line">    <span class="attr">depends_on:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">consul</span>  </span><br><span class="line">    <span class="attr">networks:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">my-net</span> </span><br><span class="line"></span><br><span class="line"><span class="attr">networks:</span></span><br><span class="line">  <span class="attr">my-net:</span></span><br><span class="line">    <span class="attr">driver:</span> <span class="string">bridge</span></span><br></pre></td></tr></table></figure><h5 id="docker-compose-yml"><a href="#docker-compose-yml" class="headerlink" title="docker-compose.yml"></a><strong><code>docker-compose.yml</code></strong></h5><p>There several changes in this <code>yml</code> config file:</p><ul><li>Add a new service <code>Fabio</code>. As mentioned above Fabio is a zero-conf load balancing, which can simply run as a docker container. This is so convenient and totally matches Cloud-Native style. The two environment variables: <code>registry_consul_addr</code> and <code>proxy_strategy</code>, are set to define the Consul’s address and the round-robin strategy. </li><li>Set the <code>FABIO_HTTP_ADDR</code> environment variable for the client. This is what we mentioned in the last section, which allows <code>client.go</code> to get Fabio service address and send requests. </li><li>Upgrade two docker images to <strong>v1.0.2</strong>.  </li></ul><h4 id="Demo"><a href="#Demo" class="headerlink" title="Demo"></a>Demo</h4><p>It’s time to run the demo! Suppose you have all the docker images build on your local machine, then run the following command: </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker-compose up --scale helloworld-server=3</span><br></pre></td></tr></table></figure><p>This command has an important tip about Docker-compose: how to run multiple instances of certain service. In our case, we need multiple instances of <code>helloworld-server</code> for load balancing. Docker-compose supports this functionality with <code>--scale</code> option. For the above command, 3 instances of helloworld-server will be launched.</p><p>You can see the demo’s result in the following image: </p><p><img src="/images/load-balancing.png" alt="load-balancing"></p><p>The client repeatedly and periodically sends the request and each request is distributed by Fabio to one of the three instances in round-robin style. Just what we expect! </p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;Background&quot;&gt;&lt;a href=&quot;#Background&quot; class=&quot;headerlink&quot; title=&quot;Background&quot;&gt;&lt;/a&gt;Background&lt;/h3&gt;&lt;p&gt;In the &lt;a href=&quot;https://baoqger.github</summary>
      
    
    
    
    
    <category term="microservice, Load balancing, Consul, Fabio Golang, Cloud-Native, Docker" scheme="https://baoqger.github.io/tags/microservice-Load-balancing-Consul-Fabio-Golang-Cloud-Native-Docker/"/>
    
  </entry>
  
  <entry>
    <title>svg-data-vis</title>
    <link href="https://baoqger.github.io/2020/12/01/svg-data-vis/"/>
    <id>https://baoqger.github.io/2020/12/01/svg-data-vis/</id>
    <published>2020-12-01T00:44:04.000Z</published>
    <updated>2021-12-23T12:34:34.799Z</updated>
    
    
    
    
    
  </entry>
  
  <entry>
    <title>Service registry and discovery in Golang Cloud-Native microservice with Consul and Docker</title>
    <link href="https://baoqger.github.io/2020/11/16/golang-service-discovery-consul/"/>
    <id>https://baoqger.github.io/2020/11/16/golang-service-discovery-consul/</id>
    <published>2020-11-16T01:22:23.000Z</published>
    <updated>2021-12-23T12:34:34.793Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Background"><a href="#Background" class="headerlink" title="Background"></a>Background</h3><p>In this post, I will give a real demo application to show how to do service registration and discovery in <code>Cloud-Native</code> microservice architecture based on <code>Consul</code> and <code>Docker</code>. And the service is developed in <code>Golang</code> language.</p><p>It will cover the following technical points:</p><ul><li>Integrate Consul with Golang application for service registration</li><li>Integrate Consul with Golang application for service discovery</li><li>Configure and Run the microservices with Docker(docker-compose)</li></ul><p>As you can see, this post will cover several critical concepts and interesting tools. I will do a quick and brief introduction of them. </p><ul><li><p><strong>Cloud-Native</strong>: this is another buzzword in the software industry. One of the key attributes of Cloud-Native application is <code>containerized</code>. To be considered cloud native, an application must be <code>infrastructure agnostic</code> and use containers. Containers provide applications the ability to run as a stand-alone environment able to move in and out of the cloud and have no dependencies on any certain cloud provider. </p></li><li><p><strong>Service Registration and Service Discovery</strong>: in the microservices application, each service needs to call other services. In order to make a request, your service needs to know the network address of a service instance. In a cloud-based microservices application, the network location is dynamically assigned. So your application needs a service discovery mechanism. On the other hand, the service registry acts as a database storing the available service instances.</p></li><li><p><strong>Consul</strong>: Consul is the tool we used in this demo application for service registry and discovery. Consul is a member in <code>CNCF(Cloud Native Computing Foundation)</code>. I will try to write a post to analyze its source code in the future.</p></li><li><p><strong>Docker-compose</strong>: is a tool to run multi-container applications on Docker. It allows different containers can communicate with each other. In this post, I will show you how to use it as well. </p></li></ul><p>All the code and config file can be found in this <a href="https://github.com/baoqger/service-discovery-demo">github repo</a>, please checkout the <code>service-discovery</code> branch for this post’s demo. </p><h3 id="Service-registry-and-discovery-demo"><a href="#Service-registry-and-discovery-demo" class="headerlink" title="Service registry and discovery demo"></a>Service registry and discovery demo</h3><p>To explain service registry and discovery, I will run a simple <code>helloworld</code> server and a client which keeps sending requests to the server every 10 seconds. The demo <code>helloworld</code> server will register itself in <code>Consul</code>, and this process is just service registry. On the other side, before the client sends a request to the server, it will first send a request to <code>Consul</code> and find the address of the server. This process is just service discovery.  OK, let’s show some code. </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line"><span class="string">&quot;fmt&quot;</span></span><br><span class="line"><span class="string">&quot;log&quot;</span></span><br><span class="line"><span class="string">&quot;net/http&quot;</span></span><br><span class="line"><span class="string">&quot;os&quot;</span></span><br><span class="line"><span class="string">&quot;strconv&quot;</span></span><br><span class="line"></span><br><span class="line">consulapi <span class="string">&quot;github.com/hashicorp/consul/api&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">serviceRegistryWithConsul()</span><br><span class="line">log.Println(<span class="string">&quot;Starting Hello World Server...&quot;</span>)</span><br><span class="line">http.HandleFunc(<span class="string">&quot;/helloworld&quot;</span>, helloworld)</span><br><span class="line">http.HandleFunc(<span class="string">&quot;/check&quot;</span>, check)</span><br><span class="line">http.ListenAndServe(getPort(), <span class="literal">nil</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">serviceRegistryWithConsul</span><span class="params">()</span></span> &#123;</span><br><span class="line">config := consulapi.DefaultConfig()</span><br><span class="line">consul, err := consulapi.NewClient(config)</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">log.Println(err)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">serviceID := <span class="string">&quot;helloworld-server&quot;</span></span><br><span class="line">port, _ := strconv.Atoi(getPort()[<span class="number">1</span>:<span class="built_in">len</span>(getPort())])</span><br><span class="line">address := getHostname()</span><br><span class="line"></span><br><span class="line">registration := &amp;consulapi.AgentServiceRegistration&#123;</span><br><span class="line">ID:      serviceID,</span><br><span class="line">Name:    <span class="string">&quot;helloworld-server&quot;</span>,</span><br><span class="line">Port:    port,</span><br><span class="line">Address: address,</span><br><span class="line">Check: &amp;consulapi.AgentServiceCheck&#123;</span><br><span class="line">HTTP:     fmt.Sprintf(<span class="string">&quot;http://%s:%v/check&quot;</span>, address, port),</span><br><span class="line">Interval: <span class="string">&quot;10s&quot;</span>,</span><br><span class="line">Timeout:  <span class="string">&quot;30s&quot;</span>,</span><br><span class="line">&#125;,</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">regiErr := consul.Agent().ServiceRegister(registration)</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> regiErr != <span class="literal">nil</span> &#123;</span><br><span class="line">log.Printf(<span class="string">&quot;Failed to register service: %s:%v &quot;</span>, address, port)</span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">log.Printf(<span class="string">&quot;successfully register service: %s:%v&quot;</span>, address, port)</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">helloworld</span><span class="params">(w http.ResponseWriter, r *http.Request)</span></span> &#123;</span><br><span class="line">log.Println(<span class="string">&quot;helloworld service is called.&quot;</span>)</span><br><span class="line">w.WriteHeader(http.StatusOK)</span><br><span class="line">fmt.Fprintf(w, <span class="string">&quot;Hello world.&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">check</span><span class="params">(w http.ResponseWriter, r *http.Request)</span></span> &#123;</span><br><span class="line">w.WriteHeader(http.StatusOK)</span><br><span class="line">fmt.Fprintf(w, <span class="string">&quot;Consul check&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">getPort</span><span class="params">()</span></span> (port <span class="type">string</span>) &#123;</span><br><span class="line">port = os.Getenv(<span class="string">&quot;PORT&quot;</span>)</span><br><span class="line"><span class="keyword">if</span> <span class="built_in">len</span>(port) == <span class="number">0</span> &#123;</span><br><span class="line">port = <span class="string">&quot;8080&quot;</span></span><br><span class="line">&#125;</span><br><span class="line">port = <span class="string">&quot;:&quot;</span> + port</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">getHostname</span><span class="params">()</span></span> (hostname <span class="type">string</span>) &#123;</span><br><span class="line">hostname, _ = os.Hostname()</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h5 id="server-go"><a href="#server-go" class="headerlink" title="server.go"></a><strong><code>server.go</code></strong></h5><p>The above <code>server.go</code> file contains many codes, but most of them are easy, and just for setting up the server and handling the request. </p><p>The interesting part is inside function <code>serviceRegistryWithConsul</code>. Consul provides APIs to register service by configuring the necessary information. For now, we can focus on two fields, the first one is <code>ID</code> which is unique for each service and we also use it for search the target service in the discovery process. The second one is <code>Check</code>, which means <code>health check</code>. Consul provides this helpful functionality. In the real microservices application, each service may have multiple instances to handle the increased requests when the concurrency is high, this is called <code>scalability</code>. But some instances may go down or throw exceptions, in service discovery we want to filter these instances out. Health check in Consul is just for this purpose. I will show you how to do that in the <a href="https://baoqger.github.io/2020/12/30/golang-load-balancing-fabio/">next post</a>.  </p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line"><span class="string">&quot;fmt&quot;</span></span><br><span class="line"><span class="string">&quot;io/ioutil&quot;</span></span><br><span class="line"><span class="string">&quot;net/http&quot;</span></span><br><span class="line"><span class="string">&quot;time&quot;</span></span><br><span class="line"></span><br><span class="line">consulapi <span class="string">&quot;github.com/hashicorp/consul/api&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> url <span class="type">string</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">serviceDiscoveryWithConsul()</span><br><span class="line">fmt.Println(<span class="string">&quot;Starting Client.&quot;</span>)</span><br><span class="line"><span class="keyword">var</span> client = &amp;http.Client&#123;</span><br><span class="line">Timeout: time.Second * <span class="number">30</span>,</span><br><span class="line">&#125;</span><br><span class="line">callServerEvery(<span class="number">10</span>*time.Second, client)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">serviceDiscoveryWithConsul</span><span class="params">()</span></span> &#123;</span><br><span class="line">config := consulapi.DefaultConfig()</span><br><span class="line">consul, <span class="type">error</span> := consulapi.NewClient(config)</span><br><span class="line"><span class="keyword">if</span> <span class="type">error</span> != <span class="literal">nil</span> &#123;</span><br><span class="line">fmt.Println(<span class="type">error</span>)</span><br><span class="line">&#125;</span><br><span class="line">services, <span class="type">error</span> := consul.Agent().Services()</span><br><span class="line"><span class="keyword">if</span> <span class="type">error</span> != <span class="literal">nil</span> &#123;</span><br><span class="line">fmt.Println(<span class="type">error</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">service := services[<span class="string">&quot;helloworld-server&quot;</span>]</span><br><span class="line">address := service.Address</span><br><span class="line">port := service.Port</span><br><span class="line">url = fmt.Sprintf(<span class="string">&quot;http://%s:%v/helloworld&quot;</span>, address, port)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">hello</span><span class="params">(t time.Time, client *http.Client)</span></span> &#123;</span><br><span class="line">response, err := client.Get(url)</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">fmt.Println(err)</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">&#125;</span><br><span class="line">body, _ := ioutil.ReadAll(response.Body)</span><br><span class="line">fmt.Printf(<span class="string">&quot;%s. Time is %v\n&quot;</span>, body, t)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">callServerEvery</span><span class="params">(d time.Duration, client *http.Client)</span></span> &#123;</span><br><span class="line"><span class="keyword">for</span> x := <span class="keyword">range</span> time.Tick(d) &#123;</span><br><span class="line">hello(x, client)</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h5 id="client-go"><a href="#client-go" class="headerlink" title="client.go"></a><strong><code>client.go</code></strong></h5><p>Similarly, in the <code>client.go</code> file, the only key part is <code>serviceDiscoveryWithConsul</code> function. Based on the Consul APIs, we can find out all the services. With the target service id (in this demo is <code>helloworld-server</code>) which is set in the registration part, we can easily find out the address. </p><p>The above parts show how to do the service registry and discovery in a completed demo. It makes use of Consul APIs a lot, I didn’t give too many explanations on that, since you can find out more detailed information in the document. </p><p>In the next section, I will show you how to run this demo application in a Cloud-Native way based on Docker and Docker-compose. </p><h3 id="Containerization"><a href="#Containerization" class="headerlink" title="Containerization"></a>Containerization</h3><p>First let’s create Dockerfile for the server as following:</p><figure class="highlight docker"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">FROM</span> golang:<span class="number">1.14</span>.<span class="number">1</span>-alpine</span><br><span class="line"></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> apk update &amp;&amp; apk upgrade &amp;&amp; apk add --no-cache bash git</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> go get github.com/hashicorp/consul/api</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">ENV</span> SOURCES /go/src/github.com/baoqger/service-discovery-demo/</span><br><span class="line"><span class="keyword">COPY</span><span class="language-bash"> . <span class="variable">$&#123;SOURCES&#125;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> <span class="built_in">cd</span> <span class="variable">$&#123;SOURCES&#125;</span>server/ &amp;&amp; CGO_ENABLED=0 go build</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">ENV</span> CONSUL_HTTP_ADDR localhost:<span class="number">8500</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">WORKDIR</span><span class="language-bash"> <span class="variable">$&#123;SOURCES&#125;</span>server/</span></span><br><span class="line"><span class="keyword">CMD</span><span class="language-bash"> <span class="variable">$&#123;SOURCES&#125;</span>server/server</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><h5 id="Dockerfile-for-server-go"><a href="#Dockerfile-for-server-go" class="headerlink" title="Dockerfile for server.go"></a><strong><code>Dockerfile</code> for server.go</strong></h5><p>This part is straightforward, if you don’t understand some of the commands used here please check the Docker’s manual. </p><p>I will not show the Dockerfile for the client any more, since it’s nearly the same as the above one. But you can find it in this <a href="https://github.com/baoqger/service-discovery-demo">github repo</a>.</p><p>Now we have both server and client running in containers. We need add the Consul into this application as well, and connect these 3 containers together. We do this with Docker-compose. </p><p>Docker-compose is driven by the <code>yml</code> file. In our case, it goes as following:</p><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">version:</span> <span class="string">&#x27;2&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="attr">services:</span> </span><br><span class="line">  <span class="attr">consul:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">consul:0.8.3</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;8500:8500&quot;</span></span><br><span class="line">    <span class="attr">networks:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">my-net</span></span><br><span class="line">      </span><br><span class="line">  <span class="attr">helloworld-server:</span></span><br><span class="line">    <span class="attr">build:</span></span><br><span class="line">      <span class="attr">context:</span> <span class="string">.</span></span><br><span class="line">      <span class="attr">dockerfile:</span> <span class="string">server/Dockerfile</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">helloworld-server:1.0.1</span></span><br><span class="line">    <span class="attr">environment:</span> </span><br><span class="line">      <span class="bullet">-</span> <span class="string">CONSUL_HTTP_ADDR=consul:8500</span></span><br><span class="line">    <span class="attr">depends_on:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">consul</span></span><br><span class="line">    <span class="attr">networks:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">my-net</span></span><br><span class="line"></span><br><span class="line">  <span class="attr">helloworld-client:</span></span><br><span class="line">    <span class="attr">build:</span></span><br><span class="line">      <span class="attr">context:</span> <span class="string">.</span></span><br><span class="line">      <span class="attr">dockerfile:</span> <span class="string">client/Dockerfile</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">helloworld-client:1.0.1</span></span><br><span class="line">    <span class="attr">environment:</span> </span><br><span class="line">      <span class="bullet">-</span> <span class="string">CONSUL_HTTP_ADDR=consul:8500</span> </span><br><span class="line">    <span class="attr">depends_on:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">consul</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">helloworld-server</span></span><br><span class="line">    <span class="attr">networks:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">my-net</span></span><br><span class="line"></span><br><span class="line"><span class="attr">networks:</span></span><br><span class="line">  <span class="attr">my-net:</span></span><br><span class="line">    <span class="attr">driver:</span> <span class="string">bridge</span></span><br><span class="line">  </span><br></pre></td></tr></table></figure><p>There are several points need to mention about docker-compose usages:</p><ul><li><strong>networks</strong>: we define a network called <code>my-net</code>, and use it in all of the 3 services to make them can talk with each other. </li><li><strong>environment</strong>: we can set up the environment variable in this part. In our case, both server and client need to send requests to Consul for registry and discovery, right? You can check the server and client file, we didn’t set the Consul address explicitly. Since Consul do it in an implicit way, it will get the value from the environment variable named <code>CONSUL_HTTP_ADDR</code>. We set it up with <code>CONSUL_HTTP_ADDR=consul:8500</code>. </li><li><strong>docker-compose up</strong>: this is the command all you need to launch the application. Another helpful command is <code>docker-compose build</code> which is used to build the image defined in the yml file. Of course, <code>docker-compose down</code> can stop the containers when you want to leave the application. </li></ul><p>Everything is setted up, you can verify the result both in the terminal and Consul UI as following:</p><p><img src="/images/service-discovery.png" alt="service-discovery"></p><p><img src="/images/consul-ui.png" alt="consul-ui"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;Background&quot;&gt;&lt;a href=&quot;#Background&quot; class=&quot;headerlink&quot; title=&quot;Background&quot;&gt;&lt;/a&gt;Background&lt;/h3&gt;&lt;p&gt;In this post, I will give a real demo </summary>
      
    
    
    
    
    <category term="microservice, service registration, service discovery, Consul, Golang, Cloud-Native, Docker" scheme="https://baoqger.github.io/tags/microservice-service-registration-service-discovery-Consul-Golang-Cloud-Native-Docker/"/>
    
  </entry>
  
  <entry>
    <title>Golang inter Goroutine communication - shared memory or channels</title>
    <link href="https://baoqger.github.io/2020/10/26/golang-concurrent-twoways/"/>
    <id>https://baoqger.github.io/2020/10/26/golang-concurrent-twoways/</id>
    <published>2020-10-26T02:29:32.000Z</published>
    <updated>2024-08-30T08:47:44.923Z</updated>
    
    <content type="html"><![CDATA[<h2 id="Introduction"><a href="#Introduction" class="headerlink" title="Introduction"></a>Introduction</h2><p>This post will demonstrate how to do inter-thread communication in Golang concurrent programming. Generally speaking, there are two ways for this fundamental question: <code>shared memory</code> and <code>message passing</code>. You’ll see how to do these in Golang based on a case study and some tricky problems around it.</p><h2 id="Background"><a href="#Background" class="headerlink" title="Background"></a>Background</h2><p><code>Golang</code> is a new popular and powerful programming language that aims to provide a simple, efficient, and safe way to build multi-threaded software. </p><p>Concurrent programming is one of Go’s main selling points. <code>Go</code> uses a concept called <em>goroutine</em> as its concurrency unit. Goroutine is a complex but interesting topic, you can find many articles about it online, This post will not cover concepts about it in detail. Simply speaking, goroutine is a user-space  level thread which is lightweight and easy to create. </p><p>As mentioned above, one of the complicated problems when we do concurrent programming is that inter-thread (or inter-goroutine) communication is very error-prone. In Golang, it provides frameworks for both <code>shared memory</code> and <code>message passing</code>. However, it encourages the use of <em>channels</em> over shared memory. </p><p>You’ll see how both of these methods in Golang based on the following case. </p><h2 id="Case-study"><a href="#Case-study" class="headerlink" title="Case study"></a>Case study</h2><p>The example is very simple: sums a collection (10 million) of integers. In fact this example is based on this good <a href="https://www.ardanlabs.com/blog/2018/12/scheduling-in-go-part3.html">article</a>. It used the <code>shared memory</code> way to realize the communication between goroutines. I expand this example and implemented the <code>message passing</code> way to show the difference.</p><h3 id="Shared-Memory"><a href="#Shared-Memory" class="headerlink" title="Shared Memory"></a>Shared Memory</h3><p>Go supports traditional shared memory accesses among goroutines. You can use various traditional synchronization primitives such as <em>lock/unlock</em> (Mutex), <em>condition variable</em> (Cond) and <em>atomic</em> read/write operations(atomic).  </p><p>In the following implementation, you can see Go uses <code>WaitGroup</code> to allow multiple goroutines to do their tasks before a waiting goroutine. This usage is very similar to <code>pthread_join</code> in C. </p><p>Goroutines are added to a WaitGroup by calling <code>Add</code> method. And the goroutines in a WaitGroup call <code>Done</code> method to notify their completion, while a goroutine make a call to <code>Wait</code> method to wait for all goroutines’ completion. </p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line"><span class="string">&quot;fmt&quot;</span></span><br><span class="line"><span class="string">&quot;math/rand&quot;</span></span><br><span class="line"><span class="string">&quot;runtime&quot;</span></span><br><span class="line"><span class="string">&quot;sync&quot;</span></span><br><span class="line"><span class="string">&quot;sync/atomic&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">numbers := generateList(<span class="number">1e7</span>)</span><br><span class="line"></span><br><span class="line">fmt.Println(<span class="string">&quot;add: &quot;</span>, add(numbers))</span><br><span class="line">fmt.Println(<span class="string">&quot;add concurrent: &quot;</span>, addConcurrent(runtime.NumCPU(), numbers))</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">generateList</span><span class="params">(totalNumbers <span class="type">int</span>)</span></span> []<span class="type">int</span> &#123;</span><br><span class="line">numbers := <span class="built_in">make</span>([]<span class="type">int</span>, totalNumbers)</span><br><span class="line"><span class="keyword">for</span> i := <span class="number">0</span>; i &lt; totalNumbers; i++ &#123;</span><br><span class="line">numbers[i] = rand.Intn(totalNumbers)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> numbers</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">add</span><span class="params">(numbers []<span class="type">int</span>)</span></span> <span class="type">int</span> &#123;</span><br><span class="line"><span class="keyword">var</span> v <span class="type">int</span></span><br><span class="line"><span class="keyword">for</span> _, n := <span class="keyword">range</span> numbers &#123;</span><br><span class="line">v += n</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> v</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">addConcurrent</span><span class="params">(goroutines <span class="type">int</span>, numbers []<span class="type">int</span>)</span></span> <span class="type">int</span> &#123;</span><br><span class="line"><span class="keyword">var</span> v <span class="type">int64</span></span><br><span class="line">totalNumbers := <span class="built_in">len</span>(numbers)</span><br><span class="line">lastGoroutine := goroutines - <span class="number">1</span></span><br><span class="line"></span><br><span class="line">strid := totalNumbers / goroutines</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> wg sync.WaitGroup</span><br><span class="line">wg.Add(goroutines)</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> g := <span class="number">0</span>; g &lt; goroutines; g++ &#123;</span><br><span class="line"><span class="keyword">go</span> <span class="function"><span class="keyword">func</span><span class="params">(g <span class="type">int</span>)</span></span> &#123;</span><br><span class="line">start := g * strid</span><br><span class="line">end := start + strid</span><br><span class="line"><span class="keyword">if</span> g == lastGoroutine &#123;</span><br><span class="line">end = totalNumbers</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> lv <span class="type">int</span></span><br><span class="line"><span class="keyword">for</span> _, n := <span class="keyword">range</span> numbers[start:end] &#123;</span><br><span class="line">lv += n</span><br><span class="line">&#125;</span><br><span class="line">atomic.AddInt64(&amp;v, <span class="type">int64</span>(lv))</span><br><span class="line">wg.Done()</span><br><span class="line">&#125;(g)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">wg.Wait()</span><br><span class="line"><span class="keyword">return</span> <span class="type">int</span>(v)</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>In the example above the <code>int64</code> variable <code>v</code> is shared across goroutines. When this variable needs to be updated, an atomic operation was done by calling <code>atomic.AddInt64()</code> method to avoid race condition and nondeterministic result. </p><p>That’s how shared memory across goroutines works in Golang. Let’s go to message passing way in next section. </p><h3 id="Message-Passing"><a href="#Message-Passing" class="headerlink" title="Message Passing"></a>Message Passing</h3><p>In Golang world, there is one sentence is famous:</p><blockquote><p>Don’t communicate by sharing memory; share memory by communicating</p></blockquote><p>For that, <code>Channel</code>(chan) is introduced in Go as a new concurrency primitive to send data across goroutines. This is also the way Golang recommended you to follow.</p><p>So the concurrent program to sum 10 million integers  based on <code>Channel</code> goes as below: </p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line"><span class="string">&quot;fmt&quot;</span></span><br><span class="line"><span class="string">&quot;math/rand&quot;</span></span><br><span class="line"><span class="string">&quot;runtime&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line"><span class="keyword">var</span> result <span class="type">int64</span></span><br><span class="line">numbers := generateList(<span class="number">1e7</span>)</span><br><span class="line"></span><br><span class="line">goroutines := runtime.NumCPU()</span><br><span class="line">lastGoroutine := goroutines - <span class="number">1</span></span><br><span class="line"></span><br><span class="line">totalNumbers := <span class="built_in">len</span>(numbers)</span><br><span class="line">strid := totalNumbers / goroutines</span><br><span class="line"></span><br><span class="line">c := <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="type">int</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> g := <span class="number">0</span>; g &lt; goroutines; g++ &#123;</span><br><span class="line">start := g * strid</span><br><span class="line">end := start + strid</span><br><span class="line"><span class="keyword">if</span> g == lastGoroutine &#123;</span><br><span class="line">end = totalNumbers</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">go</span> add(numbers[start:end], c)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> l := <span class="keyword">range</span> c &#123;</span><br><span class="line">result += <span class="type">int64</span>(l)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">fmt.Println(<span class="string">&quot;add concurrent: &quot;</span>, result)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">generateList</span><span class="params">(totalNumbers <span class="type">int</span>)</span></span> []<span class="type">int</span> &#123;</span><br><span class="line">numbers := <span class="built_in">make</span>([]<span class="type">int</span>, totalNumbers)</span><br><span class="line"><span class="keyword">for</span> i := <span class="number">0</span>; i &lt; totalNumbers; i++ &#123;</span><br><span class="line">numbers[i] = rand.Intn(totalNumbers)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> numbers</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">add</span><span class="params">(numbers []<span class="type">int</span>, c <span class="keyword">chan</span> <span class="type">int</span>)</span></span> &#123;</span><br><span class="line"><span class="keyword">var</span> v <span class="type">int</span></span><br><span class="line"><span class="keyword">for</span> _, n := <span class="keyword">range</span> numbers &#123;</span><br><span class="line">v += n</span><br><span class="line">&#125;</span><br><span class="line">c &lt;- v</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>To create a typed channel, you can call <code>make</code> method. In this case, since the value we need to pass is an integer, so we create an int type channel with <code>c := make(chan int)</code>. To read and write data to that channel, you can use <code>&lt;-</code> operator. For example, in the <code>add</code> goroutine, when we get the sum of integers, we use <code>c &lt;- v</code> to send data to the channel. </p><p>To read data from the channel in the main goroutine, we use a build-in method <code>range</code> in Golang which can iterate through data structure like slice, map and channel. </p><p>That’s it. Simple and beautiful. </p><h4 id="Hit-the-Deadlock"><a href="#Hit-the-Deadlock" class="headerlink" title="Hit the Deadlock"></a>Hit the Deadlock</h4><p>Let’s build and run the above solution. You’ll get an error message as following:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">fatal error: all goroutines are asleep - deadlock!</span><br></pre></td></tr></table></figure><p>The <code>deadlock</code> issue occurs because of these two reasons. Firstly by default sends and receives to a channel are blocking. When a data is send to a channel, the control in that goroutine is blocked at the send statement until some other Goroutine reads from the channel. Similarly when data is read from a channel, the read is blocked until some Goroutine writes data to that channel. Secondly, <code>range</code> only stops when the channel is closed. In this case, each <code>add</code> Goroutine send only one value to the channel but didn’t close the channel. And the main Goroutine keeps waiting for something to be written (in fact, it can read 4 values, but after that it doesn’t stop and keep waiting for more data). So all of the Goroutines are blocked and none of them can continue the execution. Then hit a deadlock. </p><h4 id="Fix-the-Deadlock"><a href="#Fix-the-Deadlock" class="headerlink" title="Fix the Deadlock"></a>Fix the Deadlock</h4><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line"><span class="string">&quot;fmt&quot;</span></span><br><span class="line"><span class="string">&quot;math/rand&quot;</span></span><br><span class="line"><span class="string">&quot;runtime&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line"><span class="keyword">var</span> result <span class="type">int64</span></span><br><span class="line">numbers := generateList(<span class="number">1e7</span>)</span><br><span class="line"></span><br><span class="line">goroutines := runtime.NumCPU()</span><br><span class="line">lastGoroutine := goroutines - <span class="number">1</span></span><br><span class="line"></span><br><span class="line">totalNumbers := <span class="built_in">len</span>(numbers)</span><br><span class="line">strid := totalNumbers / goroutines</span><br><span class="line"></span><br><span class="line">c := <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="type">int</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> g := <span class="number">0</span>; g &lt; goroutines; g++ &#123;</span><br><span class="line">start := g * strid</span><br><span class="line">end := start + strid</span><br><span class="line"><span class="keyword">if</span> g == lastGoroutine &#123;</span><br><span class="line">end = totalNumbers</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">go</span> add(numbers[start:end], c)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> j := <span class="number">0</span>; j &lt; goroutines; j++ &#123;</span><br><span class="line">result += <span class="type">int64</span>(&lt;-c)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">fmt.Println(<span class="string">&quot;add concurrent: &quot;</span>, result)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">generateList</span><span class="params">(totalNumbers <span class="type">int</span>)</span></span> []<span class="type">int</span> &#123;</span><br><span class="line">numbers := <span class="built_in">make</span>([]<span class="type">int</span>, totalNumbers)</span><br><span class="line"><span class="keyword">for</span> i := <span class="number">0</span>; i &lt; totalNumbers; i++ &#123;</span><br><span class="line">numbers[i] = rand.Intn(totalNumbers)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> numbers</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">add</span><span class="params">(numbers []<span class="type">int</span>, c <span class="keyword">chan</span> <span class="type">int</span>)</span></span> &#123;</span><br><span class="line"><span class="keyword">var</span> v <span class="type">int</span></span><br><span class="line"><span class="keyword">for</span> _, n := <span class="keyword">range</span> numbers &#123;</span><br><span class="line">v += n</span><br><span class="line">&#125;</span><br><span class="line">c &lt;- v</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>Let use the manual <code>for</code> loop, in each iteration we read the value from the channel and sum together. Run it again. The deadlock is resolved. </p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;Introduction&quot;&gt;&lt;a href=&quot;#Introduction&quot; class=&quot;headerlink&quot; title=&quot;Introduction&quot;&gt;&lt;/a&gt;Introduction&lt;/h2&gt;&lt;p&gt;This post will demonstrate how</summary>
      
    
    
    
    
    <category term="golang, concurrent, shared memory, message pass" scheme="https://baoqger.github.io/tags/golang-concurrent-shared-memory-message-pass/"/>
    
  </entry>
  
  <entry>
    <title>Hack operating system by xv6 project</title>
    <link href="https://baoqger.github.io/2020/09/22/os-xv6-1/"/>
    <id>https://baoqger.github.io/2020/09/22/os-xv6-1/</id>
    <published>2020-09-22T08:58:18.000Z</published>
    <updated>2021-12-23T12:34:34.798Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Background"><a href="#Background" class="headerlink" title="Background"></a>Background</h3><p>In this post, I want to introduce <code>xv6</code> which is a “simple, Unix-like operating system”. </p><p>xv6 is not only an open-source project, but also it is used for teaching purposes in MIT’s Operating Systems Engineering(6.828) course as well as many other institutions. </p><p>If you’re like me, always want to learn operating system, I guess you’ll face a very steep learning curve since operating system is complex. </p><p>For learning purpose, we need an operating system project which is <code>not too complex</code> and <code>not  too simple</code>. Luckily, xv6 is just for this purpose which is simple enough to follow up as an open source project, yet still contains the important concepts and organization of Unix. </p><h3 id="Resource"><a href="#Resource" class="headerlink" title="Resource"></a>Resource</h3><p>Since <code>xv6</code> is an open source project, you can easily find many resources online. </p><p>Personally I recommend to use this <a href="https://pdos.csail.mit.edu/6.828/2020/schedule.html">page</a>, which is the latest teaching resource for the corresponding MIT course. You can find source code, examples, slides and videos there. Very helpful!</p><h3 id="Environment-setup-for-xv6-project"><a href="#Environment-setup-for-xv6-project" class="headerlink" title="Environment setup for xv6 project"></a>Environment setup for xv6 project</h3><p>On the MIT course’s document, there are many solutions for setting up the xv6 development environment. You can follow those solutions, it will work. </p><p>For your convenience, I make a <code>Dockerfile</code> to build the docker image which contains all the necessary dependencies to keep working on xv6. The Dockerfile goes as following:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">FROM ubuntu:latest</span><br><span class="line"></span><br><span class="line">ARG DEBIAN_FRONTEND=noninteractive</span><br><span class="line"></span><br><span class="line">RUN apt-get -qq update</span><br><span class="line"></span><br><span class="line">RUN apt-get install -y git \</span><br><span class="line">                    build-essential \</span><br><span class="line">                    gdb-multiarch \</span><br><span class="line">                    qemu-system-misc \</span><br><span class="line">                    gcc-9-riscv64-linux-gnu \</span><br><span class="line">                    gcc-riscv64-linux-gnu \</span><br><span class="line">                    binutils-riscv64-linux-gnu\</span><br><span class="line">                    tmux \</span><br><span class="line">                    qemu</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;Background&quot;&gt;&lt;a href=&quot;#Background&quot; class=&quot;headerlink&quot; title=&quot;Background&quot;&gt;&lt;/a&gt;Background&lt;/h3&gt;&lt;p&gt;In this post, I want to introduce &lt;cod</summary>
      
    
    
    
    
    <category term="operating system, xv6, Unix" scheme="https://baoqger.github.io/tags/operating-system-xv6-Unix/"/>
    
  </entry>
  
  <entry>
    <title>Understand stack memory management</title>
    <link href="https://baoqger.github.io/2020/08/19/stack-frame/"/>
    <id>https://baoqger.github.io/2020/08/19/stack-frame/</id>
    <published>2020-08-18T20:54:00.000Z</published>
    <updated>2021-12-23T12:34:34.798Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Table-of-Contents"><a href="#Table-of-Contents" class="headerlink" title="Table of Contents"></a>Table of Contents</h3><p>First I have to admit that memory management is a big( and important) topic in operating system. This post can’t cover everything related to it. </p><p>In this post, I want to share something interesting I learned about stack memory management. Especially understand how the stack frame of function call works, which’s the most important part of stack memory. I will explain the mechanism in detail with examples and diagrams.</p><p>Briefly speaking, the contents of this post is:</p><ul><li>Memory layout of a process</li><li>Stack memory contents</li><li>CPU register related to stack memory management</li><li>Stack frame of function call and return mechanism</li></ul><p>To understand the concepts and machanisms deeply, a few assembly code will be shown in this post, you don’t have to know assembly lauguage as an expert for reading this post, I will add comments for these assembly codes to make explain what’s their functionalities.</p><h3 id="Stack-Memory-Management-Basic"><a href="#Stack-Memory-Management-Basic" class="headerlink" title="Stack Memory Management Basic"></a>Stack Memory Management Basic</h3><h4 id="Memory-Layout-of-Process"><a href="#Memory-Layout-of-Process" class="headerlink" title="Memory Layout of Process"></a>Memory Layout of Process</h4><p>Before we talk about Stack memory management, it’s necessary to understand <code>memory layout</code> of a process.</p><p>When you create a program, it is just some Bytes of data which is stored in the disk. When a program executes then it starts loading into memory and become a live entity. In a more specify way, some memory (virtual memory) is allocated to each process in execution for its usage by operating system. The memory assigned to a process is called process’s <code>virtual address space</code>( short for VAS). And memory layout use diagrams to help you understand the concept of process virtual address space easily.</p><p>There are some awesome posts on the internet about <a href="https://www.includehelp.com/operating-systems/memory-layout-of-a-process.aspx">memory layout</a>. And the most two critical sections are: Stack and Heap. Simply speaking, <code>Stack</code> is the memory area which is used by each process to store the local variables, passed arguments and other information when a function is called. This is the topic of this post, you’ll know more detailed in the following sections. While <code>Heap</code> segment is the one which is used for dynamic memory allocation, this is another more complex topic out of this post’s scope. </p><h4 id="Stack-Memory-Basics"><a href="#Stack-Memory-Basics" class="headerlink" title="Stack Memory Basics"></a>Stack Memory Basics</h4><p>Stack Memory is just memory region in each process’s virtual address space where <code>stack</code> data structure (Last in, first out) is used to store the data. As we mentioned above, when a new function call is invoked, then a frame of data is pushed to stack memory and when the function call returns then the frame is removed from the stack memory. This is <strong>Stack Frame</strong> which represent a function call and its argument data. And every function has its own stack frame.</p><p>Let’s say in your program there are multiple functions call each other in order. For example, <code>main() -&gt; f1() -&gt; f2() -&gt; f3()</code>, <code>main</code> function calls function one <code>f1()</code>, then function one calls function two <code>f2()</code>, finally function two calls function three <code>f3()</code>. So based on the Last in first out rule, the stack memory will be like as below: </p><p><img src="/images/stack_frames.png" alt="stack-frame"></p><p><strong>Note</strong>: the top of the stack is the bottom part of the image. Don’t feel confused for that. </p><h4 id="Stack-memory-contents"><a href="#Stack-memory-contents" class="headerlink" title="Stack memory contents"></a>Stack memory contents</h4><p>After understand stack frames, now let’s dive deep into each stack frame to discover its contents.</p><p>Each stack frame contains 4 parts:</p><ul><li>Parameter passed to the callee function</li><li>Return address of the caller function</li><li>Base pointer</li><li>Local variables of the callee function</li></ul><p><img src="/images/stack_contents.png" alt="stack-contents"></p><p>Caller and callee is very easy to understand. Let’s say <code>main() -&gt; f1()</code>, then caller function is <code>main()</code> while callee function is <code>f1()</code>. Right? </p><p>For the above 4 four parts, there are something need to emphasis. Firstly the size of <code>return address of the caller function</code> is fixed, for example, in 32 bits system the size is 4B. And <code>Base pointer</code> size is fixed as well, it’s also 4B in a 32 bits system. This fixed size is important, you’ll see the reason in following sections. </p><p>Next, in the above diagram you see two kinds of pointers: <strong>base pointer</strong> and <strong>stack pointer</strong>. Let’s check them one by one.</p><p><strong><em>Stack pointer</em></strong>: pointer to the top of the stack. When stack adds or removes data then stack pointer will change correspondingly. Stack pointer is straight forward and not difficult to understand, right?<br><strong><em>Base pointer</em></strong>: is also called <code>frame pointer</code> which points to the current active  frame. And the current active frame is the topmost frame of the stack. </p><p>The base pointer is conventionlly used to mark the start of a function’s stack frame, and the area of the stack managed by that function. As we mentioned above, since the size of return address and base pointer is fixed, so based on the address of base pointer you can get all the data in that stack frame. Local variables can be accessed with positive offset and passed parameters can be got with negative offset. That’s the reason why it is called <strong>base</strong> pointer. Great design, right? </p><p>The other thing need to discuss is what’t the content of base pointer part in each stack frame? In the above diagram you see that a 4 bytes data is pushed into the stack, we call it base pointer. But what’s the data? In fact, base pointer is designed to <code>store the caller&#39;s base pointer address</code>. This is also a smart design to make function return works well. We’ll discuss more about it later.</p><h4 id="CPU-register"><a href="#CPU-register" class="headerlink" title="CPU register"></a>CPU register</h4><p>To understand stack memory management, you’ll need to know 3 interesting CPU register:</p><ul><li><strong>eip</strong>: Instruction pointer register which stores the address of the next instruction to be run. </li><li><strong>esp</strong>: Stack pointer register which stores the address of the top of the stack at any time.</li><li><strong>ebp</strong>: Base pointer register which stores base pointer address of callee’s stack frame.  And the content at this address is the caller’s base pointer value (we already mentioned this point above).</li></ul><p>Until now, you see all the necessary stuff: stack frame, stack frame content and CPU registers. Let’s see how they play together to make stack frames of function call and return works. You’ll see how this simple but beautiful design realizes such a complex task.  </p><h3 id="Mechanism-of-function-call-and-return"><a href="#Mechanism-of-function-call-and-return" class="headerlink" title="Mechanism of function call and return"></a>Mechanism of function call and return</h3><p>In this section, you’ll understand how function call and return works by reading a few assembly codes (which are not difficult to understand).</p><h4 id="function-call"><a href="#function-call" class="headerlink" title="function call"></a>function call</h4><p><strong>Step one</strong>: as you already see in the above diagram the first part of each stack frame is the passed parameters to the callee. So all the arguments are pushed on the stack as the following codes shows:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">push arg2;</span><br><span class="line">push arg1;</span><br></pre></td></tr></table></figure><p><code>push</code> is the assembly instruction to push data onto the stack. And usually the arguments are pushed to the stack in the reverse order that they’re declared in function.</p><p><strong>Step two</strong>: the second part is the <code>Return address of the caller fn</code>, so we need to push the address of next instruction in caller function as <code>Return address</code> in callee’s stack frame. As we introduced in the last section, the address of next instruction will be stored in <code>EIP</code> register, right? The assembly code goes as following: </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">push eip;</span><br></pre></td></tr></table></figure><p><strong>Step three</strong>: upon entrying to the callee function, the old <code>EBP</code> value (the caller function’s base pointer address) is pushed onto the stack and then <code>EBP</code> is set to the value of <code>ESP</code>. Then the <code>ESP</code> is decremented (since the stack grows downward in stack memory) to allocate space for the local variables. And the codes goes as following:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">push ebp;</span><br><span class="line">mov ebp esp;</span><br></pre></td></tr></table></figure><p><code>mov</code> - the mov instruction copies the data item referred to by its second operand into the location referred to by its first operand. </p><p>So <code>mov %ebp %esp</code> just means set <code>EBP</code> a new value of <code>ESP</code>. Please note that, <code>ESP</code> value changes when data is pushed or popped onto/from the stack. But it’s always points to the top of the stack. Before this <code>mov %ebp %esp</code> instruction, <code>ESP</code> is pointing to the address just after the <code>return address of the caller</code>, and it should be the address of callee’s base pointer and just what <code>EBP</code> should store, this instruction makes sense, right?</p><p>From that on, during the execution of the callee function, the passed arguments to the function are located at the positive offsets from <code>EBP</code>, and the local variables are located at the negative offsets from <code>EBP</code>, you already see this conclusion above.</p><p>Inside a function, the stack would look like this: </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">| &lt;argument 2&gt;       |</span><br><span class="line">| &lt;argument 1&gt;       |</span><br><span class="line">| &lt;return address&gt;   |</span><br><span class="line">| &lt;old ebp&gt;          | &lt;= %ebp</span><br><span class="line">| &lt;local var 1&gt;      |</span><br><span class="line">| &lt;local var 2&gt;      | &lt;= %esp</span><br></pre></td></tr></table></figure><h4 id="function-return"><a href="#function-return" class="headerlink" title="function return"></a>function return</h4><p><strong>Step one</strong>: upon exit from the callee function, all the function has to do is set <code>ESP</code> to the value of <code>EBP</code>. In this way can simply deallocates/releases the local variables from the stack. And then it can also expose callee’s base pointer on the top of the stack for next step operation.</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mov esp, ebp;</span><br></pre></td></tr></table></figure><p>This instruction is restoring the saved value of <code>ESP</code> upon entering the function, at that point what we did is <code>mov ebp esp</code>. Smart design, right?</p><p><strong>Step two</strong>: since <code>ESP</code> already reset to the address of base pointer, next step we can simply pop the old <code>EBP</code> value from the top of stack as following: </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pop ebp;</span><br></pre></td></tr></table></figure><p><code>pop</code> instruction retrieves the topmost value from the stack and puts the value into the second operand, in this case is <code>EBP</code>. Remember the <code>callee</code> function’s base pointer stores the <code>caller</code> function’s base pointer, so this simple <code>pop ebp</code> instruction realize EBP register restore perfactly. Great design, right?</p><p><strong>Step three</strong>: next is straight forward, we need to pop the caller function return address to <code>EIP</code>.</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pop eip;</span><br></pre></td></tr></table></figure><p>Similar to step two, right? Now the system knows the next instruction (pointing to the return address in the caller function) need to run. The execution context is giving back to the caller function. </p><p>Upon returning back to the caller function, it can then increase <code>ESP</code> register again to remove the passed function arguments it pushed onto the stack. At this point, the stack frames becomes the same as it was in prior to invoking the callee function. </p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;Table-of-Contents&quot;&gt;&lt;a href=&quot;#Table-of-Contents&quot; class=&quot;headerlink&quot; title=&quot;Table of Contents&quot;&gt;&lt;/a&gt;Table of Contents&lt;/h3&gt;&lt;p&gt;First I ha</summary>
      
    
    
    
    
    <category term="memory management, stack" scheme="https://baoqger.github.io/tags/memory-management-stack/"/>
    
  </entry>
  
  <entry>
    <title>Use Docker container for local C++ development</title>
    <link href="https://baoqger.github.io/2020/07/28/linux-cpp-docker/"/>
    <id>https://baoqger.github.io/2020/07/28/linux-cpp-docker/</id>
    <published>2020-07-28T12:42:21.000Z</published>
    <updated>2021-12-23T12:34:34.797Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Why-develop-in-Docker-container"><a href="#Why-develop-in-Docker-container" class="headerlink" title="Why develop in Docker container?"></a>Why develop in Docker container?</h3><p><code>Docker</code> is the hottest technology to deploy and run the software. The key benefit of Docker is that it allows users to package an application with all of its dependencies into a standardized unit for software development. Compared with virtual machines, containers do not have high overhead and hence enable more efficient usage of the underlying system and resources. </p><p>Besides deploying and running applications, Docker containers can also make your local development work easier, especially when you need to set up a specific environment with many dependencies. </p><p>In my case, I have a project which is a C++ application running on the Linux platform. But on personal machines I’m running macOS and Windows systems, I didn’t install Linux platform on my computer. Before I start working on this project, I need to fix the platform/environment issue. </p><p>The first idea is, of course, using virtual-machines with VirtualBox and install the Linux system in it. This process will be time-consuming and tedious. So I decided to use Docker container to speed up the environment configuration step. </p><p>I will share the experience step by step. The whole process is lightweight and quick, also can practice your Docker related skills.</p><h3 id="Create-the-Docker-container"><a href="#Create-the-Docker-container" class="headerlink" title="Create the Docker container"></a>Create the Docker container</h3><p>To build a Docker image, we need a <code>Dockerfile</code>, which is a text document(without a file extension) that contains the instructions to set up an environment for a Docker container. The Docker <a href="https://docs.docker.com/get-started/overview/">official site</a> is the best place to understand those fundamental and important knowledge.</p><p>In my case the basic <code>Dockerfile</code> goes as following:</p><figure class="highlight docker"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Download base image ubuntu 20.04</span></span><br><span class="line"><span class="keyword">FROM</span> ubuntu:<span class="number">20.04</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Disable Prompt During Packages Installation</span></span><br><span class="line"><span class="keyword">ARG</span> DEBIAN_FRONTEND=noninteractive</span><br><span class="line"></span><br><span class="line"><span class="comment"># Update Ubuntu Software repository</span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> apt-get update &amp;&amp; apt-get install -y \</span></span><br><span class="line"><span class="language-bash">    make \</span></span><br><span class="line"><span class="language-bash">    cmake \</span></span><br><span class="line"><span class="language-bash">    g++ \</span></span><br><span class="line"><span class="language-bash">    libncurses5-dev \</span></span><br><span class="line"><span class="language-bash">    libncursesw5-dev \</span></span><br><span class="line"><span class="language-bash">&amp;&amp; <span class="built_in">rm</span> -rf /var/lib/apt/lists/*</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">CMD</span><span class="language-bash"> [<span class="string">&quot;bash&quot;</span>]</span></span><br></pre></td></tr></table></figure><p><strong><em>FROM</em></strong> : the first part is the <code>FROM</code> command, which tells us what image to base this off of (as we know, Docker is following a multi-layer structure). In my case,  it’s using the <code>Ubuntu:20.04</code> image, which again references a Dockerfile to automate the process. </p><p><strong><em>ARG</em></strong>: <code>ARG</code> instruction defines a variable that can be passed at build time to pass environment info. In this case, just to disable the console output during the following Linux package installation process. </p><p><strong><em>RUN</em></strong>: the next set of calls are the <code>RUN</code> commands. This <code>RUN</code> instruction allows you to install your application and packages for it. <code>RUN</code> executes commands in a new layer and creates a new layer by committing the results. Usually, you can find several <code>RUN</code> instructions in a Dockerfile. In this case, I want to install the C++ compiler and build tools (and some other specific dependency packages for development) which is not available in the Ubuntu base image.</p><p><strong><em>CMD</em></strong>: the last instruction <code>CMD</code> allows you to set a default command, which will be executed when you run the container without specifying a command. If Docker container runs with a command, this default one will be ignored. </p><p>With this <code>Dockerfile</code>, we can build the image with the next Docker command:</p><figure class="highlight docker"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker build -t linux-cpp .</span><br></pre></td></tr></table></figure><p>This will build the desired Docker image tagged as <code>linux-cpp</code>. You can list(find) this new image in your system with command <code>docker images</code>: </p><figure class="highlight txt"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE</span><br><span class="line">linux-cpp           latest              5463808c4488        8 days ago          320MB</span><br></pre></td></tr></table></figure><p>Now you can run the docker container with the newly build <code>linux-cpp</code> image:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run -it --name cpp-dev --<span class="built_in">rm</span> linux-cpp</span><br></pre></td></tr></table></figure><h3 id="Mount-source-code-into-container"><a href="#Mount-source-code-into-container" class="headerlink" title="Mount source code into container"></a>Mount source code into container</h3><p>Follow the above steps, you can have a running Docker container with C++ development dependencies in Linux environment. </p><p>Next, you can directly start your C++ program inside the container, then build and run your code. </p><p>But if you just put your program inside the container, you will have a high risk to lose your code when the container is deleted. </p><p>The better way is placing your program source code on your local machine and sync the codes into the container as you program. This is where <code>mount</code> can help you. Mount and Volume is an important topic for Docker, you can find <a href="https://docs.docker.com/storage/bind-mounts/">some posts</a> for deeper introduction. </p><p>In my case, I can realize my target with the following command:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run -it --name cpp-dev  --<span class="built_in">rm</span>  -v <span class="variable">$&#123;PWD&#125;</span>:/develop  linux-cpp</span><br></pre></td></tr></table></figure><p>the key and interesting part is: <code>-v $&#123;PWD&#125;:/develop</code>,  this will mount the current directory of the host machine into the <code>develop</code> directory inside the container. If <code>develop</code> directory is not there, Docker will make it for you. </p><p><strong><em>Note</em></strong>: the current directory <code>pwd</code> command’s usage has some variants based on your host machine. The above command works for the <code>Powershell</code> of Windows, if you are using <code>git bash</code> on Windows, please try: </p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">-v /$(<span class="built_in">pwd</span>):/develop</span><br></pre></td></tr></table></figure><p>For Mac users, try the following: </p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">-v $(<span class="built_in">pwd</span>):/develop</span><br></pre></td></tr></table></figure><p>Now you can happily code your program in your familiar host machine, save the code change and sync them into the container. Then build and run your code inside the container with every dependency it needs. </p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;Why-develop-in-Docker-container&quot;&gt;&lt;a href=&quot;#Why-develop-in-Docker-container&quot; class=&quot;headerlink&quot; title=&quot;Why develop in Docker containe</summary>
      
    
    
    
    
    <category term="docker, c++, linux" scheme="https://baoqger.github.io/tags/docker-c-linux/"/>
    
  </entry>
  
  <entry>
    <title>Understand NgRx memoizedSelector in source code level</title>
    <link href="https://baoqger.github.io/2020/04/20/memoizedSelector/"/>
    <id>https://baoqger.github.io/2020/04/20/memoizedSelector/</id>
    <published>2020-04-20T12:15:50.000Z</published>
    <updated>2021-12-23T12:34:34.797Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Background"><a href="#Background" class="headerlink" title="Background"></a>Background</h3><p><code>Selector</code> is an essential part of the entire NgRx state management system, which is much more complicated than the <code>action</code> and <code>reducer</code> part based on my learning and development experience. Sometimes I feel it is like a black box, which hides many excellent designs and techniques. I spend some time and dig into the source code of NgRx to take a look at the internals of the black box. This post (and later posts) will share some interesting points I found during the process. </p><p>When using NgRx, developers always do something like this: </p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> <span class="attr">animalListState</span>: <span class="title class_">MemoizedSelector</span>&lt;<span class="title class_">State</span>, <span class="title class_">Animal</span>[]&gt; = <span class="title function_">createSelector</span>(</span><br><span class="line">  rootState,</span><br><span class="line">  (<span class="attr">state</span>: <span class="title class_">RootState</span>): <span class="function"><span class="params">AnimalListState</span> =&gt;</span> state.<span class="property">animalList</span></span><br><span class="line">);</span><br></pre></td></tr></table></figure><p><code>createSelector</code> method return a selector function, which can be passed into the <code>store.select()</code> method to get the desired state out of the store. </p><p>By default, the type of the returned function from <code>createSelector</code> is <code>MemoizedSelector&lt;State, Result&gt;</code>. Have you ever notice that? This post will introduce what it is and how it works. </p><h3 id="What-is-memoization"><a href="#What-is-memoization" class="headerlink" title="What is memoization?"></a>What is memoization?</h3><p>Memoization is a general concept in computer science. Wikipedia explains it as follows: </p><blockquote><p>In computing, memoization or memoisation is an optimization technique used primarily to speed up computer programs by storing the results of expensive function calls and returning the cached result when the same inputs occur again. </p></blockquote><p>You can find <a href="https://dev.to/carlillo/understanding-javascripttypescript-memoization-o7k">many articles</a> online for explaining memoization with code examples. Simply speaking, a hash map is used for the cached result. Technically it’s not difficult at all. </p><p>Memoization is a great optimization solution of pure function. Generally speaking, <code>A pure function is a function where the return value is only determined by its input values, without side effects</code>.</p><p>As you may know, <code>Selector</code> is a pure function. <code>memoizedSelector</code> is just a normal selector function with memoization optimization. Next, let’s see how it works in the design of the NgRx library.</p><h3 id="Source-code-of-memoizedSelector"><a href="#Source-code-of-memoizedSelector" class="headerlink" title="Source code of memoizedSelector"></a>Source code of memoizedSelector</h3><p>In the source code of <a href="https://github.com/ngrx/platform/blob/master/modules/store/src/selector.ts"><code>NgRx</code></a>, you can find the <code>selector</code> related code in the path of <code>platform/modules/store/src/selector.ts</code>.  </p><p><code>selector.ts</code> file is roughly 700 lines, which hold all the functionalities of it. There are many interesting points inside this module, which I can share in another article, but this post focus on memoization. So I pick up all the necessary code and put it as follows: </p><figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">type</span> <span class="title class_">AnyFn</span> = <span class="function">(<span class="params">...args: <span class="built_in">any</span>[]</span>) =&gt;</span> <span class="built_in">any</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">type</span> <span class="title class_">ComparatorFn</span> = <span class="function">(<span class="params">a: <span class="built_in">any</span>, b: <span class="built_in">any</span></span>) =&gt;</span> <span class="built_in">boolean</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">type</span> <span class="title class_">MemoizedProjection</span> = &#123;</span><br><span class="line">    <span class="attr">memoized</span>: <span class="title class_">AnyFn</span>;</span><br><span class="line">    <span class="attr">reset</span>: <span class="function">() =&gt;</span> <span class="built_in">void</span>;</span><br><span class="line">    <span class="attr">setResult</span>: <span class="function">(<span class="params">result?: <span class="built_in">any</span></span>) =&gt;</span> <span class="built_in">void</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">function</span> <span class="title function_">isEqualCheck</span>(<span class="params">a: <span class="built_in">any</span>, b: <span class="built_in">any</span></span>): <span class="built_in">boolean</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> a === b;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">isArgumentsChanged</span>(<span class="params"></span></span><br><span class="line"><span class="params">    args: IArguments,</span></span><br><span class="line"><span class="params">    lastArguments:IArguments,</span></span><br><span class="line"><span class="params">    comparator: ComparatorFn</span></span><br><span class="line"><span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; args.<span class="property">length</span> ; i++) &#123;</span><br><span class="line">        <span class="keyword">if</span> (!<span class="title function_">comparator</span>(args[i], lastArguments[i])) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">function</span> <span class="title function_">defaultMemoize</span>(<span class="params"></span></span><br><span class="line"><span class="params">    projectionFn: AnyFn,</span></span><br><span class="line"><span class="params">    isArgumentsEuqal = isEqualCheck,</span></span><br><span class="line"><span class="params">    isResultEqual = isEqualCheck</span></span><br><span class="line"><span class="params"></span>): <span class="title class_">MemoizedProjection</span> &#123;</span><br><span class="line">    <span class="keyword">let</span> <span class="attr">lastArguments</span>: <span class="literal">null</span> | <span class="title class_">IArguments</span> = <span class="literal">null</span>;</span><br><span class="line">    <span class="keyword">let</span> <span class="attr">lastResult</span>: <span class="built_in">any</span> = <span class="literal">null</span>;</span><br><span class="line">    <span class="keyword">let</span> <span class="attr">overrideResult</span>: <span class="built_in">any</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">reset</span>(<span class="params"></span>) &#123;</span><br><span class="line">        lastArguments = <span class="literal">null</span>;</span><br><span class="line">        lastResult = <span class="literal">null</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">setResult</span>(<span class="params">result: <span class="built_in">any</span> = <span class="literal">undefined</span></span>) &#123;</span><br><span class="line">        overrideResult = result;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">memoized</span>(<span class="params"></span>): <span class="built_in">any</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (overrideResult !== <span class="literal">undefined</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> overrideResult;</span><br><span class="line">        &#125; </span><br><span class="line">        <span class="keyword">if</span> (!lastArguments) &#123;</span><br><span class="line">            lastResult = projectionFn.<span class="title function_">apply</span>(<span class="literal">null</span>, <span class="variable language_">arguments</span> <span class="keyword">as</span> <span class="built_in">any</span>);</span><br><span class="line">            lastArguments = <span class="variable language_">arguments</span>;</span><br><span class="line">            <span class="keyword">return</span> lastResult;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (!<span class="title function_">isArgumentsChanged</span>(<span class="variable language_">arguments</span>, lastArguments, isArgumentsEuqal)) &#123;</span><br><span class="line">            <span class="keyword">return</span> lastResult;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">const</span> newResult = projectionFn.<span class="title function_">apply</span>(<span class="literal">null</span>, <span class="variable language_">arguments</span> <span class="keyword">as</span> <span class="built_in">any</span>);</span><br><span class="line">        lastArguments = <span class="variable language_">arguments</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (<span class="title function_">isResultEqual</span>(lastResult, newResult)) &#123;</span><br><span class="line">            <span class="keyword">return</span> lastResult;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        lastResult = newResult;</span><br><span class="line">        <span class="keyword">return</span> newResult;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> &#123; memoized, reset, setResult&#125;;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>There are many interesting Typescript stuff in the above code block. But for memoization, you can focus on the method <code>defaultMemoize</code>. In the following section, I will show you how it can make your program run faster. </p><h3 id="Explore-the-memoizedSelector-method"><a href="#Explore-the-memoizedSelector-method" class="headerlink" title="Explore the memoizedSelector method"></a>Explore the memoizedSelector method</h3><p>To show how memoization works, I create a simple method <code>slowFunction</code> as following, to simulate that a method running very slowly:  </p><figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">function</span> <span class="title function_">slowFunction</span>(<span class="params">val: <span class="built_in">number</span></span>): <span class="built_in">number</span> &#123;</span><br><span class="line">    <span class="keyword">const</span> pre = <span class="keyword">new</span> <span class="title class_">Date</span>();</span><br><span class="line">    <span class="keyword">while</span> (<span class="literal">true</span>) &#123;</span><br><span class="line">        <span class="keyword">const</span> now = <span class="keyword">new</span> <span class="title class_">Date</span>();</span><br><span class="line">        <span class="keyword">if</span> (now.<span class="title function_">valueOf</span>() - pre.<span class="title function_">valueOf</span>() &gt; <span class="number">2000</span>) &#123;</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> val;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>And then test it with the following scripts: </p><figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; defaultMemoize &#125; <span class="keyword">from</span> <span class="string">&quot;./memoizedSelector&quot;</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; slowFunction &#125; <span class="keyword">from</span> <span class="string">&quot;./slowFunction&quot;</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// run slowFunction without memoization</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;First call of slowFunction(2)&quot;</span>);</span><br><span class="line"><span class="keyword">let</span> pre = <span class="keyword">new</span> <span class="title class_">Date</span>();</span><br><span class="line"><span class="title function_">slowFunction</span>(<span class="number">2</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;It takes&quot;</span> + ((<span class="keyword">new</span> <span class="title class_">Date</span>()).<span class="title function_">valueOf</span>() - pre.<span class="title function_">valueOf</span>())/<span class="number">1000</span> +  <span class="string">&quot;seconds \n&quot;</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;Second call of slowFunction(2)&quot;</span>);</span><br><span class="line">pre = <span class="keyword">new</span> <span class="title class_">Date</span>();</span><br><span class="line"><span class="title function_">slowFunction</span>(<span class="number">2</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;It takes&quot;</span> + ((<span class="keyword">new</span> <span class="title class_">Date</span>()).<span class="title function_">valueOf</span>() - pre.<span class="title function_">valueOf</span>())/<span class="number">1000</span> +  <span class="string">&quot;seconds \n&quot;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// run slowFunction with memoization</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> fastFunction = <span class="title function_">defaultMemoize</span>(slowFunction);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;First call of fastFunction(2)&quot;</span>);</span><br><span class="line">pre = <span class="keyword">new</span> <span class="title class_">Date</span>();</span><br><span class="line">fastFunction.<span class="title function_">memoized</span>(<span class="number">2</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;It takes&quot;</span> + ((<span class="keyword">new</span> <span class="title class_">Date</span>()).<span class="title function_">valueOf</span>() - pre.<span class="title function_">valueOf</span>())/<span class="number">1000</span> +  <span class="string">&quot;seconds \n&quot;</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;Second call of fastFunction(2)&quot;</span>);</span><br><span class="line">pre = <span class="keyword">new</span> <span class="title class_">Date</span>();</span><br><span class="line">fastFunction.<span class="title function_">memoized</span>(<span class="number">2</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;It takes&quot;</span> + ((<span class="keyword">new</span> <span class="title class_">Date</span>()).<span class="title function_">valueOf</span>() - pre.<span class="title function_">valueOf</span>())/<span class="number">1000</span> +  <span class="string">&quot;seconds \n&quot;</span>);</span><br></pre></td></tr></table></figure><p>The output goes as folllowing:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">$ ts-node index.ts</span><br><span class="line">First call of slowFunction(2)</span><br><span class="line">It takes2.001seconds</span><br><span class="line"></span><br><span class="line">Second call of slowFunction(2)</span><br><span class="line">It takes2.001seconds</span><br><span class="line"></span><br><span class="line">First call of fastFunction(2)</span><br><span class="line">It takes2.002seconds</span><br><span class="line"></span><br><span class="line">Second call of fastFunction(2)</span><br><span class="line">It takes0.001seconds</span><br></pre></td></tr></table></figure><p>Compared with the original <code>slowFunction</code> method, the memoized method <code>fastFunction</code> can directly output the result for the same input. That’s the power of memoization, hope you can master it. </p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;Background&quot;&gt;&lt;a href=&quot;#Background&quot; class=&quot;headerlink&quot; title=&quot;Background&quot;&gt;&lt;/a&gt;Background&lt;/h3&gt;&lt;p&gt;&lt;code&gt;Selector&lt;/code&gt; is an essential </summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>Typical usage case of Marble Testing for RxJS</title>
    <link href="https://baoqger.github.io/2020/04/12/rxjs-marble-testing/"/>
    <id>https://baoqger.github.io/2020/04/12/rxjs-marble-testing/</id>
    <published>2020-04-12T12:08:45.000Z</published>
    <updated>2021-12-23T12:34:34.798Z</updated>
    
    <content type="html"><![CDATA[<h3 id="What’s-Marble-Testing"><a href="#What’s-Marble-Testing" class="headerlink" title="What’s Marble Testing"></a>What’s Marble Testing</h3><p>RxJS is a powerful tool to handle various asynchronous tasks. Sometime RxJS observables are hard to test. In the community, there is one particular unit testing solution for RxJS observables called marble testing.</p><p>For marble testing, you can refer to <a href="https://medium.com/@bencabanes/marble-testing-observable-introduction-1f5ad39231c">these articles</a>. They all do an excellent job of introducing what it is. </p><h3 id="A-real-case-to-show-Marble-Testing’s-power"><a href="#A-real-case-to-show-Marble-Testing’s-power" class="headerlink" title="A real case to show Marble Testing’s power"></a>A real case to show Marble Testing’s power</h3><p>Recently in my development work, I came across a case where I used marble testing properly to solve the issue. </p><p>The background is for my application in the root <code>index.html</code> file, there is one third-party javascript library/SDK. For some business reasons, after the third-party library is loaded, we bind some value to the global <code>window</code> object. </p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable language_">window</span>.<span class="property">onSecretLibraryLoad</span> = <span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="variable language_">window</span>.<span class="property">SecretLibrary</span> = res; </span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>Before the loaded event is triggered, the <code>window.SecretLibary</code> was <code>undefiend</code>. After the event is triggered, it will be assigned some value. </p><p>This global value is vital for my application since one of the UI components depends on it to determine to show or hide. </p><p>Since the script was loaded with <code>async</code> flag for performance consideration, this component needs to check the <code>window.SecretLibrary</code> value repeatedly. </p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> <span class="title class_">UIComponent</span> implements <span class="title class_">OnInit</span> &#123;</span><br><span class="line">    public <span class="attr">isSecretLibraryReady$</span>: <span class="title class_">Observable</span>&lt;boolean&gt;;</span><br><span class="line">    public <span class="title function_">ngOnInit</span>(): <span class="keyword">void</span> &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">isSecretLibraryReady$</span> = <span class="variable language_">this</span>.<span class="title function_">getSecretLibraryLoadStatus</span>();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public <span class="title function_">getSecretLibraryLoadStatus</span>(): <span class="title class_">Observable</span>&lt;boolean&gt; &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="title function_">timer</span>(<span class="number">0</span>, <span class="number">500</span>).<span class="title function_">pipe</span>(</span><br><span class="line">            <span class="title function_">map</span>(<span class="function">(<span class="params">t</span>) =&gt;</span> (&#123;</span><br><span class="line">                <span class="attr">currentTimeTick</span>: t,</span><br><span class="line">                <span class="attr">isReady</span>: <span class="title class_">Boolean</span>((<span class="variable language_">window</span> <span class="keyword">as</span> any).<span class="property">SecretLibrary</span>)</span><br><span class="line">            &#125;)),</span><br><span class="line">            <span class="title function_">takeWhile</span>(</span><br><span class="line">                <span class="function">(<span class="params">val</span>) =&gt;</span> !val.<span class="property">isReady</span> &amp;&amp; val.<span class="property">currentTimeTick</span> &lt;= <span class="number">30000</span>/<span class="number">500</span>,</span><br><span class="line">                <span class="literal">true</span></span><br><span class="line">            ),</span><br><span class="line">            <span class="title function_">pluck</span>(<span class="string">&quot;isReady&quot;</span>)</span><br><span class="line">        );</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>The interesting part comes from the <code>getSecretLibraryLoadStatus</code> function. It utilizes the <code>timer</code>, <code>map</code>, <code>takeWhile</code>, and <code>pluck</code> operators of RxJS library to realize the repeatedly status checking and updating purpose. </p><p>RxJS operator is not this article’s topic, so I will not dig deep into it. Just add one comment for the <code>takeWhile</code> part, which seems a little hard to understand at the first look. It defines two conditions to stop the observable: first case is the <code>window.SecretLibrary</code> value is not undefined, which means the script is loaded; the second case is it reaches the maximum time limit (30 seconds). </p><h3 id="How-to-test-it-marble-testing"><a href="#How-to-test-it-marble-testing" class="headerlink" title="How to test it: marble testing"></a>How to test it: marble testing</h3><p>Traditionally we use <code>subscribe and assert</code> pattern to test RxJS observables. But for the case, as mentioned above: time-based observables, the traditional solution can’t handle it well. We can’t wait 30 seconds when we run the unit tests during local development or in CI pipeline. That’s unacceptable.</p><p>Marble testing can fix this issue correctly by the concept of virtual time. For what is virtual time, you can refer to <a href="https://medium.com/angular-in-depth/how-to-test-observables-a00038c7faad">these great articles</a>. I will not discuss it at a detailed level in this post. Simply speaking, virtual time empowers us to test asynchronous RxJS observable synchronously. In virtual time asynchronous functions like <code>setTimeout</code> and <code>setInterval</code> will use fake time instead of actual time. And the magic comes from the <code>TestScheduler</code> of RxJS. </p><p>The marble testing solution as following: </p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="title function_">describe</span>(<span class="string">&quot;UIComponent&quot;</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">let</span> <span class="attr">component</span>: <span class="title class_">UIComponent</span>;</span><br><span class="line">  <span class="keyword">let</span> <span class="attr">fixture</span>: <span class="title class_">ComponentFixture</span>&lt;<span class="title class_">UIComponent</span>&gt;;</span><br><span class="line">  <span class="keyword">let</span> <span class="attr">scheduler</span>: <span class="title class_">TestScheduler</span>;</span><br><span class="line"></span><br><span class="line">  <span class="title function_">beforeEach</span>(<span class="title function_">async</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">    <span class="title class_">TestBed</span>.<span class="title function_">configureTestingModule</span>(&#123;</span><br><span class="line">      <span class="attr">declarations</span>: [<span class="title class_">UIComponent</span>],</span><br><span class="line">    &#125;).<span class="title function_">compileComponents</span>();</span><br><span class="line">  &#125;));</span><br><span class="line"></span><br><span class="line">  <span class="title function_">beforeEach</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">    fixture = <span class="title class_">TestBed</span>.<span class="title function_">createComponent</span>(<span class="title class_">UIComponent</span>);</span><br><span class="line">    component = fixture.<span class="property">componentInstance</span>;</span><br><span class="line">    scheduler = <span class="keyword">new</span> <span class="title class_">TestScheduler</span>(<span class="function">(<span class="params">actual, expected</span>) =&gt;</span> <span class="title function_">expect</span>(actual).<span class="title function_">toEqual</span>(expected));</span><br><span class="line">    (<span class="variable language_">window</span> <span class="keyword">as</span> any).<span class="property">SecretLibrary</span> = <span class="literal">undefined</span>;</span><br><span class="line">  &#125;);</span><br><span class="line"></span><br><span class="line">  <span class="title function_">it</span>(<span class="string">&quot;getSecretLibraryLoadStatus method should return a boolean observable stream, for script load success case&quot;</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">    scheduler.<span class="title function_">run</span>(<span class="function">(<span class="params">&#123; expectObservable &#125;</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="title function_">timer</span>(<span class="number">2</span> * <span class="number">1000</span>).<span class="title function_">subscribe</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">        (<span class="variable language_">window</span> <span class="keyword">as</span> any).<span class="property">SecretLibrary</span> = <span class="string">&quot;SecretLibrary&quot;</span>;</span><br><span class="line">      &#125;);</span><br><span class="line">      <span class="comment">// tricky point about marble test: a, b, c these placeholders account 1 frame of virtual time</span></span><br><span class="line">      <span class="title function_">expectObservable</span>(component.<span class="title function_">getSecretLibraryLoadStatus</span>()).<span class="title function_">toBe</span>(</span><br><span class="line">        <span class="string">&quot;a 499ms b 499ms c 499ms d 499ms (e|)&quot;</span>,</span><br><span class="line">        &#123;</span><br><span class="line">          <span class="attr">a</span>: <span class="literal">false</span>,</span><br><span class="line">          <span class="attr">b</span>: <span class="literal">false</span>,</span><br><span class="line">          <span class="attr">c</span>: <span class="literal">false</span>,</span><br><span class="line">          <span class="attr">d</span>: <span class="literal">false</span>,</span><br><span class="line">          <span class="attr">e</span>: <span class="literal">true</span></span><br><span class="line">        &#125;</span><br><span class="line">      );</span><br><span class="line">    &#125;);</span><br><span class="line">  &#125;);</span><br><span class="line">&#125;);</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>Let me emphasize several key points to understand the above testing case. <code>getSecretLibraryLoadStatus</code> will repeatedly check the status of <code>window.SecretLibrary</code> every 500 milliseconds and return a boolean value stream. </p><p>I manually set the <code>window.SecretLibrary</code> value after 2 seconds by calling this: </p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="title function_">timer</span>(<span class="number">2</span> * <span class="number">1000</span>).<span class="title function_">subscribe</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">  (<span class="variable language_">window</span> <span class="keyword">as</span> any).<span class="property">SecretLibrary</span> = <span class="string">&quot;SecretLibrary&quot;</span>;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>So Let’s imagine what the result should be: the first four emit value will be <code>false</code>,  and the last value is <code>true</code>. That’s the expected observable. </p><p>But please notice that <code>scheduler.run</code>, everything run inside the callback will use virtual time. So we didn’t wait 2 seconds for the <code>timer</code> operator. Instead, it runs synchronously. </p><p>The second point needs to notice is the syntax of the marble string <code>a 499ms b 499ms c 499ms d 499ms (e|)</code>. Yes, it looks a little wired, but be careful that’s the correct way to represent marble. <strong>The alphanumeric values represent an actual emitted value, which advances time one virtual frame</strong>.</p><p>Here I only show the case where the third-party script load successfully. Of course, to have full testing coverage, we need to consider the negative case where the script failed to load. You can figure it out. </p><h3 id="Summary"><a href="#Summary" class="headerlink" title="Summary"></a>Summary</h3><p>In this post, I didn’t go into the detailed syntax of marble testing. I think the reader can find the related document easily. I record a real usage case in the development where marble testing can show its power to handle async observables. </p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;What’s-Marble-Testing&quot;&gt;&lt;a href=&quot;#What’s-Marble-Testing&quot; class=&quot;headerlink&quot; title=&quot;What’s Marble Testing&quot;&gt;&lt;/a&gt;What’s Marble Testing&lt;/</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>algo-part2</title>
    <link href="https://baoqger.github.io/2020/04/11/algo-part2/"/>
    <id>https://baoqger.github.io/2020/04/11/algo-part2/</id>
    <published>2020-04-11T13:00:20.000Z</published>
    <updated>2024-08-30T08:45:41.583Z</updated>
    
    <content type="html"><![CDATA[<h2 id="Part-2"><a href="#Part-2" class="headerlink" title="Part 2"></a>Part 2</h2><h3 id="Circular-List"><a href="#Circular-List" class="headerlink" title="Circular List"></a>Circular List</h3><p>Judge a linked list is circular or not</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">circular</span>(<span class="params">list</span>) &#123;</span><br><span class="line">  <span class="keyword">let</span> slow = list.<span class="title function_">getFirst</span>();</span><br><span class="line">  <span class="keyword">let</span> fast = list.<span class="title function_">getFirst</span>();</span><br><span class="line"></span><br><span class="line">  <span class="keyword">while</span> (fast.<span class="property">next</span> &amp;&amp; fast.<span class="property">next</span>.<span class="property">next</span>) &#123;</span><br><span class="line">    slow = slow.<span class="property">next</span>;</span><br><span class="line">    fast = fast.<span class="property">next</span>.<span class="property">next</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (slow === fast) &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="Tree"><a href="#Tree" class="headerlink" title="Tree"></a>Tree</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Node</span> &#123;</span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params">data</span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">data</span> = data;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">children</span> = [];</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="title function_">add</span>(<span class="params">data</span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">children</span>.<span class="title function_">push</span>(<span class="keyword">new</span> <span class="title class_">Node</span>(data));</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="title function_">remove</span>(<span class="params">data</span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">children</span> = <span class="variable language_">this</span>.<span class="property">children</span>.<span class="title function_">filter</span>(<span class="function"><span class="params">node</span> =&gt;</span> &#123;</span><br><span class="line">      <span class="keyword">return</span> node.<span class="property">data</span> !== data;</span><br><span class="line">    &#125;);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Tree</span> &#123;</span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">root</span> = <span class="literal">null</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="comment">// 广度优先</span></span><br><span class="line">  <span class="title function_">traverseBF</span>(<span class="params">fn</span>) &#123;</span><br><span class="line">    <span class="comment">// 初始化一个数组</span></span><br><span class="line">    <span class="keyword">const</span> arr = [<span class="variable language_">this</span>.<span class="property">root</span>];</span><br><span class="line">    <span class="comment">// 循环判断</span></span><br><span class="line">    <span class="keyword">while</span> (arr.<span class="property">length</span>) &#123;</span><br><span class="line">      <span class="comment">// 取得头部的元素</span></span><br><span class="line">      <span class="keyword">const</span> node = arr.<span class="title function_">shift</span>();</span><br><span class="line">      <span class="comment">// 把头部元素的children push到array里</span></span><br><span class="line">      arr.<span class="title function_">push</span>(...node.<span class="property">children</span>);</span><br><span class="line">      <span class="title function_">fn</span>(node);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="comment">// 深度优先</span></span><br><span class="line">  <span class="title function_">traverseDF</span>(<span class="params">fn</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> arr = [<span class="variable language_">this</span>.<span class="property">root</span>];</span><br><span class="line">    <span class="keyword">while</span> (arr.<span class="property">length</span>) &#123;</span><br><span class="line">      <span class="keyword">const</span> node = arr.<span class="title function_">shift</span>();</span><br><span class="line"></span><br><span class="line">      arr.<span class="title function_">unshift</span>(...node.<span class="property">children</span>);</span><br><span class="line">      <span class="title function_">fn</span>(node);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="variable language_">module</span>.<span class="property">exports</span> = &#123; <span class="title class_">Tree</span>, <span class="title class_">Node</span> &#125;;</span><br></pre></td></tr></table></figure><h3 id="Tree-level-width"><a href="#Tree-level-width" class="headerlink" title="Tree level width"></a>Tree level width</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="title class_">Given</span> the root node <span class="keyword">of</span> a tree, <span class="keyword">return</span></span><br><span class="line">an array where each element is the width</span><br><span class="line"><span class="keyword">of</span> the tree at each level.</span><br><span class="line">--- <span class="title class_">Example</span></span><br><span class="line"><span class="title class_">Given</span>:</span><br><span class="line">    <span class="number">0</span></span><br><span class="line">  / |  \</span><br><span class="line"><span class="number">1</span>   <span class="number">2</span>   <span class="number">3</span></span><br><span class="line">|       |</span><br><span class="line"><span class="number">4</span>       <span class="number">5</span></span><br><span class="line"><span class="title class_">Answer</span>: [<span class="number">1</span>, <span class="number">3</span>, <span class="number">2</span>]</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>solution: </p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">levelWidth</span>(<span class="params">root</span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> arr = [root, <span class="string">&#x27;s&#x27;</span>];</span><br><span class="line">  <span class="keyword">const</span> counters = [<span class="number">0</span>];</span><br><span class="line"></span><br><span class="line">  <span class="keyword">while</span> (arr.<span class="property">length</span> &gt; <span class="number">1</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> node = arr.<span class="title function_">shift</span>();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (node === <span class="string">&#x27;s&#x27;</span>) &#123;</span><br><span class="line">      counters.<span class="title function_">push</span>(<span class="number">0</span>);</span><br><span class="line">      arr.<span class="title function_">push</span>(<span class="string">&#x27;s&#x27;</span>);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      arr.<span class="title function_">push</span>(...node.<span class="property">children</span>);</span><br><span class="line">      counters[counters.<span class="property">length</span> - <span class="number">1</span>]++;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> counters;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="Events"><a href="#Events" class="headerlink" title="Events"></a>Events</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// --- Directions</span></span><br><span class="line"><span class="comment">// Create an &#x27;eventing&#x27; library out of the</span></span><br><span class="line"><span class="comment">// Events class.  The Events class should</span></span><br><span class="line"><span class="comment">// have methods &#x27;on&#x27;, &#x27;trigger&#x27;, and &#x27;off&#x27;.</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Events</span> &#123;</span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">events</span> = &#123;&#125;;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// Register an event handler</span></span><br><span class="line">  <span class="title function_">on</span>(<span class="params">eventName, callback</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">events</span>[eventName]) &#123;</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">events</span>[eventName].<span class="title function_">push</span>(callback);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">events</span>[eventName] = [callback];</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// Trigger all callbacks associated</span></span><br><span class="line">  <span class="comment">// with a given eventName</span></span><br><span class="line">  <span class="title function_">trigger</span>(<span class="params">eventName</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">events</span>[eventName]) &#123;</span><br><span class="line">      <span class="keyword">for</span> (<span class="keyword">let</span> cb <span class="keyword">of</span> <span class="variable language_">this</span>.<span class="property">events</span>[eventName]) &#123;</span><br><span class="line">        <span class="title function_">cb</span>();</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// Remove all event handlers associated</span></span><br><span class="line">  <span class="comment">// with the given eventName</span></span><br><span class="line">  <span class="title function_">off</span>(<span class="params">eventName</span>) &#123;</span><br><span class="line">    <span class="keyword">delete</span> <span class="variable language_">this</span>.<span class="property">events</span>[eventName];</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="Binary-Search-Tree"><a href="#Binary-Search-Tree" class="headerlink" title="Binary Search Tree"></a>Binary Search Tree</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 1) Implement the Node class to create</span></span><br><span class="line"><span class="comment">// a binary search tree.  The constructor</span></span><br><span class="line"><span class="comment">// should initialize values &#x27;data&#x27;, &#x27;left&#x27;,</span></span><br><span class="line"><span class="comment">// and &#x27;right&#x27;.</span></span><br><span class="line"><span class="comment">// 2) Implement the &#x27;insert&#x27; method for the</span></span><br><span class="line"><span class="comment">// Node class.  Insert should accept an argument</span></span><br><span class="line"><span class="comment">// &#x27;data&#x27;, then create an insert a new node</span></span><br><span class="line"><span class="comment">// at the appropriate location in the tree.</span></span><br><span class="line"><span class="comment">// 3) Implement the &#x27;contains&#x27; method for the Node</span></span><br><span class="line"><span class="comment">// class.  Contains should accept a &#x27;data&#x27; argument</span></span><br><span class="line"><span class="comment">// and return the Node in the tree with the same value.</span></span><br><span class="line"><span class="comment">// If the value isn&#x27;t in the tree return null.</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Node</span> &#123;</span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params">data</span>) &#123;</span><br><span class="line">    <span class="comment">// 每个node三个属性</span></span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">data</span> = data;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">left</span> = <span class="literal">null</span>;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">right</span> = <span class="literal">null</span>;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="title function_">insert</span>(<span class="params">data</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (data &lt; <span class="variable language_">this</span>.<span class="property">data</span> &amp;&amp; <span class="variable language_">this</span>.<span class="property">left</span>) &#123;</span><br><span class="line">      <span class="comment">//对left子节点的递归insert</span></span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">left</span>.<span class="title function_">insert</span>(data);</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (data &lt; <span class="variable language_">this</span>.<span class="property">data</span>) &#123;</span><br><span class="line">      <span class="comment">// 赋值给left子节点</span></span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">left</span> = <span class="keyword">new</span> <span class="title class_">Node</span>(data);</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (data &gt; <span class="variable language_">this</span>.<span class="property">data</span> &amp;&amp; <span class="variable language_">this</span>.<span class="property">right</span>) &#123;</span><br><span class="line">      <span class="comment">//对right子节点的递归insert</span></span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">right</span>.<span class="title function_">insert</span>(data);</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (data &gt; <span class="variable language_">this</span>.<span class="property">data</span>) &#123;</span><br><span class="line">      <span class="comment">// 赋值给right子节点</span></span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">right</span> = <span class="keyword">new</span> <span class="title class_">Node</span>(data);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="title function_">contains</span>(<span class="params">data</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">data</span> === data) &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="variable language_">this</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">data</span> &lt; data &amp;&amp; <span class="variable language_">this</span>.<span class="property">right</span>) &#123;</span><br><span class="line">      <span class="comment">// right子节点的contains操作</span></span><br><span class="line">      <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">right</span>.<span class="title function_">contains</span>(data);</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">data</span> &gt; data &amp;&amp; <span class="variable language_">this</span>.<span class="property">left</span>) &#123;</span><br><span class="line">      <span class="comment">// left子节点的contains操作</span></span><br><span class="line">      <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">left</span>.<span class="title function_">contains</span>(data);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="Validate-the-Binary-Search-Tree"><a href="#Validate-the-Binary-Search-Tree" class="headerlink" title="Validate the Binary Search Tree"></a>Validate the Binary Search Tree</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">validate</span>(<span class="params">node, min = <span class="literal">null</span>, max = <span class="literal">null</span></span>) &#123;</span><br><span class="line">  <span class="keyword">if</span> (max !== <span class="literal">null</span> &amp;&amp; node.<span class="property">data</span> &gt; max) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">if</span> (min !== <span class="literal">null</span> &amp;&amp; node.<span class="property">data</span> &lt; min) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">if</span> (node.<span class="property">left</span> &amp;&amp; !<span class="title function_">validate</span>(node.<span class="property">left</span>, min, node.<span class="property">data</span>)) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">if</span> (node.<span class="property">right</span> &amp;&amp; !<span class="title function_">validate</span>(node.<span class="property">right</span>, node.<span class="property">data</span>, max)) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="BubbleSort"><a href="#BubbleSort" class="headerlink" title="BubbleSort"></a>BubbleSort</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">bubbleSort</span>(<span class="params">arr</span>) &#123;</span><br><span class="line">  <span class="comment">// Implement bubblesort</span></span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; arr.<span class="property">length</span>; i++) &#123;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> j = <span class="number">0</span>; j &lt; (arr.<span class="property">length</span> - i - <span class="number">1</span>); j++) &#123;</span><br><span class="line">      <span class="keyword">if</span> (arr[j] &gt; arr[j+<span class="number">1</span>]) &#123;</span><br><span class="line">        <span class="keyword">const</span> lesser = arr[j+<span class="number">1</span>];</span><br><span class="line">        arr[j+<span class="number">1</span>] = arr[j];</span><br><span class="line">        arr[j] = lesser;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// return the sorted array</span></span><br><span class="line">  <span class="keyword">return</span> arr;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="Selection-Sort"><a href="#Selection-Sort" class="headerlink" title="Selection Sort"></a>Selection Sort</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">selectionSort</span>(<span class="params">arr</span>) &#123;</span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; arr.<span class="property">length</span>; i++) &#123;</span><br><span class="line">    <span class="keyword">let</span> indexOfMin = i;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> j = i+<span class="number">1</span>; j &lt;arr.<span class="property">length</span>; j++) &#123;</span><br><span class="line">      <span class="keyword">if</span> (arr[j] &lt; arr[indexOfMin]) &#123;</span><br><span class="line">        indexOfMin = j;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (indexOfMin !== i) &#123;</span><br><span class="line">      <span class="keyword">let</span> lesser = arr[indexOfMin];</span><br><span class="line">      arr[indexOfMin] = arr[i];</span><br><span class="line">      arr[i] = lesser;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> arr;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="Merge-Sort"><a href="#Merge-Sort" class="headerlink" title="Merge Sort"></a>Merge Sort</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">mergeSort</span>(<span class="params">arr</span>) &#123;</span><br><span class="line">  <span class="keyword">if</span> (arr.<span class="property">length</span> === <span class="number">1</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> arr;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">const</span> center = <span class="title class_">Math</span>.<span class="title function_">floor</span>(arr.<span class="property">length</span> / <span class="number">2</span>);</span><br><span class="line">  <span class="keyword">const</span> left = arr.<span class="title function_">slice</span>(<span class="number">0</span>, center);</span><br><span class="line">  <span class="keyword">const</span> right = arr.<span class="title function_">slice</span>(center);</span><br><span class="line">  <span class="comment">// 神奇的递归</span></span><br><span class="line">  <span class="keyword">return</span> <span class="title function_">merge</span>(<span class="title function_">mergeSort</span>(left), <span class="title function_">mergeSort</span>(right));</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 辅助函数merge，能够把两个已经排序的left和right数组，整合排序为一个array</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">merge</span>(<span class="params">left, right</span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> results = [];</span><br><span class="line"></span><br><span class="line">  <span class="keyword">while</span> (left.<span class="property">length</span> &amp;&amp; right.<span class="property">length</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (left[<span class="number">0</span>] &lt; right[<span class="number">0</span>]) &#123;</span><br><span class="line">      results.<span class="title function_">push</span>(left.<span class="title function_">shift</span>());</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      results.<span class="title function_">push</span>(right.<span class="title function_">shift</span>());</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="comment">// 到这行的时候，left和right，至少有一个是空的了，所以不用纠结left和right的前后位置了。</span></span><br><span class="line">  <span class="keyword">return</span> [...results, ...left, ...right];</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="binary-Gap"><a href="#binary-Gap" class="headerlink" title="binary Gap"></a>binary Gap</h3><p>A binary gap within a positive integer N is any maximal sequence of consecutive zeros that is surrounded by ones at both ends in the binary representation of N.</p><p>For example, number 9 has binary representation 1001 and contains a binary gap of length 2. The number 529 has binary representation 1000010001 and contains two binary gaps: one of length 4 and one of length 3. The number 20 has binary representation 10100 and contains one binary gap of length 1. The number 15 has binary representation 1111 and has no binary gaps. The number 32 has binary representation 100000 and has no binary gaps.</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">binaryGap</span>(<span class="params">num</span>) &#123;</span><br><span class="line">  <span class="keyword">let</span> str = num.<span class="title function_">toString</span>(<span class="number">2</span>).<span class="title function_">split</span>(<span class="string">&#x27;&#x27;</span>)</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(str)</span><br><span class="line">  <span class="keyword">let</span> counter = <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">let</span> max = <span class="number">0</span>;</span><br><span class="line">  str.<span class="title function_">forEach</span>(<span class="function">(<span class="params">char</span>) =&gt;</span>  &#123;</span><br><span class="line">    <span class="keyword">if</span> (char === <span class="string">&#x27;0&#x27;</span>) &#123;</span><br><span class="line">      counter ++;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      <span class="keyword">if</span> (counter &gt; max) &#123;</span><br><span class="line">        max = counter;</span><br><span class="line">      &#125;</span><br><span class="line">      counter = <span class="number">0</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// console.log(counter)</span></span><br><span class="line">  &#125;);</span><br><span class="line">  <span class="keyword">return</span> max;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="Bug-and-Sell-Stock"><a href="#Bug-and-Sell-Stock" class="headerlink" title="Bug and Sell Stock"></a>Bug and Sell Stock</h3><p>You will be given a list of stock prices for a given day and your goal is to return the maximum profit that could have been made by buying a stock at the given price and then selling the stock later on. For example if the input is: [45, 24, 35, 31, 40, 38, 11] then your program should return 16 because if you bought the stock at $24 and sold it at $40, a profit of $16 was made and this is the largest profit that could be made. If no profit could have been made, return -1.</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">getMaxProfit</span>(<span class="params">arr</span>) &#123;</span><br><span class="line">  <span class="keyword">var</span> minIdx = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">var</span> maxIdx = <span class="number">1</span>;</span><br><span class="line">    <span class="keyword">var</span> currMin = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">var</span> maxProfit = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span>(arr.<span class="property">length</span> &lt; <span class="number">2</span>) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&quot;Need atleast two time periods to be profitable!&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span>(<span class="keyword">var</span> i = <span class="number">1</span>; i &lt; arr.<span class="property">length</span>; i++) &#123;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// new current min.</span></span><br><span class="line">        <span class="keyword">if</span>(arr[i] &lt; arr[currMin]) &#123;</span><br><span class="line">          currMin = i;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// new best profit</span></span><br><span class="line">        <span class="keyword">if</span>(arr[maxIdx] - arr[minIdx] &lt; arr[i] - arr[currMin]) &#123;</span><br><span class="line">                maxIdx = i;</span><br><span class="line">              minIdx = currMin;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    maxProfit  = arr[maxIdx] - arr[minIdx];</span><br><span class="line">    <span class="keyword">return</span> maxProfit;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;Part-2&quot;&gt;&lt;a href=&quot;#Part-2&quot; class=&quot;headerlink&quot; title=&quot;Part 2&quot;&gt;&lt;/a&gt;Part 2&lt;/h2&gt;&lt;h3 id=&quot;Circular-List&quot;&gt;&lt;a href=&quot;#Circular-List&quot; class=&quot;he</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>algo-part1</title>
    <link href="https://baoqger.github.io/2020/04/10/algo-part1/"/>
    <id>https://baoqger.github.io/2020/04/10/algo-part1/</id>
    <published>2020-04-10T13:00:20.000Z</published>
    <updated>2024-08-30T08:45:33.625Z</updated>
    
    <content type="html"><![CDATA[<p>The Coding Interview Bootcamp: Data structure and algorithm.</p><h2 id="Part-1"><a href="#Part-1" class="headerlink" title="Part 1"></a>Part 1</h2><h3 id="String-Reverse"><a href="#String-Reverse" class="headerlink" title="String Reverse"></a>String Reverse</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">reverse</span>(<span class="params">str</span>) &#123;</span><br><span class="line">  <span class="keyword">return</span> str.<span class="title function_">split</span>(<span class="string">&#x27;&#x27;</span>).<span class="title function_">reduce</span>(<span class="function">(<span class="params">rev, char</span>) =&gt;</span> char + rev, <span class="string">&#x27;&#x27;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="Paldinromes"><a href="#Paldinromes" class="headerlink" title="Paldinromes"></a>Paldinromes</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">palindrome</span>(<span class="params">str</span>) &#123;</span><br><span class="line">  <span class="keyword">return</span> str.<span class="title function_">split</span>(<span class="string">&#x27;&#x27;</span>).<span class="title function_">every</span>(<span class="function">(<span class="params">char, i</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> char === str[str.<span class="property">length</span> - i - <span class="number">1</span>];</span><br><span class="line">  &#125;);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>another way is based on recursive method:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">palindromeRecursive</span>(<span class="params">str</span>) &#123;</span><br><span class="line">  <span class="keyword">if</span> (str.<span class="property">length</span> &lt;= <span class="number">1</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">  &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (str[<span class="number">0</span>] !== str[str.<span class="property">length</span> - <span class="number">1</span>]) &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="title function_">palindromeRecursive</span>(str.<span class="title function_">substring</span>(<span class="number">1</span>, str.<span class="property">length</span> - <span class="number">1</span>))</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="Longest-Paldinromes-substring"><a href="#Longest-Paldinromes-substring" class="headerlink" title="Longest Paldinromes substring"></a>Longest Paldinromes substring</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">longestPalin</span>(<span class="params">str</span>) &#123;</span><br><span class="line">  str = <span class="title function_">treatStr</span>(str);</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(str)</span><br><span class="line">  <span class="keyword">let</span> max =  <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">let</span> i  = <span class="number">1</span>; i &lt; str.<span class="property">length</span> - <span class="number">1</span>; i++) &#123;</span><br><span class="line">    <span class="keyword">let</span> radius = <span class="title class_">Math</span>.<span class="property">min</span> (i, str.<span class="property">length</span> - i - <span class="number">1</span>);</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(radius)</span><br><span class="line">    <span class="keyword">let</span> currentMax = <span class="title function_">getMaxSubLength</span>(str, i, radius);</span><br><span class="line">    <span class="keyword">if</span> (max &lt; currentMax) &#123;</span><br><span class="line">      max = currentMax + <span class="number">1</span>;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> max;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">getMaxSubLength</span>(<span class="params">str, i, radius</span>) &#123;</span><br><span class="line">  <span class="keyword">let</span> max = <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">let</span> j = <span class="number">0</span>; j &lt;= radius; j++) &#123;</span><br><span class="line">    <span class="keyword">if</span> (str[i - j] === str[i + j]) &#123;</span><br><span class="line">      max = j;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      <span class="keyword">break</span>;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> max;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">treatStr</span>(<span class="params">str</span>) &#123;</span><br><span class="line">  <span class="keyword">let</span> rtn = <span class="string">&#x27;&#x27;</span>;</span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; str.<span class="property">length</span>; i++) &#123;</span><br><span class="line">    <span class="keyword">if</span> (i === str.<span class="property">length</span> - <span class="number">1</span>) &#123;</span><br><span class="line">      rtn = rtn + str[i];</span><br><span class="line">    &#125; <span class="keyword">else</span>  &#123;</span><br><span class="line">      rtn = rtn + str[i] + <span class="string">&#x27;#&#x27;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> rtn;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="Integer-Reversal"><a href="#Integer-Reversal" class="headerlink" title="Integer Reversal"></a>Integer Reversal</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// --- Directions</span></span><br><span class="line"><span class="comment">// Given an integer, return an integer that is the reverse</span></span><br><span class="line"><span class="comment">// ordering of numbers.</span></span><br><span class="line"><span class="comment">// --- Examples</span></span><br><span class="line"><span class="comment">//   reverseInt(15) === 51</span></span><br><span class="line"><span class="comment">//   reverseInt(981) === 189</span></span><br><span class="line"><span class="comment">//   reverseInt(500) === 5</span></span><br><span class="line"><span class="comment">//   reverseInt(-15) === -51</span></span><br><span class="line"><span class="comment">//   reverseInt(-90) === -9</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">reverseInt</span>(<span class="params">n</span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> reversed = n</span><br><span class="line">    .<span class="title function_">toString</span>()</span><br><span class="line">    .<span class="title function_">split</span>(<span class="string">&#x27;&#x27;</span>)</span><br><span class="line">    .<span class="title function_">reverse</span>()</span><br><span class="line">    .<span class="title function_">join</span>(<span class="string">&#x27;&#x27;</span>);</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">parseInt</span>(reversed) * <span class="title class_">Math</span>.<span class="title function_">sign</span>(n);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="Anagrams"><a href="#Anagrams" class="headerlink" title="Anagrams"></a>Anagrams</h3><p>method1</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">anagrams</span>(<span class="params">stringA, stringB</span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> aCharMap = <span class="title function_">buildCharMap</span>(stringA);</span><br><span class="line">  <span class="keyword">const</span> bCharMap = <span class="title function_">buildCharMap</span>(stringB);</span><br><span class="line"></span><br><span class="line">  <span class="keyword">if</span> (<span class="title class_">Object</span>.<span class="title function_">keys</span>(aCharMap).<span class="property">length</span> !== <span class="title class_">Object</span>.<span class="title function_">keys</span>(bCharMap).<span class="property">length</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">let</span> char <span class="keyword">in</span> aCharMap) &#123;</span><br><span class="line">    <span class="keyword">if</span> (aCharMap[char] !== bCharMap[char]) &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">buildCharMap</span>(<span class="params">str</span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> charMap = &#123;&#125;;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">let</span> char <span class="keyword">of</span> str.<span class="title function_">replace</span>(<span class="regexp">/[^\w]/g</span>, <span class="string">&#x27;&#x27;</span>).<span class="title function_">toLowerCase</span>()) &#123;</span><br><span class="line">    charMap[char] = charMap[char] + <span class="number">1</span> || <span class="number">1</span>;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> charMap;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>method2</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">anagrams</span>(<span class="params">stringA, stringB</span>) &#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="title function_">cleanString</span>(stringA) === <span class="title function_">cleanString</span>(stringB);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">cleanString</span>(<span class="params">str</span>) &#123;</span><br><span class="line">  <span class="keyword">return</span> str</span><br><span class="line">    .<span class="title function_">replace</span>(<span class="regexp">/[^\w]/g</span>, <span class="string">&#x27;&#x27;</span>)</span><br><span class="line">    .<span class="title function_">toLowerCase</span>()</span><br><span class="line">    .<span class="title function_">split</span>(<span class="string">&#x27;&#x27;</span>)</span><br><span class="line">    .<span class="title function_">sort</span>()</span><br><span class="line">    .<span class="title function_">join</span>(<span class="string">&#x27;&#x27;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="Printing-Steps"><a href="#Printing-Steps" class="headerlink" title="Printing Steps"></a>Printing Steps</h3><p>The effect we need is as following: </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">--- Examples</span><br><span class="line">  steps(2)</span><br><span class="line">      &#x27;# &#x27;</span><br><span class="line">      &#x27;##&#x27;</span><br><span class="line">  steps(3)</span><br><span class="line">      &#x27;#  &#x27;</span><br><span class="line">      &#x27;## &#x27;</span><br><span class="line">      &#x27;###&#x27;</span><br><span class="line">  steps(4)</span><br><span class="line">      &#x27;#   &#x27;</span><br><span class="line">      &#x27;##  &#x27;</span><br><span class="line">      &#x27;### &#x27;</span><br><span class="line">      &#x27;####&#x27;</span><br></pre></td></tr></table></figure><p>solution based on recursive methods</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">steps</span>(<span class="params">n, row = <span class="number">0</span>, stair = <span class="string">&#x27;&#x27;</span></span>) &#123;</span><br><span class="line">  <span class="keyword">if</span> (n === row) &#123;</span><br><span class="line">    <span class="keyword">return</span>;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">if</span> (n === stair.<span class="property">length</span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(stair);</span><br><span class="line">    <span class="keyword">return</span> <span class="title function_">steps</span>(n, row + <span class="number">1</span>);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">const</span> add = stair.<span class="property">length</span> &lt;= row ? <span class="string">&#x27;#&#x27;</span> : <span class="string">&#x27; &#x27;</span>;</span><br><span class="line">  <span class="title function_">steps</span>(n, row, stair + add);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="Enter-the-Matrix-Spiral"><a href="#Enter-the-Matrix-Spiral" class="headerlink" title="Enter the Matrix Spiral"></a>Enter the Matrix Spiral</h3><p>The requirement goes as following: </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">--- Examples</span><br><span class="line">  matrix(2)</span><br><span class="line">    [[undefined, undefined],</span><br><span class="line">    [undefined, undefined]]</span><br><span class="line">  matrix(3)</span><br><span class="line">    [[1, 2, 3],</span><br><span class="line">    [8, 9, 4],</span><br><span class="line">    [7, 6, 5]]</span><br><span class="line"> matrix(4)</span><br><span class="line">    [[1,   2,  3, 4],</span><br><span class="line">    [12, 13, 14, 5],</span><br><span class="line">    [11, 16, 15, 6],</span><br><span class="line">    [10,  9,  8, 7]]</span><br></pre></td></tr></table></figure><p>solution: </p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">matrix</span>(<span class="params">n</span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> results = [];</span><br><span class="line"></span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; n; i++) &#123;</span><br><span class="line">    results.<span class="title function_">push</span>([]);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">let</span> counter = <span class="number">1</span>;</span><br><span class="line">  <span class="keyword">let</span> startColumn = <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">let</span> endColumn = n - <span class="number">1</span>;</span><br><span class="line">  <span class="keyword">let</span> startRow = <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">let</span> endRow = n - <span class="number">1</span>;</span><br><span class="line">  <span class="keyword">while</span> (startColumn &lt;= endColumn &amp;&amp; startRow &lt;= endRow) &#123;</span><br><span class="line">    <span class="comment">// Top row</span></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i = startColumn; i &lt;= endColumn; i++) &#123;</span><br><span class="line">      results[startRow][i] = counter;</span><br><span class="line">      counter++;</span><br><span class="line">    &#125;</span><br><span class="line">    startRow++;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Right column</span></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i = startRow; i &lt;= endRow; i++) &#123;</span><br><span class="line">      results[i][endColumn] = counter;</span><br><span class="line">      counter++;</span><br><span class="line">    &#125;</span><br><span class="line">    endColumn--;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Bottom row</span></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i = endColumn; i &gt;= startColumn; i--) &#123;</span><br><span class="line">      results[endRow][i] = counter;</span><br><span class="line">      counter++;</span><br><span class="line">    &#125;</span><br><span class="line">    endRow--;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// start column</span></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i = endRow; i &gt;= startRow; i--) &#123;</span><br><span class="line">      results[i][startColumn] = counter;</span><br><span class="line">      counter++;</span><br><span class="line">    &#125;</span><br><span class="line">    startColumn++;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> results;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="Fibonacci"><a href="#Fibonacci" class="headerlink" title="Fibonacci"></a>Fibonacci</h3><p>solution based on <strong>memoization</strong> and <strong>recursive</strong>.</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">memoize</span>(<span class="params">fn</span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> cache = &#123;&#125;;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">function</span>(<span class="params">...args</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (cache[args]) &#123;</span><br><span class="line">      <span class="keyword">return</span> cache[args];</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> result = fn.<span class="title function_">apply</span>(<span class="variable language_">this</span>, args);</span><br><span class="line">    cache[args] = result;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> result;</span><br><span class="line">  &#125;;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">slowFib</span>(<span class="params">n</span>) &#123;</span><br><span class="line">  <span class="keyword">if</span> (n &lt; <span class="number">2</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> n;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> <span class="title function_">fib</span>(n - <span class="number">1</span>) + <span class="title function_">fib</span>(n - <span class="number">2</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> fib = <span class="title function_">memoize</span>(slowFib);</span><br></pre></td></tr></table></figure><p>The most simplified method goes as following:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">memoize</span>(<span class="params">fn</span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> cache = &#123;&#125;;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">function</span>(<span class="params">n</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span>(cache[n]) &#123;</span><br><span class="line">      <span class="keyword">return</span> cache[n];</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">const</span> result = <span class="title function_">fn</span>(n);</span><br><span class="line">    cache[n] = result;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> result;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Make it more abstract like below:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">memoize</span>(<span class="params">fn</span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> cache = &#123;&#125;;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">function</span>(<span class="params">...args</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (cache[args]) &#123;</span><br><span class="line">      <span class="keyword">return</span> cache[args];</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> result = fn.<span class="title function_">apply</span>(<span class="variable language_">this</span>, args);</span><br><span class="line">    cache[args] = result;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> result;</span><br><span class="line">  &#125;;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="Queue-and-Stack"><a href="#Queue-and-Stack" class="headerlink" title="Queue and Stack"></a>Queue and Stack</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Queue</span> &#123;</span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">data</span> = [];</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="title function_">add</span>(<span class="params">record</span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">data</span>.<span class="title function_">unshift</span>(record);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="title function_">remove</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">data</span>.<span class="title function_">pop</span>();</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Stack</span> &#123;</span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">data</span> = [];</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="title function_">push</span>(<span class="params">record</span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">data</span>.<span class="title function_">push</span>(record);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="title function_">pop</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">data</span>.<span class="title function_">pop</span>();</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="title function_">peek</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">data</span>[<span class="variable language_">this</span>.<span class="property">data</span>.<span class="property">length</span> - <span class="number">1</span>];</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="string">``</span><span class="string">` </span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">### Two Become One </span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">Implement a Queue data structure using two stacks</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">`</span><span class="string">``</span> javascript</span><br><span class="line"><span class="keyword">const</span> <span class="title class_">Stack</span> = <span class="built_in">require</span>(<span class="string">&#x27;./stack&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Queue</span> &#123;</span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">first</span> = <span class="keyword">new</span> <span class="title class_">Stack</span>();</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">second</span> = <span class="keyword">new</span> <span class="title class_">Stack</span>();</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="title function_">add</span>(<span class="params">record</span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">first</span>.<span class="title function_">push</span>(record);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="title function_">remove</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">while</span> (<span class="variable language_">this</span>.<span class="property">first</span>.<span class="title function_">peek</span>()) &#123;</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">second</span>.<span class="title function_">push</span>(<span class="variable language_">this</span>.<span class="property">first</span>.<span class="title function_">pop</span>());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> record = <span class="variable language_">this</span>.<span class="property">second</span>.<span class="title function_">pop</span>();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">while</span> (<span class="variable language_">this</span>.<span class="property">second</span>.<span class="title function_">peek</span>()) &#123;</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">first</span>.<span class="title function_">push</span>(<span class="variable language_">this</span>.<span class="property">second</span>.<span class="title function_">pop</span>());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> record;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="title function_">peek</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">while</span> (<span class="variable language_">this</span>.<span class="property">first</span>.<span class="title function_">peek</span>()) &#123;</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">second</span>.<span class="title function_">push</span>(<span class="variable language_">this</span>.<span class="property">first</span>.<span class="title function_">pop</span>());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> record = <span class="variable language_">this</span>.<span class="property">second</span>.<span class="title function_">peek</span>();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">while</span> (<span class="variable language_">this</span>.<span class="property">second</span>.<span class="title function_">peek</span>()) &#123;</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">first</span>.<span class="title function_">push</span>(<span class="variable language_">this</span>.<span class="property">second</span>.<span class="title function_">pop</span>());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> record;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="Linked-List"><a href="#Linked-List" class="headerlink" title="Linked List"></a>Linked List</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Node</span> &#123;</span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params">data, next = <span class="literal">null</span></span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">data</span> = data;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">next</span> = next;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">LinkedList</span> &#123;</span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">head</span> = <span class="literal">null</span>;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="title function_">insertFirst</span>(<span class="params">data</span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">head</span> = <span class="keyword">new</span> <span class="title class_">Node</span>(data, <span class="variable language_">this</span>.<span class="property">head</span>);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="title function_">size</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">let</span> counter = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">let</span> node = <span class="variable language_">this</span>.<span class="property">head</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">while</span> (node) &#123;</span><br><span class="line">      counter++;</span><br><span class="line">      node = node.<span class="property">next</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> counter;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="title function_">getFirst</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">head</span>;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="title function_">getLast</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (!<span class="variable language_">this</span>.<span class="property">head</span>) &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">let</span> node = <span class="variable language_">this</span>.<span class="property">head</span>;</span><br><span class="line">    <span class="keyword">while</span> (node) &#123;</span><br><span class="line">      <span class="keyword">if</span> (!node.<span class="property">next</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> node;</span><br><span class="line">      &#125;</span><br><span class="line">      node = node.<span class="property">next</span>;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="title function_">clear</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">head</span> = <span class="literal">null</span>;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="title function_">removeFirst</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (!<span class="variable language_">this</span>.<span class="property">head</span>) &#123;</span><br><span class="line">      <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">head</span> = <span class="variable language_">this</span>.<span class="property">head</span>.<span class="property">next</span>;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="title function_">removeLast</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (!<span class="variable language_">this</span>.<span class="property">head</span>) &#123;</span><br><span class="line">      <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (!<span class="variable language_">this</span>.<span class="property">head</span>.<span class="property">next</span>) &#123;</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">head</span> = <span class="literal">null</span>;</span><br><span class="line">      <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">let</span> previous = <span class="variable language_">this</span>.<span class="property">head</span>;</span><br><span class="line">    <span class="keyword">let</span> node = <span class="variable language_">this</span>.<span class="property">head</span>.<span class="property">next</span>;</span><br><span class="line">    <span class="keyword">while</span> (node.<span class="property">next</span>) &#123;</span><br><span class="line">      previous = node;</span><br><span class="line">      node = node.<span class="property">next</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    previous.<span class="property">next</span> = <span class="literal">null</span>;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="title function_">insertLast</span>(<span class="params">data</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> last = <span class="variable language_">this</span>.<span class="title function_">getLast</span>();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (last) &#123;</span><br><span class="line">      <span class="comment">// There are some existing nodes in our chain</span></span><br><span class="line">      last.<span class="property">next</span> = <span class="keyword">new</span> <span class="title class_">Node</span>(data);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      <span class="comment">// The chain is empty!</span></span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">head</span> = <span class="keyword">new</span> <span class="title class_">Node</span>(data);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="title function_">getAt</span>(<span class="params">index</span>) &#123;</span><br><span class="line">    <span class="keyword">let</span> counter = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">let</span> node = <span class="variable language_">this</span>.<span class="property">head</span>;</span><br><span class="line">    <span class="keyword">while</span> (node) &#123;</span><br><span class="line">      <span class="keyword">if</span> (counter === index) &#123;</span><br><span class="line">        <span class="keyword">return</span> node;</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      counter++;</span><br><span class="line">      node = node.<span class="property">next</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="title function_">removeAt</span>(<span class="params">index</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (!<span class="variable language_">this</span>.<span class="property">head</span>) &#123;</span><br><span class="line">      <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (index === <span class="number">0</span>) &#123;</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">head</span> = <span class="variable language_">this</span>.<span class="property">head</span>.<span class="property">next</span>;</span><br><span class="line">      <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> previous = <span class="variable language_">this</span>.<span class="title function_">getAt</span>(index - <span class="number">1</span>);</span><br><span class="line">    <span class="keyword">if</span> (!previous || !previous.<span class="property">next</span>) &#123;</span><br><span class="line">      <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    previous.<span class="property">next</span> = previous.<span class="property">next</span>.<span class="property">next</span>;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="title function_">insertAt</span>(<span class="params">data, index</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (!<span class="variable language_">this</span>.<span class="property">head</span>) &#123;</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">head</span> = <span class="keyword">new</span> <span class="title class_">Node</span>(data);</span><br><span class="line">      <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (index === <span class="number">0</span>) &#123;</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">head</span> = <span class="keyword">new</span> <span class="title class_">Node</span>(data, <span class="variable language_">this</span>.<span class="property">head</span>);</span><br><span class="line">      <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> previous = <span class="variable language_">this</span>.<span class="title function_">getAt</span>(index - <span class="number">1</span>) || <span class="variable language_">this</span>.<span class="title function_">getLast</span>();</span><br><span class="line">    <span class="keyword">const</span> node = <span class="keyword">new</span> <span class="title class_">Node</span>(data, previous.<span class="property">next</span>);</span><br><span class="line">    previous.<span class="property">next</span> = node;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="title function_">forEach</span>(<span class="params">fn</span>) &#123;</span><br><span class="line">    <span class="keyword">let</span> node = <span class="variable language_">this</span>.<span class="property">head</span>;</span><br><span class="line">    <span class="keyword">let</span> counter = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">while</span> (node) &#123;</span><br><span class="line">      <span class="title function_">fn</span>(node, counter);</span><br><span class="line">      node = node.<span class="property">next</span>;</span><br><span class="line">      counter++;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  *[<span class="title class_">Symbol</span>.<span class="property">iterator</span>]() &#123;</span><br><span class="line">    <span class="keyword">let</span> node = <span class="variable language_">this</span>.<span class="property">head</span>;</span><br><span class="line">    <span class="keyword">while</span> (node) &#123;</span><br><span class="line">      <span class="keyword">yield</span> node;</span><br><span class="line">      node = node.<span class="property">next</span>;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="Find-the-midpoint-of-linked-list"><a href="#Find-the-midpoint-of-linked-list" class="headerlink" title="Find the midpoint of linked list"></a>Find the midpoint of linked list</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">--- <span class="title class_">Directions</span></span><br><span class="line"><span class="title class_">Return</span> the <span class="string">&#x27;middle&#x27;</span> node <span class="keyword">of</span> a linked list.</span><br><span class="line"><span class="title class_">If</span> the list has an even number <span class="keyword">of</span> elements, <span class="keyword">return</span></span><br><span class="line">the node at the end <span class="keyword">of</span> the first half <span class="keyword">of</span> the list.</span><br><span class="line">*<span class="title class_">Do</span> not* use a counter variable, *<span class="keyword">do</span> not* retrieve</span><br><span class="line">the size <span class="keyword">of</span> the list, and only iterate</span><br><span class="line">through the list one time.</span><br><span class="line">--- <span class="title class_">Example</span></span><br><span class="line">  <span class="keyword">const</span> l = <span class="keyword">new</span> <span class="title class_">LinkedList</span>();</span><br><span class="line">  l.<span class="title function_">insertLast</span>(<span class="string">&#x27;a&#x27;</span>)</span><br><span class="line">  l.<span class="title function_">insertLast</span>(<span class="string">&#x27;b&#x27;</span>)</span><br><span class="line">  l.<span class="title function_">insertLast</span>(<span class="string">&#x27;c&#x27;</span>)</span><br><span class="line">  <span class="title function_">midpoint</span>(l); <span class="comment">// returns &#123; data: &#x27;b&#x27; &#125;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">midpoint</span>(<span class="params">list</span>) &#123;</span><br><span class="line">  <span class="keyword">let</span> slow = list.<span class="title function_">getFirst</span>();</span><br><span class="line">  <span class="keyword">let</span> fast = list.<span class="title function_">getFirst</span>();</span><br><span class="line"></span><br><span class="line">  <span class="keyword">while</span> (fast.<span class="property">next</span> &amp;&amp; fast.<span class="property">next</span>.<span class="property">next</span>) &#123;</span><br><span class="line">    slow = slow.<span class="property">next</span>;</span><br><span class="line">    fast = fast.<span class="property">next</span>.<span class="property">next</span>;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> slow;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="Multiply-two-Big-numbers"><a href="#Multiply-two-Big-numbers" class="headerlink" title="Multiply two Big numbers"></a>Multiply two Big numbers</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">addbyStr</span>(<span class="params">str1, str2</span>) &#123;</span><br><span class="line">  <span class="keyword">let</span> len = <span class="title class_">Math</span>.<span class="title function_">max</span>(str1.<span class="property">length</span>, str2.<span class="property">length</span>);</span><br><span class="line">  <span class="keyword">let</span> increase = <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">let</span> rtn = <span class="string">&#x27;&#x27;</span>;</span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; len; i++) &#123;</span><br><span class="line">    <span class="keyword">let</span> ope1 = i &lt;= str1.<span class="property">length</span> - <span class="number">1</span> ? str1[str1.<span class="property">length</span> - <span class="number">1</span> -i] : <span class="string">&#x27;0&#x27;</span>;</span><br><span class="line">    <span class="keyword">let</span> ope2 = i &lt;= str2.<span class="property">length</span> - <span class="number">1</span> ? str2[str2.<span class="property">length</span> - <span class="number">1</span> -i] : <span class="string">&#x27;0&#x27;</span>;</span><br><span class="line">    <span class="keyword">let</span> temp = <span class="built_in">parseInt</span>(ope1) + <span class="built_in">parseInt</span>(ope2) + increase;</span><br><span class="line">    <span class="keyword">if</span> (temp &gt;= <span class="number">10</span>) &#123;</span><br><span class="line">      increase = <span class="number">1</span>;</span><br><span class="line">      temp = temp - <span class="number">10</span>;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      increase = <span class="number">0</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    rtn = temp + rtn;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> rtn;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">addArr</span>(<span class="params">arr</span>) &#123;</span><br><span class="line">  <span class="keyword">let</span> result = arr.<span class="title function_">reduce</span>(<span class="function">(<span class="params">rtn, each</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> rtn = <span class="title function_">addbyStr</span>(rtn, each);</span><br><span class="line">  &#125;);</span><br><span class="line">  <span class="keyword">return</span> result;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">mutliTwoStr</span>(<span class="params">str1, str2</span>) &#123;</span><br><span class="line">  <span class="keyword">let</span> rtn = [];</span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; str2.<span class="property">length</span>; i++) &#123;</span><br><span class="line">    <span class="keyword">let</span> count = <span class="built_in">parseInt</span>(str2[str2.<span class="property">length</span> - <span class="number">1</span> - i]);</span><br><span class="line">    <span class="keyword">let</span> temp = <span class="keyword">new</span> <span class="title class_">Array</span>(count).<span class="title function_">fill</span>(str1)</span><br><span class="line">    <span class="keyword">let</span> tempResult = <span class="title function_">addArr</span>(temp)</span><br><span class="line">    tempResult =  tempResult + <span class="string">&#x27;0&#x27;</span>.<span class="title function_">repeat</span>(i)</span><br><span class="line">    rtn.<span class="title function_">push</span>(tempResult)</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> <span class="title function_">addArr</span>(rtn);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;The Coding Interview Bootcamp: Data structure and algorithm.&lt;/p&gt;
&lt;h2 id=&quot;Part-1&quot;&gt;&lt;a href=&quot;#Part-1&quot; class=&quot;headerlink&quot; title=&quot;Part 1&quot;&gt;&lt;/a&gt;</summary>
      
    
    
    
    
    <category term="algorithm" scheme="https://baoqger.github.io/tags/algorithm/"/>
    
  </entry>
  
  <entry>
    <title>What happens when you run apt commands</title>
    <link href="https://baoqger.github.io/2019/09/09/what-happen-dpkg-install/"/>
    <id>https://baoqger.github.io/2019/09/09/what-happen-dpkg-install/</id>
    <published>2019-09-09T03:30:56.000Z</published>
    <updated>2021-12-23T12:34:34.800Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Background"><a href="#Background" class="headerlink" title="Background"></a>Background</h3><p>In Linux world softwares are delivered in the form of <code>package</code>. As a software engineer wants to work in Linux platform, you’ll run package management commands again and again. So you need to understand what actually happens when you run such commands. In this article, I’ll introduce this topic. </p><p><strong>Note</strong> that different Linux distros have different package management tool. In this article let’s focus on Ubuntu system and the package management tool is <code>apt</code>. </p><h3 id="Software-repositories"><a href="#Software-repositories" class="headerlink" title="Software repositories"></a>Software repositories</h3><p>Nowadays, everybody is familiar with app store, which is one central location. And users can retrieve applications there. In Linux world, <strong>software repositories</strong> work just like app store. Software repositories are generally made available in the form of mirros, to which your Linux system subscribe. </p><p>There are many repository mirrors in the world, you can decide which ones to use. In Ubuntu system, it’s defined in the config file of <code>/etc/apt/sources.list</code> as follows: </p><img src="/images/sourceslist.png" title="sources list" width="800px" height="600px"><p>The URLs defined in the file are just software repositories. </p><h3 id="Package-index"><a href="#Package-index" class="headerlink" title="Package index"></a>Package index</h3><p>The APT package index is essentially a database of available packages from the repositories mentioned above. </p><p>In Ubuntu system, the package index files are stored in <code>/var/lib/apt/lists</code></p><h3 id="apt-update"><a href="#apt-update" class="headerlink" title="apt update"></a>apt update</h3><p>Based on the above two points, we can easily understand what happens when we run <code>apt update</code>. It doesn’t update any installed packages, instead it updates the <strong>package index</strong> files in your local machine by sending new network requests to the <strong>software repositories</strong>. That’s also the reason why we need to run it before we run <code>apt upgrade</code> or <code>apt install</code>. Because the upgraded version or the newly installed version will depend on the updated package index files. In this way users will get the lastest version of the target package. </p><h3 id="apt-cache-search"><a href="#apt-cache-search" class="headerlink" title="apt-cache search"></a>apt-cache search</h3><p>Before you actually install a package, you can run <code>apt-cache search</code> command with the package name to get the list of any matched available packages. This can help you in case that you don’t know the exact package name in advance. </p><p><code>apt-cache</code> command doesn’t send any network request, instead it works based on the package index files in your local machine. How to prove this point? Of course the most direct way is reading the source code. But I want to show you another way to prove it with the tool of <code>strace</code>.</p><p><code>strace</code> is a tool can show you all the invoked <code>system call</code> when you run a command. If our guess about <code>apt-cache search</code> is correct, it should invoke system call to read the files in the package index directory <code>/var/lib/apt/lists</code>, right? Let’s have a look by running this command: </p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">strace apt-cache search openvpn 2&gt;&amp;1 | grep open</span><br></pre></td></tr></table></figure><p>Not that the <strong>2&gt;&amp;1</strong> part in the preceding command, this is because <code>strace</code> writes all its output to <code>stderr</code>, not <code>stdout</code>. And a <code>pipe</code> redirects stdout, not stderr. So you need to redirect stderr of strace to stdout before piping to <code>grep</code>. The output is very long but contains the following lines: </p><img src="/images/strace_aptcache.png" title="sources list" width="800px" height="600px"><p>Same as what we guessed. All right. </p><h3 id="apt-install"><a href="#apt-install" class="headerlink" title="apt install"></a>apt install</h3><p>There are many people asking questions on the forums about the secret of <code>apt install</code> like <a href="https://askubuntu.com/questions/162477/how-are-packages-actually-installed-via-apt-get-install">this one</a>. Does <code>apt install</code> download the source code of packages and then build it on your machine? That’s also one of the question came to my mind when I first touched Linux world. My intuition tells me there shouldn’t be compiling and building process involved when I run <code>apt install</code>. Because I think it’s too time consuming. </p><p>In fact, <code>apt install</code> is used to install the <strong>prebuilt binary package</strong> to your machine. Simply speaking, it does two tasks:</p><ul><li>Download the package, a <strong>Debian package</strong>, to <code>/var/cache/apt/archives</code></li><li>Extract files from the Debian package and copy them to the specific system location</li></ul><p>Because Ubuntu is originated from Debian system, so the package you install on Ubuntu is in fact a Debian package which is an archive file with the name ending <code>.deb</code>. For instance, the <code>openvpn</code> Debian package is as follows: </p><img src="/images/deb_package.png" title="sources list" width="800px" height="600px"><p>Then we can use <code>ar x &lt;package_name.deb&gt;</code> command to extract the package, you will find that there are three files inside each Debian package:</p><img src="/images/content_debian.png" title="sources list" width="800px" height="600px"><ul><li>debian-binary – A text file indicating the version of the .deb package format.</li><li>control.tar.gz – A compressed file and it contains md5sums and control directory for building package.</li><li>data.tar.xz – A compressed file and it contains all the files to be installed on your system. This is what we need continue to exmpolre. </li></ul><p>Run the following <code>tar</code> command to open this tarball</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">tar -xf data.tar.xz</span><br></pre></td></tr></table></figure><p>Note that the tarball contains the following directories: </p><img src="/images/content_datatar.png" title="sources list" width="600px" height="400px"><p>take a look into the <code>usr</code> directory, you’ll find the prebuild binaries. </p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;Background&quot;&gt;&lt;a href=&quot;#Background&quot; class=&quot;headerlink&quot; title=&quot;Background&quot;&gt;&lt;/a&gt;Background&lt;/h3&gt;&lt;p&gt;In Linux world softwares are delivered</summary>
      
    
    
    
    
    <category term="apt, Ubuntu, Linux, package management" scheme="https://baoqger.github.io/tags/apt-Ubuntu-Linux-package-management/"/>
    
  </entry>
  
  <entry>
    <title>How to use libraries in Linux C program</title>
    <link href="https://baoqger.github.io/2019/08/25/how-to-write-linux-c-program-with-external-library/"/>
    <id>https://baoqger.github.io/2019/08/25/how-to-write-linux-c-program-with-external-library/</id>
    <published>2019-08-25T08:08:36.000Z</published>
    <updated>2021-12-23T12:34:34.795Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Background"><a href="#Background" class="headerlink" title="Background"></a>Background</h3><p>After you learn and understand how to write small C programs in Linux (that means you know the syntax of C language and how to compile your programs with <code>gcc</code>), you will want to have some adventures to write more powerful and larger programs. To be a great software engineer, you need this passion to explore, right?</p><p>To write a larger program, you can’t build everything from scratch. This means you need to import and use libraries developed by others in your program.  </p><p>For new developers of Linux C programming, the whole handling of libraries can be a mystery, which requires knowledge about <code>gcc compiler</code>, <code>Linux system</code>, <code>GNU conventions</code> and so on. In this article, I will focus on this topic and piece all these together. After reading this post, I hope you can feel free and confident to add the shared libraries from the open source world to your program. </p><p><strong>Note</strong>: To illustrate the discussion more clearly, this article is based on this demo github <a href="https://github.com/baoqger/handle-c-library-demo-linux">app</a>. And my demo app is forked from Stephan Avenwedde’s original <a href="https://opensource.com/article/20/6/linux-libraries">repo</a>. Thanks for that.  </p><p>The code logic of this demo app is very straightforward, so I will not review the code line by line in this article, which is not the target of this post. </p><h3 id="Static-library-vs-Shared-library"><a href="#Static-library-vs-Shared-library" class="headerlink" title="Static library vs Shared library"></a>Static library vs Shared library</h3><p>Generally speaking, there are two types of libraries: <code>Static</code> and <code>Shared</code>. </p><ul><li><strong>static library</strong>: is simply a collection of ordinary object files; conventionally, static libraries end with the <code>.a</code> suffix. This collection is created using <code>ar</code> command. For example, in the demo app, we build the static library like this:</li></ul><figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">CFLAGS =-Wall -Werror</span><br><span class="line"></span><br><span class="line"><span class="section">libmy_static.a: libmy_static_a.o libmy_static_b.o</span></span><br><span class="line">ar -rsv ./lib/static/libmy_static.a libmy_static_a.o libmy_static_b.o</span><br><span class="line"></span><br><span class="line"><span class="section">libmy_static_a.o: libmy_static_a.c</span></span><br><span class="line">cc -c libmy_static_a.c -o libmy_static_a.o <span class="variable">$(CFLAGS)</span></span><br><span class="line"></span><br><span class="line"><span class="section">libmy_static_b.o: libmy_static_b.c</span></span><br><span class="line">cc -c libmy_static_b.c -o libmy_static_b.o <span class="variable">$(CFLAGS)</span></span><br></pre></td></tr></table></figure><p>In our case, the static library will be installed in the subdirectory <code>./lib/static</code> and named as <code>libmy_static.a</code>.   </p><p>When the application links against a static library, the library’s code becomes part of the resulting executable. So you can run the application without any further setting or configuration. That’s the biggest advantage of the static library, and you’ll see how it works in the next section. </p><p>Static libraries aren’t used as often as they once were, since <code>shared library</code> has more advantages. </p><ul><li><strong>shared library</strong>: end with <code>.so</code> which means <strong>shared object</strong>. The shared library is loaded into memory when the application starts. If multiple applications use the same shared library, the shared library will be loaded only once. In our demo app, the shared library is built as follows: </li></ul><figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">libmy_shared.so: libmy_shared.o</span></span><br><span class="line">cc -shared -o ./lib/shared/libmy_shared.so libmy_shared.o</span><br><span class="line"></span><br><span class="line"><span class="section">libmy_shared.o: libmy_shared.c</span></span><br><span class="line">cc -c -fPIC libmy_shared.c -o libmy_shared.o</span><br></pre></td></tr></table></figure><p>The shared library <code>libmy_shared.so</code> is installed inside <code>./lib/shared</code> subdirectory. Note that the shared library is built with some special options for <code>gcc</code>, like <code>-fPIC</code> and <code>-shared</code>. In detail, you can check the document of gcc. </p><h3 id="Naming-convention"><a href="#Naming-convention" class="headerlink" title="Naming convention"></a>Naming convention</h3><p>Generally speaking, the name of shared library follows the pattern: <code>lib</code> + name of library + <code>.so</code>. Of course, version information is very important, but in this article, let’s ignore the version issue.</p><h3 id="Link-library"><a href="#Link-library" class="headerlink" title="Link library"></a>Link library</h3><p>After building the libraries, next step you need to import the libraries in your app. For our app, the source code is the file of <code>demo/main.c</code> as follows:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;libmy_shared.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;libmy_static_a.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;libmy_static_b.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;Press Enter to repeat\n\n&quot;</span>);</span><br><span class="line">    <span class="keyword">do</span>&#123;</span><br><span class="line">        <span class="type">int</span> n = getRandInt();</span><br><span class="line">        n = negateIfOdd(n);</span><br><span class="line">        printInteger(&amp;n);</span><br><span class="line"></span><br><span class="line">    &#125; <span class="keyword">while</span> (getchar() == <span class="string">&#x27;\n&#x27;</span>);</span><br><span class="line">   </span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Note that we import three <code>header file</code> of our libraries. The next question is how to build the demo app. </p><p>Let’s recall the building process of a C program as follows:</p><img src="/images/compile_process.png" title="compile process" width="800px" height="600px"><p>This is a two-step process: <code>compile</code> and <code>link</code>. Firstly, the source code file of <code>main.c</code> will be compiled to an object file, let’s say <code>main.o</code> file. In this step, the critical thing is telling <code>gcc</code> where to find the <code>header file</code> of the libraries. Next, link the <code>main.o</code> object file with our libraries: <code>libmy_static.a</code> and <code>libmy_shared.so</code>. <code>gcc</code> needs to know the name of library it should link and where to find these libraries, right? </p><p>These information can be defined by the following three options:</p><ul><li><code>I</code>: add the include directory for header files,</li><li><code>l</code>: name of the library </li><li><code>L</code>: the directory for the library</li></ul><p>In our case, the <code>make</code> command to build the demo app is as follows:</p><figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">LIBS = -L../lib/shared -L../lib/static -lmy_shared -lmy_static -I../</span><br><span class="line"></span><br><span class="line">CFLAGS =-Wall -Werror</span><br><span class="line"></span><br><span class="line"><span class="section">demo: </span></span><br><span class="line">cc -o my_app main.c <span class="variable">$(CFLAGS)</span> <span class="variable">$(LIBS)</span></span><br></pre></td></tr></table></figure><p>Since we have two libraries: <code>libmy_static.a</code> and <code>libmy_shared.so</code>, based on the naming convention we mentioned above, the <code>-l</code> option for library name should be <strong>my_static</strong> and <strong>my_shared</strong>. We can use two <code>-l</code> options for each library.  </p><p>For the <code>-L</code> option, we need to provide the directory path where to find the libraries. We can use the path <code>../lib/shared</code> and <code>../lib/static</code> relative to the demo’s source code file. Right? And the same rule applies to the <code>-I</code> option for the include header file as well. </p><p>Run <code>make demo</code> command, and you can build the demo app with the libraries linked together successfully. </p><h3 id="Filesystem-placement-convention"><a href="#Filesystem-placement-convention" class="headerlink" title="Filesystem placement convention"></a>Filesystem placement convention</h3><p>As I show above, the libraries are placed inside the subdirectory of this project.  This is inconvenient for others to import your library. Most open source software tends to follow the <code>GNU</code> standards. The <code>GNU</code> standards recommend installing by default all libraries in <code>/usr/local/lib</code> and all the header files in <code>/usr/local/include</code> when distributing source code. So let’s add one more <code>make</code> command to install the library file and header file to the directory based on the GNU convention: </p><figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">INSTALL ?= install</span><br><span class="line">PREFIX ?= /usr/local</span><br><span class="line">LIBDIR = <span class="variable">$(PREFIX)</span>/lib</span><br><span class="line">INCLUDEDIR = <span class="variable">$(PREFIX)</span>/<span class="keyword">include</span></span><br><span class="line"></span><br><span class="line"><span class="section">install: library</span></span><br><span class="line"><span class="variable">$(INSTALL)</span> -D libmy_shared.h <span class="variable">$(INCLUDEDIR)</span>/libmy_shared.h</span><br><span class="line"><span class="variable">$(INSTALL)</span> -D libmy_static_a.h <span class="variable">$(INCLUDEDIR)</span>/libmy_static_a.h</span><br><span class="line"><span class="variable">$(INSTALL)</span> -D libmy_static_b.h <span class="variable">$(INCLUDEDIR)</span>/libmy_static_b.h</span><br><span class="line"><span class="variable">$(INSTALL)</span> -D ./lib/static/libmy_static.a <span class="variable">$(LIBDIR)</span>/libmy_static.a</span><br><span class="line"><span class="variable">$(INSTALL)</span> -D ./lib/shared/libmy_shared.so <span class="variable">$(LIBDIR)</span>/libmy_shared.so</span><br><span class="line"></span><br><span class="line"><span class="section">uninstall:</span></span><br><span class="line">rm <span class="variable">$(INCLUDEDIR)</span>/libmy_shared.h</span><br><span class="line">rm <span class="variable">$(INCLUDEDIR)</span>/libmy_static_a.h</span><br><span class="line">rm <span class="variable">$(INCLUDEDIR)</span>/libmy_static_b.h</span><br><span class="line">rm <span class="variable">$(LIBDIR)</span>/libmy_static.a</span><br><span class="line">rm <span class="variable">$(LIBDIR)</span>/libmy_shared.so</span><br></pre></td></tr></table></figure><p>You can find the similar make command in my open source projects for this purpose. </p><p>The benefit is <code>gcc</code> compiler (which is also from GNU and follows the same convention) will look for the libraries by default in these two directories: <code>/usr/local/lib</code> and <code>/usr/local/include</code>. So you don’t need to set <code>-L</code> and <code>-I</code> options. For example, after we run <code>make install</code> command above and install the library into the system directory, you can build the demo app as follows: </p><figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">GNULIBS = -lmy_shared -lmy_static</span><br><span class="line"></span><br><span class="line">CFLAGS =-Wall -Werror</span><br><span class="line"></span><br><span class="line"><span class="comment"># you can run this make command after you install </span></span><br><span class="line"><span class="comment"># the libraries into the default system directory: /usr/local/bin</span></span><br><span class="line"><span class="section">gnudemo: </span></span><br><span class="line">cc -o my_app main.c <span class="variable">$(CFLAGS)</span> <span class="variable">$(GNULIBS)</span></span><br></pre></td></tr></table></figure><p>Understand the <code>GNU</code> convention can make your development more easier, right? </p><p>Then next step let’s run the demo app by simply calling <code>./my_app</code>, but you’ll get the following error message:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">./my_app: error while loading shared libraries: libmy_shared.so: cannot open shared object file: No such file or directroy</span><br></pre></td></tr></table></figure><p>What’s happening? </p><h3 id="Dynamic-linker"><a href="#Dynamic-linker" class="headerlink" title="Dynamic linker"></a>Dynamic linker</h3><p>When we start up an executable, the Linux kernel automatically runs the <code>dynamic linker</code> (or dynamic loader). This dynamic linker, in turn, finds and loads all other shared libraries used by the program.</p><p>In fact, the executable file in Linux system is usually in the format of <a href="https://linux-audit.com/elf-binaries-on-linux-understanding-and-analysis/"><code>ELF</code></a> which abbreviates <code>Executable and Linkable Format</code>. The ELF executable contains linking information, and the dynamic linker just reads that information to load shared libraries. </p><p>In Linux system, the dynamic linker is name <code>ld.so</code></p><p>Based on the above error message, we can say that the dynamic linker cannot find the shared library. We can verify this point by running <code>ldd</code> command, which is used to print the shared objects (shared libraries) required by each program or shared object specified on the command line.</p><img src="/images/ldd-result.png" title="ldd" width="800px" height="600px"><p>Clearly, our shared library <code>libmy_shared.so</code> is not found. We need to take a look how at <code>ld.so</code> works. The best way to find such information is running <code>man</code> command. We can get the following information in the <code>ld.so</code> man document:</p><img src="/images/ldso.png" title="ld.so" width="800px" height="600px"><p>Based on this screenshot, we can solve this issue in three ways:</p><ul><li>install the shared library in the directory: <code>/lib</code> or <code>/usr/lib</code></li><li>edit the environment variable <code>LD_LIBRARY_PATH</code> by appending the path of directories containing our library </li><li>update the cache file <code>/etc/ld.so.cache</code></li></ul><p>The first two methods can work well based on my test, but personally I recommend to use the third method, which is a more systematic way to register a library. </p><h3 id="Register-library"><a href="#Register-library" class="headerlink" title="Register library"></a>Register library</h3><p>To register a new library, we need to use command <code>ldconfig</code> which configures dynamic linker run-time bindings. </p><p>How does <code>ldconfig</code> work? It will search <code>.so</code> library files in some specific directories, and the search result will be updated to dynamic linker’s cache file <code>/etc/ld.so.cache</code>. </p><p>And one of the directory <code>ldconfig</code> will look at is <code>/etc/ld.so.conf</code>. In our Ubuntu system, it’s in fact a file as follows:</p><img src="/images/ld.so.conf.png" title="ld.so.conf" width="800px" height="600px"><p>it is expanded to all the <code>.conf</code> files inside <code>ld.so.conf.d</code>, in my case, there is one default file <code>libc.conf</code> as follows: </p><img src="/images/libc.conf.png" title="libc.conf" width="800px" height="600px"><p>Note that <code>/usr/local/lib</code> is defined inside the file, then <code>ldconfig</code> will search .so libraries in this directory. </p><p>As we mentioned in above section, <code>/usr/local/lib</code> is just the place to install shared library based on GNU convention. Right? </p><p>So we can simply run <code>ldconfig</code> command without any option to <strong>register a new library</strong> (make sure the library is install in that directory): </p><img src="/images/ldconfig.png" title="ldconfig" width="800px" height="600px"><p>In the above screenshot, you can see the change before and after running command <code>sudo ldconfig</code>. (<code>ldconfig -p</code> will list the current libraries reading from cache file <code>/etc/ld.so.cache</code>). After registering the library, it is added into the cache file of dynamic linker, right? Let’s verify this again with <code>ldd</code>:   </p><img src="/images/ldd-result-after.png" title="ldd-result" width="800px" height="600px"><p>Our new shared library can be found! Then we can run the app successfully as well. </p><h3 id="Summary"><a href="#Summary" class="headerlink" title="Summary"></a>Summary</h3><p>In this article we discussed several important tools like <code>ld.so</code>, <code>ldd</code>, <code>ldconfig</code> and <code>gcc</code>, which help you build and import shared libraries. Another thing is <code>GNU</code> convention or standard which defines the behavior of these tools.  </p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;Background&quot;&gt;&lt;a href=&quot;#Background&quot; class=&quot;headerlink&quot; title=&quot;Background&quot;&gt;&lt;/a&gt;Background&lt;/h3&gt;&lt;p&gt;After you learn and understand how to </summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>How HTTPS works: part five - manual verification of SSL/TLS certificates</title>
    <link href="https://baoqger.github.io/2019/03/06/https-certificate-manual-verify-openssl/"/>
    <id>https://baoqger.github.io/2019/03/06/https-certificate-manual-verify-openssl/</id>
    <published>2019-03-06T08:00:47.000Z</published>
    <updated>2022-02-25T02:44:06.454Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Background"><a href="#Background" class="headerlink" title="Background"></a>Background</h3><p>In the previous articles of this series, we examined how digital signatures and certificates make the <code>TLS handshake</code> process work. Generally speaking, this process is handled by platforms like web browsers. In this article, I want to <strong>demystify the process of TLS handshake by manual verification of SSL/TLS certificates step by step</strong>. </p><h3 id="Certificate-chain"><a href="#Certificate-chain" class="headerlink" title="Certificate chain"></a>Certificate chain</h3><p>In this previous <a href="http://localhost:4000/2019/03/02/https-certificate-anatomy/">article</a>, we mentioned that <strong>the server returns not one, but multiple certificates. These associated certificates form a certificate chain</strong> as follows: </p><img src="/images/https-certificates-chain.png" title="certificates chain" width="800px" height="600px"><p>The intermediate CA signs the server certificate, and Root CA signs the certificate of the intermediate CA (There can be multiple intermediate CAs). Pay attention to the <code>subject</code> and <code>issuer</code> names of each certificate, and you can notice that one certificate’s issue name is another certificate’s subject name. Certificates can find their CA’s certificate in the chain with this information. </p><p>For example, the following <code>openssl</code> command prints the certificate chain of google.com: </p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">openssl s_client -showcerts -connect google.com:443</span><br></pre></td></tr></table></figure><p>The previous <a href="http://localhost:4000/2019/03/02/https-certificate-anatomy/">article</a> explained that the chain contains three certificates. Let us extract the google.com server certificate into file <a href="https://gist.github.com/baoqger/8c854336118737db2cb55997ca7888c9"><strong>google_com.pem</strong></a> and the intermediate CA certificate into file <a href="https://gist.github.com/baoqger/59cd171e2114030a9f70790e99bd86d0"><strong>intermediate_ca.pem</strong></a>. These two files are the input data for this manual verification experiment. </p><h3 id="Manual-verification-of-SSL-TLS-certificates"><a href="#Manual-verification-of-SSL-TLS-certificates" class="headerlink" title="Manual verification of SSL/TLS certificates"></a>Manual verification of SSL/TLS certificates</h3><p>The entire process can be illustrated as follows: </p><img src="/images/https-manual-verification.png" title="certificates chain" width="800px" height="600px"><p>Let us go through it step by step. </p><h4 id="Extract-the-public-key-of-intermediate-CA"><a href="#Extract-the-public-key-of-intermediate-CA" class="headerlink" title="Extract the public key of intermediate CA"></a>Extract the public key of intermediate CA</h4><p>Since the certificate of the google.com server is signed with intermediate CA’s private key. The first step is to extract the public key of intermediate CA from its certificate. </p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">openssl x509 -in ./intermediate_ca.pem -noout -pubkey &gt; ./intermediate_ca_pub.pem</span><br></pre></td></tr></table></figure><p>The content of file <strong>intermediate_ca_pub.pem</strong> goes as follows:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">-----BEGIN PUBLIC KEY-----</span><br><span class="line">MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA9Yjf52KMHjf4N0KQf2yH</span><br><span class="line">0PtlgiX96MtrpP9t6Voj4pn2HOmSA5kTfAkKivpC1l5WJKp6M4Qf0elpu7l07FdM</span><br><span class="line">ZmiTdzdVU/45EE23NLtfJXc3OxeU6jzlndW8w7RD6y6nR++wRBFj2LRBhd1BMEiT</span><br><span class="line">G7+39uBFAiHglkIXz9krZVY0ByYEDaj9fcou7+pIfDdNPwCfg9/vdYQueVdc/Fdu</span><br><span class="line">Gpb//Iyappm+Jdl/liwG9xEqAoCA62MYPFBJh+WKyl8ZK1mWgQCg+1HbyncLC8mW</span><br><span class="line">T+9wScdcbSD9mbS04soud/0t3Au2axMMjBkrF5aYufCL9qAnu7bjjVGPva7Hm7GJ</span><br><span class="line">nQIDAQAB</span><br><span class="line">-----END PUBLIC KEY-----</span><br></pre></td></tr></table></figure><p>You can look at the public key in PEM format (which is not readable to humans). </p><h4 id="Extract-the-signature"><a href="#Extract-the-signature" class="headerlink" title="Extract the signature"></a>Extract the signature</h4><p>Next, let us extract the digital signature of the google.com server’s certificate. This task is a little bit complex, and we need several Linux commands to form a data stream pipeline as follows: </p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">openssl x509 -in ./google_com.pem -text -noout -certopt ca_default,no_validity,no_serial,no_subject,no_extensions,no_signame \</span><br><span class="line">| grep -v &#x27;Signature Algorithm&#x27; \</span><br><span class="line">| tr -d &#x27;[:space:]:&#x27; \</span><br><span class="line">| xxd -r -p &gt; ./certificate-signature.bin</span><br></pre></td></tr></table></figure><ul><li><code>openssl x509</code>: extract the digital signature. <code>openssl</code> command supports <code>certopt</code> option, which allows multiple arguments separated by commas. The output of the first command should be:</li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Signature Algorithm: sha256WithRSAEncryption</span><br><span class="line">        76:6a:8a:d8:44:ac:14:40:92:36:f3:4a:b5:cb:54:36:67:c7:</span><br><span class="line">        &lt;... content omitted ...&gt;</span><br><span class="line">        14:22:3f:2a:90:a5:e4:9b:26:df:33:15:4b:d2:5c:f7:89:8e:</span><br><span class="line">        f7:6a:c4:a6</span><br></pre></td></tr></table></figure><ul><li><code>grep -v</code>: invert the sense of matching and select non-matching lines (because of -v option).<code>Signature Algorithm: sha256WithRSAEncryption</code> is matched, but only the Hex code lines are selected based on the invert-match rule. The data stream after filtering should be:</li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">76:6a:8a:d8:44:ac:14:40:92:36:f3:4a:b5:cb:54:36:67:c7:</span><br><span class="line">&lt;... content omitted ...&gt;</span><br><span class="line">14:22:3f:2a:90:a5:e4:9b:26:df:33:15:4b:d2:5c:f7:89:8e:</span><br><span class="line">f7:6a:c4:a6</span><br></pre></td></tr></table></figure><p>Note <strong>Signature Algorithm: sha256WithRSAEncryption</strong> means that the signature is signed with <code>SHA-256</code> hash function and <code>RSA</code> encryption algorithm. When we need to re-compute the hash again, we must use the same hash function: <code>SHA-256</code>. </p><ul><li><p><code>tr -d</code>: delete the colons. The colons are to make it more readable. After removing the formatting colons, the output only contains Hex code. </p></li><li><p><code>xxd -r -p</code>: convert the Hex code into binary format and redirect to file <strong>certificate-signature.bin</strong> </p></li></ul><h4 id="Decrypt-the-signature"><a href="#Decrypt-the-signature" class="headerlink" title="Decrypt the signature"></a>Decrypt the signature</h4><p>Now that we have both the digital signature and the public key of the intermediate CA. We can decrypt the signature as follows:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">openssl rsautl -verify -inkey ./intermediate_ca_pub.pem -in ./certificate-signature.bin -pubin &gt; ./certificate-signature-decrypted.bin</span><br></pre></td></tr></table></figure><p>Store the decrypted signature in file <strong>certificate-signature-decrypted.bin</strong>. We can view the hash with openssl like so:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">openssl asn1parse -inform der -in ./certificate-signature-decrypted.bin</span><br></pre></td></tr></table></figure><p>The output is: </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">0:d=0  hl=2 l=  49 cons: SEQUENCE</span><br><span class="line">2:d=1  hl=2 l=  13 cons: SEQUENCE</span><br><span class="line">4:d=2  hl=2 l=   9 prim: OBJECT            :sha256</span><br><span class="line">15:d=2  hl=2 l=   0 prim: NULL</span><br><span class="line">17:d=1  hl=2 l=  32 prim: OCTET STRING      [HEX DUMP]:66EFBE4CEA76272C76CEE8FA297C1BF70C41F8E049C7E0E4D23C965CBE8F1B84</span><br></pre></td></tr></table></figure><p>The hash is in the last line: <code>66EFBE4CEA76272C76CEE8FA297C1BF70C41F8E049C7E0E4D23C965CBE8F1B84</code>. </p><h4 id="Re-compute-the-hash"><a href="#Re-compute-the-hash" class="headerlink" title="Re-compute the hash"></a>Re-compute the hash</h4><p>Now that we got the original hash of the certificate, we need to verify whether we can re-compute the same hash using the same hashing function (as mentioned above SHA-256 in this case).</p><p>The previous <a href="https://organicprogrammer.com/2019/03/05/https-certificate-signature/">article</a> explained that <strong>the digital signature is signed based on all of the information instead of only public key</strong>. We need to extract everything but the signature from the certificate. </p><p>We can extract the data and output it to file <strong>google_com_cert_body.bin</strong> as follows: </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">openssl asn1parse -i -in ./google_com.pem -strparse 4 -out ./google_com_cert_body.bin  -noout</span><br></pre></td></tr></table></figure><p>Note: you can refer to this openssl <a href="https://linux.die.net/man/1/asn1parse">document</a> to have a deeper understanding about the behavior of this command. </p><p>Finally, let us re-compute the hash with SHA256 as follows: </p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">openssl dgst -sha256 ./google_com_cert_body.bin</span><br><span class="line"></span><br><span class="line">SHA256(./google_com_cert_body.bin)= 66efbe4cea76272c76cee8fa297c1bf70c41f8e049c7e0e4d23c965cbe8f1b84</span><br></pre></td></tr></table></figure><p>The re-computed hash is <code>66efbe4cea76272c76cee8fa297c1bf70c41f8e049c7e0e4d23c965cbe8f1b84</code>, which matches with the original hash. So we can get the conclusion that: <strong>the intermediate CA signs the goole.com server certificate</strong>. </p><h3 id="Summary"><a href="#Summary" class="headerlink" title="Summary"></a>Summary</h3><p>In this article, we go through the verification process of SSL/TLS certificates step by step manually. I have to admit that the concepts of digital signatures and certificates are too abstract to understand, especially in the details. I hope the experiment, which carries out with certificates from the real world, can help you do that.  </p><h3 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h3><p><a href="https://linuxctl.com/2017/02/x509-certificate-manual-signature-verification/">x509 Certificate Manual Signature Verification</a> written by George Bolo.</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;Background&quot;&gt;&lt;a href=&quot;#Background&quot; class=&quot;headerlink&quot; title=&quot;Background&quot;&gt;&lt;/a&gt;Background&lt;/h3&gt;&lt;p&gt;In the previous articles of this serie</summary>
      
    
    
    
    
    <category term="digital signature, hash function" scheme="https://baoqger.github.io/tags/digital-signature-hash-function/"/>
    
  </entry>
  
  <entry>
    <title>How HTTPS works: part four - digital signature</title>
    <link href="https://baoqger.github.io/2019/03/05/https-certificate-signature/"/>
    <id>https://baoqger.github.io/2019/03/05/https-certificate-signature/</id>
    <published>2019-03-05T08:00:47.000Z</published>
    <updated>2022-02-10T01:52:07.488Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Background"><a href="#Background" class="headerlink" title="Background"></a>Background</h3><p>The <a href="https://organicprogrammer.com/2019/02/25/https-certificate/">second</a> article of this series shows that we should not directly exchange <code>public key</code> to establish a secure channel. Instead, <code>certificates</code> should be used to establish trust between clients and servers. And the last article examines the content of certificates, which encodes two very crucial pieces of information: <strong>the server’s public key</strong> and a <strong>digital signature</strong> that can confirm the certificate’s authenticity. In this article, let us examine what digital signature is and how it works.  </p><h3 id="Digital-Signature"><a href="#Digital-Signature" class="headerlink" title="Digital Signature"></a>Digital Signature</h3><p>The concept of <code>digital signature</code> can be illustrated as follows: </p><img src="/images/https-signature-process.png" title="digital signature process" width="600px" height="400px"><p>When the server sends a message to the client, how can we prevent the attackers from eavesdropping on the message? The solution is that the server attaches its signature to the message, and the client accepts the message only if the verification of the certificate passes. So this process can be divided into two parts: <code>sign the message to get the digital signature</code> and <code>verify the digital signature</code>.</p><ul><li><p><strong>Sign the message</strong>: means <code>hash</code> the message and <code>encrypt</code> the hash with the server’s private key. The encrypted hash is called <code>digital signature</code>. </p></li><li><p><strong>Verify the signature</strong>: means <code>decrypt</code> the signature with the server’s public key to get the hash, <code>re-compute</code> the hash of the message again, and compare the identity of two hashes.</p></li></ul><p>What can we benefit from signing and verifying the digital signature? To verify the digital signature is to confirm two things: </p><ul><li><p><strong>Message Integrity</strong>: the message has not changed since the signature was attached because it is based on a  <code>cryptographic hash</code> of the message. </p></li><li><p><strong>Proof of Origin</strong>: the signature belongs to the person who alone has access to the private key. In this way, the recipient of the message can be sure of the origin of the message.</p></li></ul><p>Information security has other attributes, but integrity and authentication are the two traits you must know.</p><h3 id="Secrets-behind-digital-signature"><a href="#Secrets-behind-digital-signature" class="headerlink" title="Secrets behind digital signature"></a>Secrets behind digital signature</h3><p>As mentioned in the above section, the digital signature can prove the integrity of the message and the authenticity of the message’s owner. To understand how it works, you must understand the following two facts: </p><ul><li><strong>Hash is irreversible</strong></li></ul><p>In the previous articles, we explained that cryptography is a two-way algorithm. You can <code>encrypt</code> the plaintext to the ciphertext and <code>decrypt</code> the ciphertext back to the plaintext. It means the cryptographic algorithm is reversible. </p><p>Different from cryptographic algorithms, <strong>A hash is irreversible!</strong>. This irreversibility is the whole point.</p><p>The goal of any cryptographic hashing algorithm is to reduce the arbitrarily sized input into a fixed-sized hash. The cryptographic hashing algorithm should guarantee that no two different messages can produce an identical hash. That is <code>collide</code>. </p><p>In this way, it is impossible for attackers to reverse engineer such a <code>collision</code>. </p><img src="/images/https-signature-hash.png" title="Hash is irreversible" width="600px" height="400px"><p>The attacker intercepts the message and changes it. Then the verification process of the signature on the client-side can not pass since the re-computed hashing can not match the original hashing. </p><p>I will write about how to implement a hash function in the future. In this article, you can ignore the details. Just remember that hashing is irreversible. </p><p><strong>The private key prove identity</strong></p><p>The attack shown above does not pass the verification because the signature and the forged message do not match. Then this time, the attacker compute a new hash based on the forged message and sign the hash with his private key. Can this attack work? </p><img src="/images/https-signature-key-identity.png" title="Hash is irreversible" width="800px" height="600px"><p>The short answer is No. </p><p>When the client gets the digital signature, the first step is to <code>decrypt</code> it. The decryption breaks for this new attack because the forged signature is signed with the attacker’s private key instead of the server’s private key. </p><p><strong>It’s impossible for anybody except the owner of the private key to generate something that can be decrypted using the public key.</strong> This is the nature of public-key cryptography. I will write other articles to explain it mathematically in the future.  </p><p>In a word, the private key can prove identity.</p><h3 id="How-does-signature-make-certificate-secure"><a href="#How-does-signature-make-certificate-secure" class="headerlink" title="How does signature make certificate secure?"></a>How does signature make certificate secure?</h3><p>The digital signature is not designed only for TLS certificates, and it has other applications, which is not the focus of my article. The important thing is to understand how to apply digital signature in the PKI framework and how it makes certificates more secure. </p><p>The key is that <strong>the certificate associates the public key with the server you are connecting to</strong>. As we see in <a href="https://organicprogrammer.com/2019/03/02/https-certificate-anatomy/">last</a> article, the certificate must contain some information about the identity of the server, such as the domain name of the server. For example, the <code>Subject</code> property of the <a href="https://gist.github.com/baoqger/79923d4f92b166bb914aa700721d6a0b">certificate</a> we examined in the last article</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Subject: CN = *.google.com</span><br></pre></td></tr></table></figure><p>And the digital signature is <code>signed based on all of the information instead of only public key</code>. It can prevent man-in-the-middle attack in the two following cases:</p><ul><li><p>The attacker intercepts the server’s certificate and changes the public key or any other information, the hash code in the signature does not match the hash code of the content of the forged certificate, and the client rejects it. It is <code>Message Integrity</code> mentioned above. </p></li><li><p>The attacker can obtain a certificate signed by the trusted CA by pretending as a legitimate business. When the client requests a certificate from the server, the attacker can replace it with his own. The validation on the client-side can not pass. Although the attacker’s certificate is signed by a trusted CA, the domain name(or other server information) does not match the expected one. It is <code>Proof of Origin</code> mentioned above. </p></li></ul><p>So far, I hope you can understand (roughly) the beauty of this Internet security framework. </p><h3 id="Summary"><a href="#Summary" class="headerlink" title="Summary"></a>Summary</h3><p>In this article, I examined how a digital signature works. You see how to sign a signature and how to verify it. Digital signature and certificate are the most abstract part of the PKI framework. So in the following article, let me illustrate the whole process by manually going through the certificate verification process step by step. We will use <code>openssl</code> to examine the result in each step.</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;Background&quot;&gt;&lt;a href=&quot;#Background&quot; class=&quot;headerlink&quot; title=&quot;Background&quot;&gt;&lt;/a&gt;Background&lt;/h3&gt;&lt;p&gt;The &lt;a href=&quot;https://organicprogrammer</summary>
      
    
    
    
    
    <category term="digital signature, hash function" scheme="https://baoqger.github.io/tags/digital-signature-hash-function/"/>
    
  </entry>
  
  <entry>
    <title>How HTTPS works: part three - the anatomy of certificate</title>
    <link href="https://baoqger.github.io/2019/03/02/https-certificate-anatomy/"/>
    <id>https://baoqger.github.io/2019/03/02/https-certificate-anatomy/</id>
    <published>2019-03-02T08:00:47.000Z</published>
    <updated>2022-01-10T02:28:34.981Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Background"><a href="#Background" class="headerlink" title="Background"></a>Background</h3><p>In the <a href="https://organicprogrammer.com/2019/02/25/https-certificate/">last article</a>, we examined the importance of certificates, which prevent us from the man-in-the-middle attacks. But we did not explain the mechanics of certificates, and it will be the focus of the following articles. In this article, let us first examine how the <code>TLS certificate</code> looks like and what kind of information it contains? </p><h3 id="Anatomy-of-certificate"><a href="#Anatomy-of-certificate" class="headerlink" title="Anatomy of certificate"></a>Anatomy of certificate</h3><p>The official name of <code>SSL/TLS certificate</code> is <a href="https://en.wikipedia.org/wiki/X.509"><code>X.509 certificate</code></a>. Before we can examine the content of the certificate, we must get it. We can do this with <code>openssl</code>. <code>openssl</code> is a popular tool in the network security field. In the following articles, we will use it a lot. For the use of <code>openssl</code>, you can refer to this online <a href="https://www.feistyduck.com/books/openssl-cookbook/">document</a>. </p><p>Let us pull the certificate from google.com domain as follows: </p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">openssl s_client -showcerts -connect google.com:443</span><br></pre></td></tr></table></figure><p>The output contains a large amount of information, and I omit some unnecessary codes to make it compact as follows: </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line">CONNECTED(00000003)</span><br><span class="line">depth=2 C = US, O = Google Trust Services LLC, CN = GTS Root R1</span><br><span class="line">verify return:1</span><br><span class="line">depth=1 C = US, O = Google Trust Services LLC, CN = GTS CA 1C3</span><br><span class="line">verify return:1</span><br><span class="line">depth=0 CN = *.google.com</span><br><span class="line">verify return:1</span><br><span class="line">---</span><br><span class="line">Certificate chain</span><br><span class="line"> 0 s:CN = *.google.com</span><br><span class="line">   i:C = US, O = Google Trust Services LLC, CN = GTS CA 1C3</span><br><span class="line">-----BEGIN CERTIFICATE-----</span><br><span class="line">MIINsjCCDJqgAwIBAgIRAPq8ife/MxCUCgAAAAEl/TIwDQYJKoZIhvcNAQELBQAw</span><br><span class="line">FYN5klRqI0hWa3wYe6tnXm/2PvPbAwqsnAq3q+Iek+3pGm6YTshJyA7P9L176psd</span><br><span class="line">&lt;... content omitted ...&gt;</span><br><span class="line">dm6slAYpHOryFcrvXzu1lHSylCAFNT/OYcH1GLTf0qJXuN7YnX9swoYu2oCDkIyA</span><br><span class="line">Hss2DDp7f8qf0VgDNNxZB8drZ9ID85YA3qgeIbHHAB8UIj8qkKXkmybfMxVL0lz3</span><br><span class="line">iY73asSm</span><br><span class="line">-----END CERTIFICATE-----</span><br><span class="line"> 1 s:C = US, O = Google Trust Services LLC, CN = GTS CA 1C3</span><br><span class="line">   i:C = US, O = Google Trust Services LLC, CN = GTS Root R1</span><br><span class="line">-----BEGIN CERTIFICATE-----</span><br><span class="line">MIIFljCCA36gAwIBAgINAgO8U1lrNMcY9QFQZjANBgkqhkiG9w0BAQsFADBHMQsw</span><br><span class="line">CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU</span><br><span class="line">&lt;... content omitted ...&gt;</span><br><span class="line">AJ2xDx8hcFH1mt0G/FX0Kw4zd8NLQsLxdxP8c4CU6x+7Nz/OAipmsHMdMqUybDKw</span><br><span class="line">juDEI/9bfU1lcKwrmz3O2+BtjjKAvpafkmO8l7tdufThcV4q5O8DIrGKZTqPwJNl</span><br><span class="line">1IXNDw9bg1kWRxYtnCQ6yICmJhSFm/Y3m6xv+cXDBlHz4n/FsRC6UfTd</span><br><span class="line">-----END CERTIFICATE-----</span><br><span class="line"> 2 s:C = US, O = Google Trust Services LLC, CN = GTS Root R1</span><br><span class="line">   i:C = BE, O = GlobalSign nv-sa, OU = Root CA, CN = GlobalSign Root CA</span><br><span class="line">-----BEGIN CERTIFICATE-----</span><br><span class="line">MIIFYjCCBEqgAwIBAgIQd70NbNs2+RrqIQ/E8FjTDTANBgkqhkiG9w0BAQsFADBX</span><br><span class="line">MQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEQMA4GA1UE</span><br><span class="line">&lt;... content omitted ...&gt;</span><br><span class="line">9U5pCZEt4Wi4wStz6dTZ/CLANx8LZh1J7QJVj2fhMtfTJr9w4z30Z209fOU0iOMy</span><br><span class="line">+qduBmpvvYuR7hZL6Dupszfnw0Skfths18dG9ZKb59UhvmaSGZRVbNQpsg3BZlvi</span><br><span class="line">d0lIKO2d1xozclOzgjXPYovJJIultzkMu34qQb9Sz/yilrbCgj8=</span><br><span class="line">-----END CERTIFICATE-----</span><br><span class="line">---</span><br><span class="line">Server certificate</span><br><span class="line">subject=CN = *.google.com</span><br><span class="line"></span><br><span class="line">issuer=C = US, O = Google Trust Services LLC, CN = GTS CA 1C3</span><br><span class="line"></span><br><span class="line">---</span><br><span class="line">&lt;... content omitted ...&gt;</span><br></pre></td></tr></table></figure><p>Note: if you want to take a look at the full content of the above output, please refer to this online <a href="https://gist.github.com/baoqger/d1d5792d17c4b260ca186d9d2651066b">gist file</a></p><p>Based on the format of the output, you can figure out that the content between <code>-----BEGIN CERTIFICATE-----</code> and <code>-----END CERTIFICATE-----</code> markers is a certificate. </p><p>Another remarkable point is that the server returns not one, but three certificates. These associated certificates form a <code>certificate chain</code>. I will examine it in future articles. In the current post, let us focus on the certificate itself. </p><p>As shown above, the default format of the certificate is <code>PEM(Privacy Enhanced Mail)</code>. PEM is a Base64 encoded binary format. We can convert it to a human-readable format with <code>openssl</code>.</p><p>First, let us extract the google.com server certificate into a file named <strong>google_com.pem</strong>. Remember to include the <code>BEGIN</code> and <code>END</code> markers, but nothing more. You can refer to this <a href="https://gist.github.com/baoqger/8c854336118737db2cb55997ca7888c9">file</a>.</p><p>Then, run the following openssl command: </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">openssl x509 -in google_com.pem -noout -text</span><br></pre></td></tr></table></figure><p>here is the <a href="https://gist.github.com/baoqger/79923d4f92b166bb914aa700721d6a0b">output</a> (with some content omitted):</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br></pre></td><td class="code"><pre><span class="line">Certificate:</span><br><span class="line">    Data:</span><br><span class="line">        Version: 3 (0x2)</span><br><span class="line">        Serial Number:</span><br><span class="line">            fa:bc:89:f7:bf:33:10:94:0a:00:00:00:01:25:fd:32</span><br><span class="line">        Signature Algorithm: sha256WithRSAEncryption</span><br><span class="line">        Issuer: C = US, O = Google Trust Services LLC, CN = GTS CA 1C3</span><br><span class="line">        Validity</span><br><span class="line">            Not Before: Nov 29 02:22:33 2021 GMT</span><br><span class="line">            Not After : Feb 21 02:22:32 2022 GMT</span><br><span class="line">        Subject: CN = *.google.com</span><br><span class="line">        Subject Public Key Info:</span><br><span class="line">            Public Key Algorithm: id-ecPublicKey</span><br><span class="line">                Public-Key: (256 bit)</span><br><span class="line">                pub:</span><br><span class="line">                    04:a1:c2:d2:74:cc:32:68:86:68:18:0c:8f:5a:e1:</span><br><span class="line">                    &lt;... content omitted ...&gt;</span><br><span class="line">                    c8:1b:6b:85:5d</span><br><span class="line">                ASN1 OID: prime256v1</span><br><span class="line">                NIST CURVE: P-256</span><br><span class="line">        X509v3 extensions:</span><br><span class="line">            X509v3 Key Usage: critical</span><br><span class="line">                Digital Signature</span><br><span class="line">            X509v3 Extended Key Usage:</span><br><span class="line">                TLS Web Server Authentication</span><br><span class="line">            X509v3 Basic Constraints: critical</span><br><span class="line">                CA:FALSE</span><br><span class="line">            X509v3 Subject Key Identifier:</span><br><span class="line">                04:0E:70:9D:60:11:97:01:1B:0E:7E:72:B1:99:E5:28:F7:29:E0:72</span><br><span class="line">            X509v3 Authority Key Identifier:</span><br><span class="line">                keyid:8A:74:7F:AF:85:CD:EE:95:CD:3D:9C:D0:E2:46:14:F3:71:35:1D:27</span><br><span class="line"></span><br><span class="line">            Authority Information Access:</span><br><span class="line">                OCSP - URI:http://ocsp.pki.goog/gts1c3</span><br><span class="line">                CA Issuers - URI:http://pki.goog/repo/certs/gts1c3.der</span><br><span class="line"></span><br><span class="line">            X509v3 Subject Alternative Name:</span><br><span class="line">                DNS:*.google.com, DNS:*.appengine.google.com, DNS:*.bdn.dev, DNS:*.cloud.google.com, DNS:*.crowdsource.google.com, DNS:*.datacompute.google.com, DNS:*.google.ca, DNS:*.</span><br><span class="line">                &lt;... content omitted ...&gt;</span><br><span class="line">                youtubekids.com, DNS:yt.be, DNS:*.yt.be, DNS:android.clients.google.com, DNS:developer.android.google.cn, DNS:developers.android.google.cn, DNS:source.android.google.cn</span><br><span class="line">            X509v3 Certificate Policies:</span><br><span class="line">                Policy: 2.23.140.1.2.1</span><br><span class="line">                Policy: 1.3.6.1.4.1.11129.2.5.3</span><br><span class="line"></span><br><span class="line">            X509v3 CRL Distribution Points:</span><br><span class="line"></span><br><span class="line">                Full Name:</span><br><span class="line">                  URI:http://crls.pki.goog/gts1c3/QqFxbi9M48c.crl</span><br><span class="line"></span><br><span class="line">            CT Precertificate SCTs:</span><br><span class="line">                Signed Certificate Timestamp:</span><br><span class="line">                    Version   : v1 (0x0)</span><br><span class="line">                    Log ID    : 29:79:BE:F0:9E:39:39:21:F0:56:73:9F:63:A5:77:E5:</span><br><span class="line">                                BE:57:7D:9C:60:0A:F8:F9:4D:5D:26:5C:25:5D:C7:84</span><br><span class="line">                    Timestamp : Nov 29 03:22:38.708 2021 GMT</span><br><span class="line">                    Extensions: none</span><br><span class="line">                    Signature : ecdsa-with-SHA256</span><br><span class="line">                                30:46:02:21:00:B5:C7:D9:40:A7:62:19:B6:D8:62:D2:</span><br><span class="line">                                &lt;... content omitted ...&gt;</span><br><span class="line">                                F9:53:FA:C7:EF:2C:BA:9C</span><br><span class="line">                Signed Certificate Timestamp:</span><br><span class="line">                    Version   : v1 (0x0)</span><br><span class="line">                    Log ID    : 41:C8:CA:B1:DF:22:46:4A:10:C6:A1:3A:09:42:87:5E:</span><br><span class="line">                                4E:31:8B:1B:03:EB:EB:4B:C7:68:F0:90:62:96:06:F6</span><br><span class="line">                    Timestamp : Nov 29 03:22:38.872 2021 GMT</span><br><span class="line">                    Extensions: none</span><br><span class="line">                    Signature : ecdsa-with-SHA256</span><br><span class="line">                                30:45:02:21:00:87:35:02:A8:F6:06:EF:BC:F4:C1:95:</span><br><span class="line">                                &lt;... content omitted ...&gt;</span><br><span class="line">                                7E:5B:8B:35:E6:D2:3C</span><br><span class="line">    Signature Algorithm: sha256WithRSAEncryption</span><br><span class="line">         76:6a:8a:d8:44:ac:14:40:92:36:f3:4a:b5:cb:54:36:67:c7:</span><br><span class="line">         3a:a5:e9:b5:31:6c:51:5f:f3:ed:6a:99:ac:a7:5b:9c:ae:c9:</span><br><span class="line">         &lt;... content omitted ...&gt;</span><br><span class="line">         59:07:c7:6b:67:d2:03:f3:96:00:de:a8:1e:21:b1:c7:00:1f:</span><br><span class="line">         14:22:3f:2a:90:a5:e4:9b:26:df:33:15:4b:d2:5c:f7:89:8e:</span><br><span class="line">         f7:6a:c4:a6</span><br></pre></td></tr></table></figure><p>The certificate contains many elements. They are specified using a syntax<br>referred to as <code>ASN.1(Abstract Syntax Notation)</code>. As you can see, the certificate consists of two parts: <strong>Data</strong> and <strong>Signature Algorithm</strong>. The <strong>Data</strong> part contains the identity information about this server certificate. And the second part is the <code>digital signature</code> of this certificate. I’ll highlight the following elements:</p><ul><li><strong>Issuer</strong>: identifies who issues this certificate, also known as CA(certificate authority).</li><li><strong>Subject</strong>: identifies to whom the certificate is issued. In the case of the server certificate, the <code>Subject</code> should be the organization that owns the server. But in the certificate chain, the <code>Issuer</code> of the server certificate is the <code>Subject</code> of the intermediate certificate. I’ll examine this relationship in detail in the following article. </li><li><strong>Subject Public Key Info</strong>: the server’s public key. As we mentioned above, we created the certificate just to send the public key to the client. </li><li><strong>Signature Algorithm</strong>: refers to the element at the bottom of the certificate. The <strong>sha256WithRSAEncryption</strong> part denotes the <code>hash function</code> and <code>encryption algorithm</code> used to <code>sign the certificate</code>. In the above case, the server uses <code>sha256</code> as the hash function and <code>RSA</code> as the encryption algorithm. And the following block contains the signed hash of X.509 certificate data, called <code>digital signature</code>. The digital signature is the key information in certificates to establish trust between clients and servers. I’ll explain how a digital certificate works in the next article. </li></ul><h3 id="Summary"><a href="#Summary" class="headerlink" title="Summary"></a>Summary</h3><p>This article examines the information contained inside certificates using the tool <code>openssl</code>. We highlight some critical elements, and in the following article let us take a deep look at <code>digital signature</code>.</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;Background&quot;&gt;&lt;a href=&quot;#Background&quot; class=&quot;headerlink&quot; title=&quot;Background&quot;&gt;&lt;/a&gt;Background&lt;/h3&gt;&lt;p&gt;In the &lt;a href=&quot;https://organicprogram</summary>
      
    
    
    
    
    <category term="certificate, digital signature, hashing" scheme="https://baoqger.github.io/tags/certificate-digital-signature-hashing/"/>
    
  </entry>
  
  <entry>
    <title>How HTTPS works: part two - why we need public key and certificate</title>
    <link href="https://baoqger.github.io/2019/02/25/https-certificate/"/>
    <id>https://baoqger.github.io/2019/02/25/https-certificate/</id>
    <published>2019-02-25T08:00:47.000Z</published>
    <updated>2022-01-17T23:32:07.222Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Background"><a href="#Background" class="headerlink" title="Background"></a>Background</h3><p>In the first article of this series, I gave a high-level overview of <code>TLS handshake</code>. It covers many complex concepts like <code>encryption/decryption</code> <code>hash function</code> <code>public key</code> <code>private key</code>  and <code>digital certificate</code>. These concepts are defined in the framework of <code>Public Key Infrastructure (PKI)</code>.</p><p>Let’ continue exploring the PKI. This article focuses on understanding the <code>certificates</code> used to establish trust between clients and servers.  </p><h3 id="Symmetric-plus-Asymmetric"><a href="#Symmetric-plus-Asymmetric" class="headerlink" title="Symmetric plus Asymmetric"></a>Symmetric plus Asymmetric</h3><p><a href="https://organicprogrammer.com/2019/02/22/https-handshake/">Last post</a> examined the <code>TLS handshake</code>. What is remarkable in this process is both <code>symmetric encryption</code> and <code>asymmetric encryption</code> are used. </p><p><code>symmetric encryption</code> and <code>asymmetric encryption</code> are the two broad categories of cryptographic algorithms. </p><p>Symmetric key encryption uses the same key on both sides of the communication channel to encrypt or decrypt data. In <code>HTTPS</code> case, the client and server agree upon new keys to use for symmetric encryption, called <strong>session key</strong>. The HTTP messages are encrypted by this symmetric session key. </p><p>It has the advantage of being very fast with low overhead. In this way, it can minimize the performance impact <code>TLS</code> will have on the network communications. </p><p>But the real challenge of symmetric encryption is <strong>how to keep the key private and secure!</strong> The client and server must exchange keys without letting an interested eavesdropper see them. This seems like a <strong>chicken and egg problem</strong>; you can’t establish keys over an insecure channel, and you can’t establish a secure channel without keys. Right? </p><p>This key management turns out to be the most difficult part of encryption operations and is where asymmetric or public-key cryptography enters. </p><p>Simply speaking, <strong>a secure channel is firstly established with asymmetric cryptography and then the symmetric session key is exchanged through this secure channel</strong>. </p><p><strong>Note</strong>: Cryptography is a complex topic, which isn’t in the scope of this series of articles. You can find <a href="https://opensource.com/article/19/6/cryptography-basics-openssl-part-2">tons</a> of documents on the internet about it for deeper understanding. You can regard it as a block box and ignore the details. This doesn’t influence your understanding of <code>HTTPS</code> in high level </p><h3 id="Why-do-we-need-certificates"><a href="#Why-do-we-need-certificates" class="headerlink" title="Why do we need certificates"></a>Why do we need certificates</h3><p>Now we know public-key cryptography is needed to establish a secure channel. Can we directly transmit the public key from servers to clients? Why do we need a certificate as the carrier to pass the public key? Can we exchange the public key without certificates as follows: </p><img src="/images/https_wo_certificate.png" title="public key without certificate" width="600px" height="400px"><p>But the ultimate question is how you(as the client) know that the public key can be trusted as authentic? Assume that an attacker can not only view traffic, but also can intercept and modify it. Then the attacker can carry out <code>man-in-the-middle</code> attack as follows:  </p><img src="/images/https_mitm.png" title="man in the middle attack" width="800px" height="600px"><p>The attacker can replace the server’s public key with its own and send it to the client. The client doesn’t feel anything wrong and keeps using this public key as normal. The client encrypts the session key with the forged public key(the one from attackers) and sends it out. The attacker decrypts the session key with its private key, re-encrypt the session key with the server’s public key, and sends it to the server. As normal, the server decrypts the session key and agrees on it. But this session key is in the attacker’s hand too. The attacker can decrypt all the subsequent network traffic. </p><p>The problem here is that the client blindly <strong>trusts</strong> that the public key belongs to the server. That’s the reason why we need the <code>certificates</code> to establish trust between clients and servers.</p><h3 id="Summary"><a href="#Summary" class="headerlink" title="Summary"></a>Summary</h3><p>In this article, we understand the importance of public-key cryptography and certificates. In the next article, we will take a deep look at the certificate.  </p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;Background&quot;&gt;&lt;a href=&quot;#Background&quot; class=&quot;headerlink&quot; title=&quot;Background&quot;&gt;&lt;/a&gt;Background&lt;/h3&gt;&lt;p&gt;In the first article of this series, I</summary>
      
    
    
    
    
    <category term="public key, man-in-the-middle, certificate" scheme="https://baoqger.github.io/tags/public-key-man-in-the-middle-certificate/"/>
    
  </entry>
  
  <entry>
    <title>How HTTPS works: part one - TLS handshake</title>
    <link href="https://baoqger.github.io/2019/02/22/https-handshake/"/>
    <id>https://baoqger.github.io/2019/02/22/https-handshake/</id>
    <published>2019-02-22T03:04:58.000Z</published>
    <updated>2022-01-23T22:47:32.154Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Background"><a href="#Background" class="headerlink" title="Background"></a>Background</h3><p>At present, everybody knows about the lock icon in the browser’s address bar indicating that the session is protected by <code>HTTPS</code>.In this series of articles, I’ll show you how HTTPS works based on my research. </p><p>Simply speaking, <code>HTTPS = HTTP + SSL/TLS</code>. </p><p>In the <code>HTTP</code> protocol, the client communicates with the server by transmitting the message over the network. But the message is in the original format known as plaintext. The bad guys (attackers) can easily eavesdrop on the message. That’s the reason why we need <code>SSL/TLS</code>. </p><p>There are tons of <a href="https://www.globalsign.com/en/blog/ssl-vs-tls-difference">articles</a> online describing the relationship between SSL and TLS. You can regard TLS as the modern and advanced version of SSL. By conversion, we generally put them together as the name of the network security protocol. </p><p>In the <a href="https://en.wikipedia.org/wiki/OSI_model">OSI model</a>, the <code>HTTP</code> protocol is in <strong>layer 7</strong>, which is at the top of protocol stacks, how about <code>TLS</code> protocol. Although <code>TLS</code> is short for <code>Transport Layer Security</code>, it’s not in <strong>layer 4(transport layer)</strong>. You can roughly regard it as <strong>layer 5(session layer)</strong>. </p><p>This means there is no nontrivial difference between <code>HTTP</code> and <code>HTTPS</code> in terms of message transmission. This series of articles will focus on the security part of <code>HTTPS</code>. If you want to understand HTTP itself, please read my other <a href="https://baoqger.github.io/2021/12/01/understand-http-1-1-client-golang/">articles</a>. </p><p>As the first article of this series, I will talk about how to establish an <code>HTTPS</code> connection. This introduces a new concept: <strong>TLS handshake</strong>.</p><h3 id="TLS-Handshake"><a href="#TLS-Handshake" class="headerlink" title="TLS Handshake"></a>TLS Handshake</h3><p>In my previous article, I wrote about <a href="https://baoqger.github.io/2019/07/14/why-tcp-four-way-handshake/"><code>TCP three way handshake</code></a> to establish a TCP connection. For <code>HTTP</code> protocol, that’s all it needs to do. But <code>HTTPS</code> has to do <code>TLS handshake</code> as well. The process can be illustrated as follows: </p><p><strong>Note</strong> TLS handshakes occur after a TCP connection has been opened via a TCP handshake.</p><img src="/images/https-tls-handshake.png" title="tls handshake" width="600px" height="400px"><p><strong>Note</strong> to understand each detail of the above processing, you need to have some prerequisite knowledge such as <code>encryption/decryption</code>, <code>hash function</code>, <code>public key</code>, <code>private key</code>, and <code>digital certificate</code>.  If you don’t know, don’t worry. After reading this series of articles, you’ll have it under your belt. In this article, I’ll go through this process roughly and ignore the detail of each step. </p><ul><li><p><strong>Client hello message</strong>: the client starts the handshake by sending a “hello” message to the server. This “hello” message includes the TLS version and the <code>cipher suites</code> supported on the client-side. <code>cipher suites</code> is a fancy name for the set of encryption algorithms for use in establishing a secure connection.</p></li><li><p><strong>Server hello message</strong>: the server chooses the best(or suitable) SSL/TLS version and encryption algorithm among the candidates sent by the client. The server’s chosen cipher suite and <code>certificate</code> are sent to the client. <code>certificate</code> makes SSL/TLS encryption possible, which is critical to understand the entire process. For now, you need to know certificates contain the server’s <code>public key</code>  which is sent to the client. And the <code>private key</code> is kept secret on the server. </p></li><li><p><strong>Authentication</strong>: The client verifies the server’s certificate (I’ll investigate the certificate verification process at a very detailed level in another article). </p></li><li><p><strong>Encrypt the pre-master key</strong>: The client generates one random “pre-master” key, encrypts “pre-master” key with the server’s public key (extract from the certificate) and sends the encrypted “pre-master” key to the server.</p></li><li><p><strong>Decrypt the pre-master key</strong>: The server decrypts the “pre-master” key with its private key (The premaster key is encrypted with the public key and can only be decrypted with the private key by the server. This is called <code>asymmetric encryption</code>).</p></li><li><p><strong>Session key created</strong>: Both client and server will generate a <code>session key</code> based on the “pre-master” key. The <code>session key</code> should be the same on both sides.</p></li><li><p><strong>HTTP message encryption</strong>: Until the last step, the handshake is completed. The client and server will use the agreed <code>session key</code> to encrypt the following HTTP messages and continue the communication (since both sides use the same key, this is called <code>symmetric encryption</code>). </p></li></ul><p>That’s all about <code>TLS handshake</code> process. </p><h3 id="Summary"><a href="#Summary" class="headerlink" title="Summary"></a>Summary</h3><p>As the first article of this series, I go through the entire process of TLS handshake. In future articles, I’ll show you the mysteries of each part. </p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;Background&quot;&gt;&lt;a href=&quot;#Background&quot; class=&quot;headerlink&quot; title=&quot;Background&quot;&gt;&lt;/a&gt;Background&lt;/h3&gt;&lt;p&gt;At present, everybody knows about the </summary>
      
    
    
    
    
    <category term="HTTPS, TLS handshake, SSL/TLS" scheme="https://baoqger.github.io/tags/HTTPS-TLS-handshake-SSL-TLS/"/>
    
  </entry>
  
  <entry>
    <title>Why TCP connection termination needs four-way handshake</title>
    <link href="https://baoqger.github.io/2018/12/14/why-tcp-four-way-handshake/"/>
    <id>https://baoqger.github.io/2018/12/14/why-tcp-four-way-handshake/</id>
    <published>2018-12-14T08:34:58.000Z</published>
    <updated>2021-12-23T12:34:34.801Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Background"><a href="#Background" class="headerlink" title="Background"></a>Background</h3><p>In <code>TCP/IP</code> protocol stack, the <code>three way handshake</code> for connection establishment and <code>four way handshake</code> for connection termination are some concepts you must understand.</p><p>But after I learned <code>TCP/IP</code> stack, one question coming to my mind is why the connection termination needs four-way handshake. In this article, I will focus on this topic. To understand the answer to this question, we need to first explain the details of these two processes and compare them to find the difference. </p><h3 id="TCP-connection-establishment"><a href="#TCP-connection-establishment" class="headerlink" title="TCP connection establishment"></a>TCP connection establishment</h3><p>In contrast to <code>UDP</code>, TCP is a <code>connection-oriented</code> and <code>reliable full duplex</code> protocol, which requires a logical connection to be established between the two processes before data is exchanged. The connection must be maintained during the entire process that communication is taking place. And in TCP both sides can send data to its peer. </p><p>So four things need to happen for fully establishing a TCP connection:</p><ul><li>Each node has send a <code>SYN</code> flag to its peer (that’s two things, one <code>SYN</code> in each direction)</li><li>Each node has received a <code>ACK</code> flag of its own <code>SYN</code> flag from its peer  (that’s two things) </li></ul><p>Both <code>SYN</code> and <code>ACK</code> are properties in <code>TCP</code> header, where <code>SYN</code> means <code>synchronization</code> and <code>ACK</code> means <code>acknowledgement</code>. In detail the process goes as follows:</p><p>Firstly, the client sends the <code>SYN: 1</code> packet to server to start the connection. When the server receives the packet, it will send the <code>ACK: 1</code> packet to client to confirm that. Since in the TCP protocol, the server can also send data to the client. So the server needs to send the <code>SYN: 1</code> packet to the client as well. Finally, when the client sends the <code>ACK: 1</code> packet to the server. The establishment process is done, which goes as follows: </p><img src="/images/tcp-establishment-4-packets.png" title="tcp establishment with four packets" width="600px" height="400px"><p>Note that the server sends two packets: <code>ACK: 1</code> and <code>SYN: 1</code> in sequence. Why not combine these two packets into one to have a better network performance? So the common implementation of TCP protocol  goes as follows:</p><img src="/images/tcp-establishment-3-packets.png" title="tcp establishment with three packets" width="600px" height="400px"><p><strong>Note</strong>: besides <code>SYN</code> and <code>ACK</code> flag, in the establishment stage there are other fields need to be set in TCP header such as: <code>sequence number</code> and <code>window</code>. I will discuss these important TCP header fields in other articles.</p><h3 id="TCP-connection-termination"><a href="#TCP-connection-termination" class="headerlink" title="TCP connection termination"></a>TCP connection termination</h3><p>When the data stream transportation (I will not cover this part in this article) is over, we need to terminate the TCP connection. </p><p>Same as above, four things need to happen for fully terminating a TCP connection:</p><ul><li>Each node has send a <code>FIN</code> flag to its peer (that’s two things, one <code>FIN</code> in each direction)</li><li>Each node has received a <code>ACK</code> flag of its own <code>FIN</code> flag from its peer  (that’s two things) </li></ul><img src="/images/tcp_termination.png" title="tcp termination" width="600px" height="400px"><p>But the difference is that in most TCP implementation, four packets are used to terminate the connection. We didn’t combine the <code>ACK: 1</code> packet (marked as ②) and the <code>FIN: 1</code> packet (marked as ③) into one packet. </p><p>The reason is <code>ACK: 1</code> packet (marked as ②) is send by TCP stack automatically. And the next <code>FIN: 1</code> packet (marked as ③) is controlled in application level by calling <code>close</code> socket API. Application has the control to terminate the connection. So in common case, we didn’t merge this two packets into one. </p><p>It’s flexible for the application to control this process, for example, in this way the application can reuse existing TCP connection to reduce the overhead and improve the performance. In next article, I will talk about this topic.  </p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;Background&quot;&gt;&lt;a href=&quot;#Background&quot; class=&quot;headerlink&quot; title=&quot;Background&quot;&gt;&lt;/a&gt;Background&lt;/h3&gt;&lt;p&gt;In &lt;code&gt;TCP/IP&lt;/code&gt; protocol stack,</summary>
      
    
    
    
    
    <category term="TCP, IP" scheme="https://baoqger.github.io/tags/TCP-IP/"/>
    
  </entry>
  
  <entry>
    <title>array-pointer-similaries-c</title>
    <link href="https://baoqger.github.io/2018/11/12/array-pointer-similarities-c/"/>
    <id>https://baoqger.github.io/2018/11/12/array-pointer-similarities-c/</id>
    <published>2018-11-12T07:25:32.000Z</published>
    <updated>2022-01-12T07:27:37.937Z</updated>
    
    
    
    
    
    <category term="programming c, array, pointer" scheme="https://baoqger.github.io/tags/programming-c-array-pointer/"/>
    
  </entry>
  
  <entry>
    <title>How to build a Heap in linear time complexity</title>
    <link href="https://baoqger.github.io/2018/10/08/why-build-heap-is-a-linear-operation/"/>
    <id>https://baoqger.github.io/2018/10/08/why-build-heap-is-a-linear-operation/</id>
    <published>2018-10-07T23:43:52.000Z</published>
    <updated>2022-06-14T21:39:39.581Z</updated>
    
    <content type="html"><![CDATA[<h3 id="Background"><a href="#Background" class="headerlink" title="Background"></a>Background</h3><p>In this article, I will focus on the topic of <code>data structure and algorithms</code> (in my eyes, one of the most important skills for software engineers). Someday I came across one <a href="https://stackoverflow.com/questions/9755721/how-can-building-a-heap-be-on-time-complexity">question</a> goes like this: <em>how can building a heap be O(n) time complexity?</em> This question confuses me for a while, so I did some investigation and research on it. This article will share what I learned during this process, which covers the following points:</p><ul><li>What is a heap data structure? How does a heap behave? </li><li>How to implement a heap in C programming?</li><li>How to do the time complexity analysis on building the heap?</li></ul><h3 id="Basics-of-Heap"><a href="#Basics-of-Heap" class="headerlink" title="Basics of Heap"></a>Basics of Heap</h3><p>Before we dive into the implementation and time complexity analysis, let’s first understand the <code>heap</code>. </p><p>As a data structure, the <code>heap</code> was created for the heapsort sorting algorithm long ago. Besides heapsort, <code>heaps</code> are used in many famous algorithms such as <a href="https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm">Dijkstra’s algorithm</a> for finding the shortest path. Essentially, <em>heaps are the data structure you want to use when you want to be able to access the maximum or minimum element very quickly.</em></p><p>In computer science, a <code>heap</code> is a <em>specialized tree-based</em> data structure. A common implementation of a <code>heap</code> is the <em>binary heap</em>, in which the tree is a <em>binary tree</em>. </p><p>So a <code>heap</code> can be defined as a binary tree, but with two additional properties (that’s why we said it is a specialized tree):</p><ul><li><p><strong>shape property</strong>: a binary heap is a <em>complete</em> binary tree. So what is a <em>complete</em> binary tree? That is all levels of the tree, except possibly the last one(deepest) are fully filled, and, if the last level of the tree is not complete, the nodes of that level are filled from left to right. The complete binary tree is one type of binary tree, in detail,  you can refer to this <a href="https://en.wikipedia.org/wiki/Binary_tree#Types_of_binary_trees">document</a> to learn more about it.</p></li><li><p><strong>Heap property</strong>: the key stored in each node is either greater than or equal to (max-heaps) or less than or equal to (min-heaps) the keys in the node’s children. </p></li></ul><p>The following image shows a binary max-heap based on tree representation: </p><img src="/images/heap.png" title="heap" width="400px" height="300px"><p>The <code>heap</code> is a powerful data structure; because you can insert an element and extract(remove) the smallest or largest element from a min-heap or max-heap with only <strong>O(log N)</strong> time. That’s why we said that if you want to access to the maximum or minimum element very quickly, you should turn to <code>heaps</code>. In the next section, I will examine how heaps work by implementing one in C programming. </p><p>Note: The heap is closely related to another data structure called the <a href="https://en.wikipedia.org/wiki/Priority_queue"><code>priority queue</code></a>.  The <code>priority queue</code> can be implemented in various ways, but the <code>heap</code> is one maximally efficient implementation and in fact, priority queues are often referred as “heaps”, regardless of how they may be implemented. </p><h3 id="Implementation-of-Heap"><a href="#Implementation-of-Heap" class="headerlink" title="Implementation of Heap"></a>Implementation of Heap</h3><p>Because of the <code>shape property</code> of heaps, we usually implement it as an array, as follows:</p><ul><li>Each element in the array represents a node of the heap.</li><li>The parent/child relationship can be defined by the elements’ indices in the array. Given a node at index <code>i</code>, the left child is at index <code>2*i + 1</code> and the right child is at index <code>2*i + 2</code>, and its parent is at index <code>⌊(i-1)/2⌋</code> (<code>⌊⌋</code> means Floor operation). </li></ul><img src="/images/array-representation.png" title="heap" width="400px" height="300px"><p>Based on the above model, let’s start implementing our heap. As we mentioned, there are two types of heaps: min-heap and max-heap, in this article, I will work on <code>max-heap</code>. The difference between max-heap and min-heap is trivial, you can try to write out the min-heap after you understand this article. </p><p>The completed code implementation is inside this Github <a href="https://github.com/baoqger/max-heap-in-c">repo</a>. </p><p>First, let’s define the interfaces of max-heap in the header file as follows:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// maxheap.h file</span></span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> _MAXHEAP_H</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> _MAXHEAP_H</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="type">int</span> key_type;</span><br><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span> _<span class="title">maxheap</span> *<span class="title">maxheap</span>;</span> <span class="comment">// opaque type</span></span><br><span class="line"></span><br><span class="line">maxheap <span class="title function_">maxheap_create</span><span class="params">()</span>;</span><br><span class="line">maxheap <span class="title function_">maxheap_heapify</span><span class="params">(<span class="type">const</span> key_type *<span class="built_in">array</span>, <span class="type">int</span> n)</span>;</span><br><span class="line"><span class="type">void</span> <span class="title function_">maxheap_destroy</span><span class="params">(maxheap)</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">maxheap_findmax</span><span class="params">(maxheap)</span>;</span><br><span class="line"><span class="type">void</span> <span class="title function_">maxheap_insert</span><span class="params">(maxheap, key_type)</span>;</span><br><span class="line"><span class="type">void</span> <span class="title function_">maxheap_deletemax</span><span class="params">(maxheap)</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">maxheap_is_empty</span><span class="params">(maxheap)</span>;</span><br><span class="line"><span class="type">int</span> <span class="title function_">maxheap_size</span><span class="params">(maxheap)</span>;</span><br><span class="line"><span class="type">void</span> <span class="title function_">maxheap_clear</span><span class="params">(maxheap)</span>;</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br></pre></td></tr></table></figure><p>We define the max-heap as <code>struct _maxheap</code> and hide its implementation in the header file. And expose this struct in the interfaces via a handler(which is a pointer) <code>maxheap</code>. This technique in C program is called <a href="https://stackoverflow.com/questions/2301454/what-defines-an-opaque-type-in-c-and-when-are-they-necessary-and-or-useful"><code>opaque type</code></a>. <code>Opaque type</code> simulates the encapsulation concept of OOP programming. So that the internal details of a type can change without the code that uses it having to change. The detailed implementation goes as following:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// maxheap.c file</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> _<span class="title">maxheap</span> &#123;</span></span><br><span class="line">key_type* <span class="built_in">array</span>;</span><br><span class="line"><span class="type">int</span> max_size;</span><br><span class="line"><span class="type">int</span> cur_size;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>The max-heap elements are stored inside the <code>array</code> field. The capacity of the array is defined as field <code>max_size</code> and the current number of elements in the array is <code>cur_size</code>. </p><p>Next, let’s go through the interfaces one by one (most of the interfaces are straightforward, so I will not explain too much about them). The first one is <code>maxheap_create</code>, which constructs an instance of <code>maxheap</code> by allocating memory for it. </p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// maxheap.c file</span></span><br><span class="line">maxheap <span class="title function_">maxheap_create</span><span class="params">()</span> &#123;</span><br><span class="line">maxheap h = (maxheap)<span class="built_in">malloc</span>(<span class="keyword">sizeof</span>(<span class="keyword">struct</span> _maxheap));</span><br><span class="line"><span class="keyword">if</span> (h == <span class="literal">NULL</span>) &#123;</span><br><span class="line"><span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;Not enough memory!\n&quot;</span>);</span><br><span class="line"><span class="built_in">abort</span>();</span><br><span class="line">&#125;</span><br><span class="line">h-&gt;max_size = <span class="number">64</span>;</span><br><span class="line">h-&gt;cur_size = <span class="number">-1</span>;</span><br><span class="line">h-&gt;<span class="built_in">array</span> = (key_type*) <span class="built_in">malloc</span>(<span class="keyword">sizeof</span>(key_type)*(h-&gt;max_size));</span><br><span class="line"><span class="keyword">if</span> (h-&gt;<span class="built_in">array</span> == <span class="literal">NULL</span>) &#123;</span><br><span class="line"><span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;Not enough memory!\n&quot;</span>);</span><br><span class="line"><span class="built_in">abort</span>();</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> h;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>The initial capacity of the max-heap is set to 64, we can dynamically enlarge the capacity when more elements need to be inserted into the heap: </p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// maxheap.c file</span></span><br><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">maxheap_double_capacity</span><span class="params">(maxheap h)</span> &#123;</span><br><span class="line"><span class="type">int</span> new_max_size = <span class="number">2</span> * h-&gt;max_size;</span><br><span class="line">key_type* new_array = (key_type*) <span class="built_in">malloc</span>(<span class="keyword">sizeof</span>(key_type)* (new_max_size));</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (new_array == <span class="literal">NULL</span>) &#123;</span><br><span class="line"><span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;Not enough memory!\n&quot;</span>);</span><br><span class="line"><span class="built_in">abort</span>();</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">for</span>(<span class="type">int</span> i = <span class="number">0</span>; i &lt; h-&gt;cur_size; i++) &#123;</span><br><span class="line">new_array[i] = h-&gt;<span class="built_in">array</span>[i];</span><br><span class="line">&#125;</span><br><span class="line"><span class="built_in">free</span>(h-&gt;<span class="built_in">array</span>);</span><br><span class="line">h-&gt;<span class="built_in">array</span> = new_array;</span><br><span class="line">h-&gt;max_size = new_max_size;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>This is an internal API, so we define it as a <a href="https://www.tutorialspoint.com/static-functions-in-c"><code>static</code></a> function, which limits the access scope to its object file. </p><p>When the program doesn’t use the max-heap data anymore, we can destroy it as follows:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// maxheap.c file</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">maxheap_destroy</span><span class="params">(maxheap h)</span> &#123;</span><br><span class="line">assert(h);</span><br><span class="line"><span class="built_in">free</span>(h-&gt;<span class="built_in">array</span>);</span><br><span class="line"><span class="built_in">free</span>(h);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Don’t forget to release the allocated memory by calling <code>free</code>. </p><p>Next, let’s work on the difficult but interesting part: insert an element in <strong>O(log N)</strong> time. The solution goes as follows:</p><ul><li>Add the element to the end of the array. (The end of the array corresponds to the leftmost open space of the bottom level of the tree).</li><li>Compare the added element with its parent; if they are in the correct order(parent should be greater or equal to the child in max-heap, right?), stop.</li><li>If not, swap the element with its parent and return to the above step until reaches the top of the tree(the top of the tree corresponds to the first element in the array). </li></ul><p>The first step of adding an element to the array’s end conforms to the <strong>shape property</strong> first. Then the <strong>heap property</strong> is restored by traversing up the heap. The recursive traversing up and swapping process is called <code>heapify-up</code>. It is can be illustrated by the following pseudo-code:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">Max-Heapify-Up(A, i):</span><br><span class="line">    parent ← (i - 1) / 2</span><br><span class="line">    </span><br><span class="line">    if parent &gt;= 0 and A[parent] &lt; A[i] then:</span><br><span class="line">        swap A[i] and A[parent]</span><br><span class="line">        Max-Heapify-Up(A, parent)</span><br></pre></td></tr></table></figure><p>The implementation goes as follows:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// maxheap.c file</span></span><br><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">maxheap_swap</span><span class="params">(maxheap h, <span class="type">int</span> i, <span class="type">int</span> j)</span> &#123;</span><br><span class="line">assert(h &amp;&amp; i &gt;=<span class="number">0</span> &amp;&amp; i &lt;= h-&gt;cur_size &amp;&amp; j &gt;= <span class="number">0</span> &amp;&amp; j &lt;= h-&gt;cur_size);</span><br><span class="line">key_type tmp = h-&gt;<span class="built_in">array</span>[i];</span><br><span class="line">h-&gt;<span class="built_in">array</span>[i] = h-&gt;<span class="built_in">array</span>[j];</span><br><span class="line">h-&gt;<span class="built_in">array</span>[j] = tmp;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">maxheap_heapifyup</span><span class="params">(maxheap h, <span class="type">int</span> k)</span> &#123;</span><br><span class="line">assert(h &amp;&amp; k &gt;= <span class="number">0</span> &amp;&amp; k &lt;= h-&gt;cur_size);</span><br><span class="line"></span><br><span class="line"><span class="keyword">while</span>(k&gt;=<span class="number">0</span> &amp;&amp; h-&gt;<span class="built_in">array</span>[k] &gt; h-&gt;<span class="built_in">array</span>[k/<span class="number">2</span>]) &#123;</span><br><span class="line">maxheap_swap(h, k/<span class="number">2</span>, k);</span><br><span class="line">k /= <span class="number">2</span>;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">maxheap_insert</span><span class="params">(maxheap h, key_type key)</span> &#123;</span><br><span class="line">assert(h);</span><br><span class="line"></span><br><span class="line">h-&gt;cur_size += <span class="number">1</span>;</span><br><span class="line"><span class="comment">// make sure there is space</span></span><br><span class="line"><span class="keyword">if</span> (h-&gt;cur_size == h-&gt;max_size) &#123;</span><br><span class="line">maxheap_double_capacity(h);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// add at the end</span></span><br><span class="line">h-&gt;<span class="built_in">array</span>[h-&gt;cur_size] = key;</span><br><span class="line"></span><br><span class="line"><span class="comment">// restore the heap property by heapify-up</span></span><br><span class="line">maxheap_heapifyup(h, h-&gt;cur_size);</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>The number of operations requried in <code>heapify-up</code> depends on how many levels the new element must rise to satisfy the heap property. So the worst-case time complexity should be the height of the binary heap, which is <strong>log N</strong>. And appending a new element to the end of the array can be done with constant time by using <code>cur_size</code> as the index. As a result, the total time complexity of the insert operation should be <strong>O(log N)</strong>. </p><p>Similarly, next, let’s work on: extract the root from the heap while retaining the heap property in <strong>O(log N)</strong> time. The solution goes as follows:</p><ul><li>Replace the first element of the array with the element at the end. Then delete the last element. </li><li>Compare the new root with its children; if they are in the correct order, stop.</li><li>If not, swap the element with its child and repeat the above step.</li></ul><p>This similar traversing down and swapping process is called <code>heapify-down</code>. <code>heapify-down</code> is a little more complex than <code>heapify-up</code> since the parent element needs to swap with the <em>larger</em> children in the max heap. The implementation goes as follows: </p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// maxheap.c file</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">maxheap_is_empty</span><span class="params">(maxheap h)</span> &#123;</span><br><span class="line">assert(h);</span><br><span class="line"><span class="keyword">return</span> h-&gt;cur_size &lt; <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">maxheap_heapifydown</span><span class="params">(maxheap h, <span class="type">int</span> k)</span> &#123;</span><br><span class="line">assert(h);</span><br><span class="line"></span><br><span class="line"><span class="keyword">while</span>(<span class="number">2</span>*k &lt;= h-&gt;cur_size) &#123;</span><br><span class="line"><span class="type">int</span> j = <span class="number">2</span>*k;</span><br><span class="line"><span class="keyword">if</span> (j&lt;h-&gt;cur_size &amp;&amp; h-&gt;<span class="built_in">array</span>[j+<span class="number">1</span>] &gt; h-&gt;<span class="built_in">array</span>[j]) &#123;</span><br><span class="line">j++;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> (h-&gt;<span class="built_in">array</span>[k] &gt;= h-&gt;<span class="built_in">array</span>[j]) &#123;</span><br><span class="line"><span class="keyword">break</span>;</span><br><span class="line">&#125;</span><br><span class="line">maxheap_swap(h, k, j);</span><br><span class="line">k = j;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">maxheap_findmax</span><span class="params">(maxheap h)</span> &#123;</span><br><span class="line"><span class="keyword">if</span> (maxheap_is_empty(h)) &#123;</span><br><span class="line"><span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;Heap is empty!\n&quot;</span>);</span><br><span class="line"><span class="built_in">abort</span>();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// max is the first position</span></span><br><span class="line"><span class="keyword">return</span> h-&gt;<span class="built_in">array</span>[<span class="number">0</span>];</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">maxheap_deletemax</span><span class="params">(maxheap h)</span> &#123;</span><br><span class="line"><span class="keyword">if</span> (maxheap_is_empty(h)) &#123;</span><br><span class="line"><span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;Heap is empty!\n&quot;</span>);</span><br><span class="line"><span class="built_in">abort</span>();</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// swap the first and last element</span></span><br><span class="line">maxheap_swap(h, <span class="number">0</span>, h-&gt;cur_size);</span><br><span class="line">h-&gt;cur_size -= <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line">maxheap_heapifydown(h, <span class="number">0</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Based on the analysis of <code>heapify-up</code>, similarly, the time complexity of extract is also <strong>O(log n)</strong>.</p><p>In the next section, let’s go back to the question raised at the beginning of this article. </p><h3 id="The-time-complexity-of-building-a-heap"><a href="#The-time-complexity-of-building-a-heap" class="headerlink" title="The time complexity of building a heap"></a>The time complexity of building a heap</h3><p>What’s the time complexity of building a heap? The first answer that comes to my mind is <strong>O(n log n)</strong>. Since the time complexity to insert an element is <em>O(log n)</em>, for n elements the insert is repeated n times, so the time complexity is <em>O(n log n)</em>. Right?</p><p>We can use another optimal solution to build a heap instead of inserting each element repeatedly. It goes as follows:</p><ul><li>Arbitrarily putting the n elements into the array to respect the <strong>shape property</strong>.</li><li>Starting from the lowest level and moving upwards, sift the root of each subtree downward as in the <code>heapify-down</code> process until the <strong>heap property</strong> is restored. </li></ul><p>This process can be illustrated with the following image:</p><img src="/images/build-heap.png" title="heap" width="400px" height="300px"><p>This algorithm can be implemented as follows: </p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">maxheap <span class="title function_">maxheap_heapify</span><span class="params">(<span class="type">const</span> key_type* <span class="built_in">array</span>, <span class="type">int</span> n)</span> &#123;</span><br><span class="line">assert(<span class="built_in">array</span> &amp;&amp; n &gt; <span class="number">0</span>);</span><br><span class="line"></span><br><span class="line">maxheap h = (maxheap)<span class="built_in">malloc</span>(<span class="keyword">sizeof</span>(<span class="keyword">struct</span> _maxheap));</span><br><span class="line"><span class="keyword">if</span>(h == <span class="literal">NULL</span>) &#123;</span><br><span class="line"><span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;Not enough memory!\n&quot;</span>);</span><br><span class="line"><span class="built_in">abort</span>();</span><br><span class="line">&#125;</span><br><span class="line">h-&gt;max_size = n;</span><br><span class="line">h-&gt;cur_size = <span class="number">-1</span>;</span><br><span class="line">h-&gt;<span class="built_in">array</span> = (key_type*)(<span class="built_in">malloc</span>(<span class="keyword">sizeof</span>(key_type)*h-&gt;max_size));</span><br><span class="line"><span class="keyword">if</span>(h-&gt;<span class="built_in">array</span> == <span class="literal">NULL</span>) &#123;</span><br><span class="line"><span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;Not enough memory!\n&quot;</span>);</span><br><span class="line"><span class="built_in">abort</span>();</span><br><span class="line">&#125;</span><br><span class="line">h-&gt;cur_size = n<span class="number">-1</span>;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i=<span class="number">0</span>; i&lt; n; i++) &#123;</span><br><span class="line">h-&gt;<span class="built_in">array</span>[i] = <span class="built_in">array</span>[i];</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// small trick here. don&#x27;t need start the loop from the end</span></span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = h-&gt;max_size/<span class="number">2</span>; i &gt;= <span class="number">0</span>; i--) &#123; </span><br><span class="line">maxheap_heapifydown(h, i);</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> h;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Next, let’s analyze the time complexity of this above process. Suppose there are <em>n</em> elements in the heap, and the height of the heap is <em>h</em> (for the heap in the above image, the height is 3). Then we should have the following relationship: </p><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mn>2</mn><mi>h</mi></msup><mo>&lt;</mo><mo>=</mo><mi>n</mi><mo>&lt;</mo><mo>=</mo><msup><mn>2</mn><mrow><mi>h</mi><mo>+</mo><mn>1</mn></mrow></msup><mo>−</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">2^{h} &lt;= n &lt;= 2^{h+1} - 1 </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.888208em;vertical-align:-0.0391em;"></span><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.849108em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">h</span></span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">&lt;</span></span><span class="base"><span class="strut" style="height:0.36687em;vertical-align:0em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.5782em;vertical-align:-0.0391em;"></span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">&lt;</span></span><span class="base"><span class="strut" style="height:0.36687em;vertical-align:0em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.9324379999999999em;vertical-align:-0.08333em;"></span><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8491079999999999em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">h</span><span class="mbin mtight">+</span><span class="mord mtight">1</span></span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">1</span></span></span></span><p>When there is only one node in the last level then <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi><mo>=</mo><msup><mn>2</mn><mi>h</mi></msup></mrow><annotation encoding="application/x-tex">n = 2^{h} </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.849108em;vertical-align:0em;"></span><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.849108em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">h</span></span></span></span></span></span></span></span></span></span></span></span>. And when the last level of the tree is fully filled then <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi><mo>=</mo><msup><mn>2</mn><mrow><mi>h</mi><mo>+</mo><mn>1</mn></mrow></msup><mo>−</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">n = 2^{h+1} - 1 </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.9324379999999999em;vertical-align:-0.08333em;"></span><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8491079999999999em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">h</span><span class="mbin mtight">+</span><span class="mord mtight">1</span></span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">1</span></span></span></span></p><p>And start from the bottom as level <em>0</em> (the root node is level <em>h</em>), in level <em>j</em>, there are at most <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mn>2</mn><mrow><mi>h</mi><mo>−</mo><mi>j</mi></mrow></msup></mrow><annotation encoding="application/x-tex">2^{h-j} </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8491079999999999em;vertical-align:0em;"></span><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8491079999999999em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">h</span><span class="mbin mtight">−</span><span class="mord mathnormal mtight" style="margin-right:0.05724em;">j</span></span></span></span></span></span></span></span></span></span></span></span> nodes. And each node at most takes <em>j</em> times swap operation. So in level <em>j</em>, the total number of operation is <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>j</mi><mo>∗</mo><msup><mn>2</mn><mrow><mi>h</mi><mo>−</mo><mi>j</mi></mrow></msup></mrow><annotation encoding="application/x-tex">j*2^{h-j} </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.85396em;vertical-align:-0.19444em;"></span><span class="mord mathnormal" style="margin-right:0.05724em;">j</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">∗</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.8491079999999999em;vertical-align:0em;"></span><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8491079999999999em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">h</span><span class="mbin mtight">−</span><span class="mord mathnormal mtight" style="margin-right:0.05724em;">j</span></span></span></span></span></span></span></span></span></span></span></span>.</p><p>So the total running time for building the heap is proportional to:</p><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>T</mi><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo><mo>=</mo><mstyle scriptlevel="0" displaystyle="true"><munderover><mo>∑</mo><mrow><mi>j</mi><mo>=</mo><mn>0</mn></mrow><mi>h</mi></munderover><mrow><mi>j</mi><mo>∗</mo><msup><mn>2</mn><mrow><mi>h</mi><mo>−</mo><mi>j</mi></mrow></msup></mrow><mo>=</mo><mstyle scriptlevel="0" displaystyle="true"><munderover><mo>∑</mo><mrow><mi>j</mi><mo>=</mo><mn>0</mn></mrow><mi>h</mi></munderover><mrow><mi>j</mi><mo>∗</mo><mfrac><msup><mn>2</mn><mi>h</mi></msup><msup><mn>2</mn><mi>j</mi></msup></mfrac></mrow></mstyle></mstyle></mrow><annotation encoding="application/x-tex"> T(n) = \displaystyle\sum_{j=0}^h {j*2^{h-j}} = \displaystyle\sum_{j=0}^h {j* \frac {2^{h}} {2^{j}}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:3.2498900000000006em;vertical-align:-1.4137769999999998em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.8361130000000006em;"><span style="top:-1.872331em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.05724em;">j</span><span class="mrel mtight">=</span><span class="mord mtight">0</span></span></span></span><span style="top:-3.050005em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span><span style="top:-4.3000050000000005em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">h</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.4137769999999998em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05724em;">j</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">∗</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8991079999999999em;"><span style="top:-3.1130000000000004em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">h</span><span class="mbin mtight">−</span><span class="mord mathnormal mtight" style="margin-right:0.05724em;">j</span></span></span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:3.2498900000000006em;vertical-align:-1.4137769999999998em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.8361130000000006em;"><span style="top:-1.872331em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.05724em;">j</span><span class="mrel mtight">=</span><span class="mord mtight">0</span></span></span></span><span style="top:-3.050005em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span><span style="top:-4.3000050000000005em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">h</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.4137769999999998em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05724em;">j</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">∗</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.526108em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.750664em;"><span style="top:-2.9890000000000003em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.05724em;">j</span></span></span></span></span></span></span></span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.849108em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">h</span></span></span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span><p>If we factor out the <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mn>2</mn><mi>h</mi></msup></mrow><annotation encoding="application/x-tex">2^{h} </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.849108em;vertical-align:0em;"></span><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.849108em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">h</span></span></span></span></span></span></span></span></span></span></span></span> term, then we get:</p><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>T</mi><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo><mo>=</mo><msup><mn>2</mn><mi>h</mi></msup><mstyle scriptlevel="0" displaystyle="true"><munderover><mo>∑</mo><mrow><mi>j</mi><mo>=</mo><mn>0</mn></mrow><mi>h</mi></munderover><mfrac><mi>j</mi><msup><mn>2</mn><mi>j</mi></msup></mfrac></mstyle></mrow><annotation encoding="application/x-tex"> T(n) = 2^{h} \displaystyle\sum_{j=0}^h {\frac {j} {2^{j}}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:3.2498900000000006em;vertical-align:-1.4137769999999998em;"></span><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.849108em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">h</span></span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.8361130000000006em;"><span style="top:-1.872331em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.05724em;">j</span><span class="mrel mtight">=</span><span class="mord mtight">0</span></span></span></span><span style="top:-3.050005em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span><span style="top:-4.3000050000000005em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">h</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.4137769999999998em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord"><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3365200000000002em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.750664em;"><span style="top:-2.9890000000000003em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.05724em;">j</span></span></span></span></span></span></span></span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05724em;">j</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span><p>As we know, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mstyle scriptlevel="0" displaystyle="true"><munderover><mo>∑</mo><mrow><mi>j</mi><mo>=</mo><mn>0</mn></mrow><mi mathvariant="normal">∞</mi></munderover><mfrac><mi>j</mi><msup><mn>2</mn><mi>j</mi></msup></mfrac></mstyle></mrow><annotation encoding="application/x-tex">\displaystyle\sum_{j=0}^{\infty} {\frac {j} {2^{j}}} </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:3.0651740000000007em;vertical-align:-1.4137769999999998em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.6513970000000007em;"><span style="top:-1.872331em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.05724em;">j</span><span class="mrel mtight">=</span><span class="mord mtight">0</span></span></span></span><span style="top:-3.050005em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span><span style="top:-4.3000050000000005em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">∞</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.4137769999999998em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord"><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3365200000000002em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.750664em;"><span style="top:-2.9890000000000003em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.05724em;">j</span></span></span></span></span></span></span></span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05724em;">j</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span> is a series converges to 2 (in detail, you can refer to this <a href="https://en.wikipedia.org/wiki/Series_(mathematics)">wiki</a>).  </p><p>Using this we have:</p><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>T</mi><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo><mo>=</mo><msup><mn>2</mn><mi>h</mi></msup><mstyle scriptlevel="0" displaystyle="true"><munderover><mo>∑</mo><mrow><mi>j</mi><mo>=</mo><mn>0</mn></mrow><mi>h</mi></munderover><mfrac><mi>j</mi><msup><mn>2</mn><mi>j</mi></msup></mfrac><mo>&lt;</mo><mo>=</mo><msup><mn>2</mn><mi>h</mi></msup><mstyle scriptlevel="0" displaystyle="true"><munderover><mo>∑</mo><mrow><mi>j</mi><mo>=</mo><mn>0</mn></mrow><mi mathvariant="normal">∞</mi></munderover><mfrac><mi>j</mi><msup><mn>2</mn><mi>j</mi></msup></mfrac><mo>&lt;</mo><mo>=</mo><msup><mn>2</mn><mi>h</mi></msup><mo>∗</mo><mn>2</mn><mo>=</mo><msup><mn>2</mn><mrow><mi>h</mi><mo>+</mo><mn>1</mn></mrow></msup></mstyle></mstyle></mrow><annotation encoding="application/x-tex"> T(n) = 2^{h} \displaystyle\sum_{j=0}^h {\frac {j} {2^{j}}} &lt;= 2^{h} \displaystyle\sum_{j=0}^{\infty} {\frac {j} {2^{j}}} &lt;= 2^{h}*2 = 2^{h + 1}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:3.2498900000000006em;vertical-align:-1.4137769999999998em;"></span><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.849108em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">h</span></span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.8361130000000006em;"><span style="top:-1.872331em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.05724em;">j</span><span class="mrel mtight">=</span><span class="mord mtight">0</span></span></span></span><span style="top:-3.050005em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span><span style="top:-4.3000050000000005em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">h</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.4137769999999998em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord"><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3365200000000002em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.750664em;"><span style="top:-2.9890000000000003em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.05724em;">j</span></span></span></span></span></span></span></span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05724em;">j</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">&lt;</span></span><span class="base"><span class="strut" style="height:0.36687em;vertical-align:0em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:3.0651740000000007em;vertical-align:-1.4137769999999998em;"></span><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8991079999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">h</span></span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.6513970000000007em;"><span style="top:-1.872331em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.05724em;">j</span><span class="mrel mtight">=</span><span class="mord mtight">0</span></span></span></span><span style="top:-3.050005em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span><span style="top:-4.3000050000000005em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">∞</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.4137769999999998em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord"><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3365200000000002em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.750664em;"><span style="top:-2.9890000000000003em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.05724em;">j</span></span></span></span></span></span></span></span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05724em;">j</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">&lt;</span></span><span class="base"><span class="strut" style="height:0.36687em;vertical-align:0em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.8991079999999999em;vertical-align:0em;"></span><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8991079999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">h</span></span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">∗</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">2</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.8991079999999999em;vertical-align:0em;"></span><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8991079999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">h</span><span class="mbin mtight">+</span><span class="mord mtight">1</span></span></span></span></span></span></span></span></span></span></span></span><p>Based on the condition <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mn>2</mn><mi>h</mi></msup><mo>&lt;</mo><mo>=</mo><mi>n</mi></mrow><annotation encoding="application/x-tex">2^{h} &lt;= n </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.888208em;vertical-align:-0.0391em;"></span><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.849108em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">h</span></span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">&lt;</span></span><span class="base"><span class="strut" style="height:0.36687em;vertical-align:0em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">n</span></span></span></span>, so we have:</p><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>T</mi><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo><mo>&lt;</mo><mo>=</mo><mn>2</mn><mi>n</mi><mo>=</mo><mi>O</mi><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex"> T(n) &lt;= 2n = O(n)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">&lt;</span></span><span class="base"><span class="strut" style="height:0.36687em;vertical-align:0em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">2</span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">)</span></span></span></span><p>Now we prove that building a heap is a linear operation.</p><h3 id="Summary"><a href="#Summary" class="headerlink" title="Summary"></a>Summary</h3><p>In this article, we examined what is a <code>Heap</code> and understand how it behaves(<code>heapify-up</code> and <code>heapify-down</code>) by implementing it. More importantly, we analyze the time complexity of building a heap and prove it’s a linear operation.</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;Background&quot;&gt;&lt;a href=&quot;#Background&quot; class=&quot;headerlink&quot; title=&quot;Background&quot;&gt;&lt;/a&gt;Background&lt;/h3&gt;&lt;p&gt;In this article, I will focus on the t</summary>
      
    
    
    
    
    <category term="priority queue, data structure, algorithm, time complexity, Big O notation" scheme="https://baoqger.github.io/tags/priority-queue-data-structure-algorithm-time-complexity-Big-O-notation/"/>
    
  </entry>
  
</feed>
