<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Laputa</title><link>https://chenjianyong.com/zh/</link><description>Recent content on Laputa</description><generator>Hugo</generator><language>zh</language><atom:link href="https://chenjianyong.com/zh/index.xml" rel="self" type="application/rss+xml"/><item><title>Seastar: sharded service(2)</title><link>https://chenjianyong.com/zh/blog/2022/seastar-sharded-service2/</link><pubDate>Thu, 15 Dec 2022 00:00:00 +0000</pubDate><guid>https://chenjianyong.com/zh/blog/2022/seastar-sharded-service2/</guid><description>&lt;h2 id="preface"&gt;Preface&lt;/h2&gt;
&lt;p&gt;&lt;a href="blog/2022/seastar-sharded-service1/"&gt;第一篇&lt;/a&gt;里面介绍了一下 &lt;code&gt;seastar::sharded&lt;/code&gt; 的基本概念和用法, 一般情况下我们用这些就足够了, 但是 Seastar 还为其他一些特殊的使用场景提供了支持, 当程序功能越来越复杂, 碰到这些场景的概率肯定会更大, 所以从完备的层面考虑, 还是得介绍一些他们; 其实也并不困难, Seastar 是秉持实用主义的, 也就是说在里面的组件一定是有现实中的使用场景的, 用到他们只是时间的问题(了解了这些组件之后可以在 &lt;a href="https://github.com/redpanda-data/redpanda"&gt;redpanda&lt;/a&gt; 和 &lt;a href="https://github.com/scylladb/scylladb"&gt;scylladb&lt;/a&gt; 的 codebase 里搜索一下具体的使用场景)&lt;/p&gt;
&lt;h2 id="sharded-parameter"&gt;sharded parameter&lt;/h2&gt;
&lt;p&gt;前面并没有特别说明 &lt;code&gt;seastar::sharded&lt;/code&gt; 的 &lt;code&gt;start()&lt;/code&gt; 以及 &lt;code&gt;invoke_on_*&lt;/code&gt; 系列函数允许传递哪些参数, 笼统地说只要是支持拷贝构造的类型(包括内置数据类型)都支持, 但是可以更具体地分为三类:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;arbitrary constant values - these are copied to all instances&lt;/li&gt;
&lt;li&gt;other &lt;code&gt;sharded&amp;lt;&amp;gt;&lt;/code&gt; values - these are transformed before passing to the functor; the local instance is extracted and passed&lt;/li&gt;
&lt;li&gt;shard-dependent parameter&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;第一类是最简单也是也是最常用的, 所有除了第二类和第三类说明的类型(&lt;code&gt;sharded&lt;/code&gt; 和 &lt;code&gt;sharded_parameter&lt;/code&gt;)外的其他类型都属于第一类, 比如 &lt;code&gt;int&lt;/code&gt;、&lt;code&gt;std::string&lt;/code&gt; 以及自定义类型 &lt;code&gt;class Widget&lt;/code&gt; 等, 他们会被拷贝到各个 shard&lt;/p&gt;</description></item><item><title>Seastar: sharded service(1)</title><link>https://chenjianyong.com/zh/blog/2022/seastar-sharded-service1/</link><pubDate>Thu, 01 Dec 2022 00:00:00 +0000</pubDate><guid>https://chenjianyong.com/zh/blog/2022/seastar-sharded-service1/</guid><description>&lt;h2 id="preface"&gt;Preface&lt;/h2&gt;
&lt;p&gt;Seastar 是一个多线程异步库, 基于它的 App 通常都有在多个 shard(也称 logic core) 上对称部署服务的诉求; 为此我们需要在多个 shard 上创建服务的实例, 并且让这些实例执行某些操作; 这些涉及到 shard 之间的通信, Seastar 提倡使用显式的消息传递(message passing)而不是传统多线程编程常用的共享内存&amp;amp;加锁的方式进行通信, 为此提供了 &lt;code&gt;smp&lt;/code&gt; 工具; 所以我们其实可以这样写:&lt;/p&gt;
&lt;figure class="code" data-lang="c&amp;#43;&amp;#43;"&gt;
 &lt;figcaption&gt;&lt;span class="code-lang"&gt;c&amp;#43;&amp;#43;&lt;/span&gt;&lt;button class="code-copy" type="button" aria-label="复制代码"&gt;复制&lt;/button&gt;
 &lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c++" data-lang="c++"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Service&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;instances&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;instances&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;smp&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;smp&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;invoke_on_all&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;instances&lt;/span&gt;&lt;span class="p"&gt;]()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;this_shard_id&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Service&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;p&gt;使用 &lt;code&gt;smp&lt;/code&gt; 中的工具, 我们可以实现这些操作, 但是如果有很多这样的服务, 那么就需要重复大量类似的代码(以上代码只是该场景下很小的一部分), 所以我们应该将其沉淀为一个通用的组件, 而 Seastar 也是这样做的, 这就是 &lt;code&gt;seastar::sharded&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;一开始它并不叫这个名字, 而是 &lt;code&gt;seastar::distributed&lt;/code&gt;, 即分布式服务, 后面考虑到 distributed 经常用于跨机器的场景, 而这里实际上是同机器跨核, 所以改名为 &lt;code&gt;seastar::sharded&lt;/code&gt;, 不过考虑到向前兼容还是把 &lt;code&gt;seastar::distributed&lt;/code&gt; 作为 &lt;code&gt;seastar::sharded&lt;/code&gt; 的一个别名保留, 只是不再推荐使用&lt;/p&gt;
&lt;h2 id="一个-"&gt;一个 🌰&lt;/h2&gt;
&lt;p&gt;在了解它的实现之前, 先看看它的一些用法, Seastar 提供了一个简易的 HTTP server, 以此为例, 看看如何使用 &lt;code&gt;sharded&lt;/code&gt; 在多个 core 上部署它; 为了简化逻辑, 使用 &lt;code&gt;seastar::async&lt;/code&gt; 以串行的方式写:&lt;/p&gt;</description></item><item><title>Seastar: network stack</title><link>https://chenjianyong.com/zh/blog/2022/seastar-network-stack/</link><pubDate>Sun, 13 Nov 2022 00:00:00 +0000</pubDate><guid>https://chenjianyong.com/zh/blog/2022/seastar-network-stack/</guid><description>&lt;h1 id="seastar-network-stack"&gt;Seastar: network stack&lt;/h1&gt;
&lt;h2 id="preface"&gt;Preface&lt;/h2&gt;
&lt;p&gt;Seastar 中提供了两种协议栈:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;native stack&lt;/li&gt;
&lt;li&gt;posix stack&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;其中 native stack 是 seastar 自己实现的一套协议栈, 一般是和 DPDK 配合使用; 而 posix stack 则是传统的内核协议栈; 由于我并不了解 DPDK, 暂时也没有学习/使用的需要, 所以目前还是先关注 posix stack 的实现(只关注 TCP, unix socket/UDP/SCTP 暂时不管), 以及 seastar 是如何抽象 network stack 这个概念从而统一 native stack 和 posix stack 二者的.&lt;/p&gt;
&lt;h2 id="network-stack-api"&gt;network stack API&lt;/h2&gt;
&lt;p&gt;为了统一 native stack 与 posix stack, seastar net 模块中抽象除了如下实体：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;socket&lt;/code&gt;: 可以视作调用了 &lt;code&gt;socket(2)&lt;/code&gt; 但是还没有 &lt;code&gt;connect(2)&lt;/code&gt; 的 fd, 通过它我们可以发起网络连接得到 &lt;code&gt;connected_socket&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;connected_socket&lt;/code&gt;: 一个处于连接状态的 TCP/SCTP 全双工流&lt;/li&gt;
&lt;li&gt;&lt;code&gt;server_socket&lt;/code&gt; : TCP/SCTP 监听描述符, 等待 &lt;code&gt;accept(2)&lt;/code&gt; 新的网络连接&lt;/li&gt;
&lt;li&gt;&lt;code&gt;udp_channel&lt;/code&gt;: udp 管道, 用于读写数据&lt;/li&gt;
&lt;li&gt;&lt;code&gt;udp_datagram&lt;/code&gt;: udp 数据报&lt;/li&gt;
&lt;li&gt;&lt;code&gt;network_stack&lt;/code&gt;:&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="socket"&gt;socket&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;This class is responsible for establishing a connection between two endpoints. It allows for the connection attempt to be canceled.&lt;/p&gt;</description></item><item><title>一个符号导致的问题</title><link>https://chenjianyong.com/zh/blog/2022/%E4%B8%80%E4%B8%AA%E7%AC%A6%E5%8F%B7%E5%AF%BC%E8%87%B4%E7%9A%84%E9%97%AE%E9%A2%98/</link><pubDate>Sun, 07 Aug 2022 00:00:00 +0000</pubDate><guid>https://chenjianyong.com/zh/blog/2022/%E4%B8%80%E4%B8%AA%E7%AC%A6%E5%8F%B7%E5%AF%BC%E8%87%B4%E7%9A%84%E9%97%AE%E9%A2%98/</guid><description>&lt;h2 id="preface"&gt;Preface&lt;/h2&gt;
&lt;p&gt;最近在优化 Seastar 中 httpd 的一些逻辑，完事之后跑一跑单测想确认下对现有逻辑的确无影响，但是一跑发现有一个 chunk 相关的测试挂了——但是我明明还没有改动到这块，只是改了一下 keepalive 的判定逻辑。&lt;/p&gt;
&lt;p&gt;细究之后发现还是挺有意思的，所以打算把它记录下来；当然也不仅仅只是记录这个问题，查这个问题的时候也顺便学习了一下 Seastar 的单测该怎么写怎么执行、httpd 中 HTTP 协议解析流程，HTTP 中的 trailer 概念，以及 ragel 这个新工具的使用，所以也一并记录下来(同时也说明文章很有可能会抓不住重点 :))&lt;/p&gt;
&lt;h2 id="问题"&gt;问题&lt;/h2&gt;
&lt;p&gt;单测是这样：&lt;/p&gt;
&lt;figure class="code" data-lang="c&amp;#43;&amp;#43;"&gt;
 &lt;figcaption&gt;&lt;span class="code-lang"&gt;c&amp;#43;&amp;#43;&lt;/span&gt;&lt;button class="code-copy" type="button" aria-label="复制代码"&gt;复制&lt;/button&gt;
 &lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c++" data-lang="c++"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;SEASTAR_TEST_CASE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;test_full_chunk_format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;check_http_reply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;GET /test HTTP/1.1&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;Host: test&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;Transfer-Encoding: chunked&lt;/span&gt;&lt;span class="se"&gt;\r\n\r\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;a;abc-def;hello=world;aaaa&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;1234567890&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;a;a0-!#$%&amp;amp;&amp;#39;*+.^_`|~=&lt;/span&gt;&lt;span class="se"&gt;\&amp;#34;&lt;/span&gt;&lt;span class="s"&gt;quoted string obstext&lt;/span&gt;&lt;span class="se"&gt;\x80\x81\xff&lt;/span&gt;&lt;span class="s"&gt; quoted_pair: &lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="se"&gt;\&amp;#34;\r\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;1234521345&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;0&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;a:b&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;~|`_^.+*&amp;#39;&amp;amp;%$#!-0a: ~!@#$%^&amp;amp;*()_+&lt;/span&gt;&lt;span class="se"&gt;\x80\x81\xff\r\n&lt;/span&gt;&lt;span class="s"&gt; obs fold &lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;12345678901234521345&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;abc-def&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;hello=world&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;aaaa&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;a0-!#$%&amp;amp;&amp;#39;*+.^_`|~=quoted string obstext&lt;/span&gt;&lt;span class="se"&gt;\x80\x81\xff&lt;/span&gt;&lt;span class="s"&gt; quoted_pair: a&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;a: b&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;~|`_^.+*&amp;#39;&amp;amp;%$#!-0a: ~!@#$%^&amp;amp;*()_+&lt;/span&gt;&lt;span class="se"&gt;\x80\x81\xff&lt;/span&gt;&lt;span class="s"&gt; obs fold&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;echo_string_handler&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;p&gt;这个单测主要是为了测试 httpd 是否能正确解析 chunked 数据——通过 &lt;code&gt;chunked_source_impl&lt;/code&gt;；&lt;/p&gt;</description></item><item><title>Seastar: temporary buffer</title><link>https://chenjianyong.com/zh/blog/2022/seastar-temporary-buffer/</link><pubDate>Sat, 16 Jul 2022 00:00:00 +0000</pubDate><guid>https://chenjianyong.com/zh/blog/2022/seastar-temporary-buffer/</guid><description>&lt;h2 id="preface"&gt;Preface&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;temporary_buffer&lt;/code&gt; 是 Seastar 提供的一种自我管理(self-managed)字节缓冲区，它类似于 &lt;code&gt;std::string&lt;/code&gt; 或者 &lt;code&gt;std::unique_ptr&amp;lt;char[]&amp;gt;&lt;/code&gt;，但是提供了一些更加灵活的内存管理机制，比如它可以独占底层的缓冲区，也可以和其他 &lt;code&gt;temporary_buffer&lt;/code&gt; 共享底层缓冲区、甚至只共享其他 &lt;code&gt;temporay_buffer&lt;/code&gt; 底层缓冲区的一部分&amp;hellip;，因为这些功能，这个数据结构在 Seastar 以及 Scylla/RedPanda 等基于 Seastar 的项目中使用得非常广泛&lt;/p&gt;
&lt;h2 id="temporary-buffer"&gt;temporary buffer&lt;/h2&gt;
&lt;p&gt;首先来看看其结构定义：&lt;/p&gt;
&lt;figure class="code" data-lang="c&amp;#43;&amp;#43;"&gt;
 &lt;figcaption&gt;&lt;span class="code-lang"&gt;c&amp;#43;&amp;#43;&lt;/span&gt;&lt;button class="code-copy" type="button" aria-label="复制代码"&gt;复制&lt;/button&gt;
 &lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c++" data-lang="c++"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt; &lt;span class="n"&gt;CharType&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;temporary_buffer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;CharType&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;_buffer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;_size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;deleter&lt;/span&gt; &lt;span class="n"&gt;_deleter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;p&gt;非常简单的一个结构，其中 &lt;code&gt;_buffer&lt;/code&gt; 就是其底层缓冲区，&lt;code&gt;_size&lt;/code&gt; 就是该缓冲区的大小；但是需要注意的是，由于 &lt;code&gt;temporay_buffer&lt;/code&gt; 是可以从其他 &lt;code&gt;temporary_buffer&lt;/code&gt; 共享的(甚至只共享一部分)，所以 &lt;code&gt;_buffer&lt;/code&gt; 可能并是最初分配的内存的起始地址，因此 &lt;code&gt;_size&lt;/code&gt; 也可能并不是最初分配内存的大小&lt;/p&gt;
&lt;p&gt;二者的关系可能是这样：&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;
 &lt;source type="image/webp" srcset="https://chenjianyong.com/images/blog/seastar/seastar-temporary-buffer_hu_5f46bdf3c0deddae.webp 480w, https://chenjianyong.com/images/blog/seastar/seastar-temporary-buffer_hu_7fcf4ae892236f2c.webp 768w, https://chenjianyong.com/images/blog/seastar/seastar-temporary-buffer_hu_19ce598040831c11.webp 1046w" sizes="(max-width: 720px) 100vw, 720px"&gt;
 &lt;img src="https://chenjianyong.com/images/blog/seastar/seastar-temporary-buffer_hu_31935ecab70356bd.png"
 alt="seastar-temporary-buffer"
 width="1046" height="502"
 loading="lazy" decoding="async"&gt;
 &lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;而 &lt;code&gt;deleter&lt;/code&gt; 自然就是用来释放该内存的工具了，相关逻辑暂且按下不表，后面会用另外一个 &lt;a href="https://chenjianyong.com/zh/blog/2022/seastar-temporary-buffer/#deleter"&gt;section&lt;/a&gt; 来解读，还是很有趣的&lt;/p&gt;
&lt;h3 id="构造--析构"&gt;构造 &amp;amp; 析构&lt;/h3&gt;
&lt;p&gt;首先来看看它的构造和析构函数：&lt;/p&gt;
&lt;figure class="code" data-lang="c&amp;#43;&amp;#43;"&gt;
 &lt;figcaption&gt;&lt;span class="code-lang"&gt;c&amp;#43;&amp;#43;&lt;/span&gt;&lt;button class="code-copy" type="button" aria-label="复制代码"&gt;复制&lt;/button&gt;
 &lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c++" data-lang="c++"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;explicit&lt;/span&gt; &lt;span class="nf"&gt;temporary_buffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;_buffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;static_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;CharType&lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;malloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CharType&lt;/span&gt;&lt;span class="p"&gt;)))),&lt;/span&gt; &lt;span class="n"&gt;_size&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_deleter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;make_free_deleter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_buffer&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;_buffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;bad_alloc&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;temporary_buffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CharType&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;deleter&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;noexcept&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;_buffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;_size&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;_deleter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;temporary_buffer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;noexcept&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;_buffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nullptr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_size&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;p&gt;一个是默认构造函数，另一个则是指定缓冲区的大小，然后用 &lt;code&gt;malloc&lt;/code&gt; 分配指定大小的缓冲区，此时 &lt;code&gt;deleter&lt;/code&gt; 通过 &lt;code&gt;make_free_deleter&lt;/code&gt; 构造出来，它的功能和它的名字一样：通过 &lt;code&gt;std::free&lt;/code&gt; 释放 &lt;code&gt;_buffer&lt;/code&gt;；还有一个则是直接传入 raw buffer 和 size，以及自定义&lt;code&gt;deleter&lt;/code&gt;&lt;/p&gt;</description></item><item><title>Seastar: 用户线程</title><link>https://chenjianyong.com/zh/blog/2022/seastar-%E7%94%A8%E6%88%B7%E7%BA%BF%E7%A8%8B/</link><pubDate>Sun, 22 May 2022 00:00:00 +0000</pubDate><guid>https://chenjianyong.com/zh/blog/2022/seastar-%E7%94%A8%E6%88%B7%E7%BA%BF%E7%A8%8B/</guid><description>&lt;h2 id="preface"&gt;Preface&lt;/h2&gt;
&lt;p&gt;通常我们在 seastar 中写代码是不能阻塞的，如果我们希望在一段异步代码之后执行完毕之后开始执行另外一个逻辑，那么我们就需要通过 continuation 的方式将其串联起来，比如：&lt;/p&gt;
&lt;figure class="code" data-lang="c&amp;#43;&amp;#43;"&gt;
 &lt;figcaption&gt;&lt;span class="code-lang"&gt;c&amp;#43;&amp;#43;&lt;/span&gt;&lt;button class="code-copy" type="button" aria-label="复制代码"&gt;复制&lt;/button&gt;
 &lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c++" data-lang="c++"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;seastar&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;then&lt;/span&gt;&lt;span class="p"&gt;([]()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="cm"&gt;/* another code piece */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;p&gt;而不能直接调用 &lt;code&gt;future::get()&lt;/code&gt; 或者 &lt;code&gt;future::wait()&lt;/code&gt;：&lt;/p&gt;
&lt;figure class="code" data-lang="c&amp;#43;&amp;#43;"&gt;
 &lt;figcaption&gt;&lt;span class="code-lang"&gt;c&amp;#43;&amp;#43;&lt;/span&gt;&lt;button class="code-copy" type="button" aria-label="复制代码"&gt;复制&lt;/button&gt;
 &lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c++" data-lang="c++"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;seastar&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* another code piece */&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;p&gt;以上代码在 &lt;code&gt;wait()&lt;/code&gt; 的过程中就会 core dump。&lt;/p&gt;
&lt;p&gt;但是 seastar 提供了 &lt;code&gt;seastar::thread&lt;/code&gt; 这个工具，通过它，我们可以正常执行可能导致阻塞(即 &lt;code&gt;future::wait()&lt;/code&gt;)的代码：&lt;/p&gt;
&lt;figure class="code" data-lang="c&amp;#43;&amp;#43;"&gt;
 &lt;figcaption&gt;&lt;span class="code-lang"&gt;c&amp;#43;&amp;#43;&lt;/span&gt;&lt;button class="code-copy" type="button" aria-label="复制代码"&gt;复制&lt;/button&gt;
 &lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c++" data-lang="c++"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;ss&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kr"&gt;thread&lt;/span&gt; &lt;span class="n"&gt;th&lt;/span&gt;&lt;span class="p"&gt;([]()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;chrono_literals&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ss&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Hello, seastar thread!&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ss&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;do_with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;th&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;[](&lt;/span&gt;&lt;span class="n"&gt;seastar&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kr"&gt;thread&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;th&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;th&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;p&gt;实际上其内部并没有阻塞，但是却产生了以同步方式写异步代码的效果(通过 &lt;code&gt;ucontext&lt;/code&gt;)，有点 async/await 的感觉；这个工具在单测中用的非常普遍，而且像 scylla 和 redpanda 的 &lt;code&gt;main&lt;/code&gt; 函数都是通过它启动的。&lt;/p&gt;
&lt;h2 id="seastarasync"&gt;&lt;code&gt;seastar::async&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;虽然我们可以像上面一样直接使用 &lt;code&gt;seastar::thread&lt;/code&gt;，但是却要处理等待 thread 结束(&lt;code&gt;join()&lt;/code&gt;)、生命周期管理等问题，所以 seastar 更推荐我们使用 &lt;code&gt;seastar::async&lt;/code&gt; 这个函数，比如之前的代码通过该函数可以改写成这样：&lt;/p&gt;</description></item><item><title>ucontext and coroutine</title><link>https://chenjianyong.com/zh/blog/2022/ucontext-and-coroutine/</link><pubDate>Sun, 08 May 2022 00:00:00 +0000</pubDate><guid>https://chenjianyong.com/zh/blog/2022/ucontext-and-coroutine/</guid><description>&lt;h2 id="preface"&gt;Preface&lt;/h2&gt;
&lt;p&gt;最近在看 &lt;a href="http://docs.seastar.io/master/tutorial.html#seastarthread"&gt;&lt;code&gt;seastar::thread&lt;/code&gt;&lt;/a&gt; 的实现，暂且不说它的巧妙(实际上目前还没有完全看懂，但是 Seastar 出品，必属精品)，我首先注意到了 &lt;em&gt;ucontext&lt;/em&gt;，这是 &lt;code&gt;seastar::thread&lt;/code&gt; 中能够等待一个 unavailable future 的关键，之前没有接触过这套 API，网上搜索了一下相关资料才了解到它居然可以用来实现协程，顿时有了兴趣。&lt;/p&gt;
&lt;p&gt;学习 OS 时我们就知道线程有几种实现方式：在内核态中实现、在用户态中实现以及混合实现；内核级线程我们已经在 &lt;em&gt;pthread&lt;/em&gt; 中见识过了，用户态的线程，或者说协程，在不少语言中都有实现，比如 Lua 的 coroutine，Golang 的 goroutine。&lt;/p&gt;
&lt;p&gt;对于 &lt;em&gt;pthread&lt;/em&gt; 线程，操作系统会对它们进行调度，使用者需要做的更多是处理线程之间的通信与同步；而到了 协程，则不是这样了，OS 压根不知道它们的存在，所以它们的调度也得由使用者来做，比如 Lua 的 coroutine——用户需要决定该执行哪一个协程以及何时切换到其他协程，Golang 的 goroutine(GMP 模型应该看做是混合实现)则更近一步——从语言层面就接管了协程的调度，大大减少了协程的使用负担，用户只需要专注于自己的业务逻辑——放心地 &lt;code&gt;go&lt;/code&gt; ，Golang runtime 自会让 goroutine 之间高效地配合运行。&lt;/p&gt;
&lt;h2 id="ucontext"&gt;ucontext&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;ucontext&lt;/em&gt; 也可以用来实现协程，它整体来看还是类似于 Lua coroutine —— 需要用户去调度执行；我们知道，不论是 thread 还是 coroutine 调度/切换，都需要保存当时的执行上下文，以便后续可以回去继续执行；thread 的上下文由 OS 保存维护，对用户是透明的；而这里 coroutine 要用户来进行调度，所以其上下文对用户自然也是可见的——就是 &lt;em&gt;ucontext&lt;/em&gt;，即 user thread context——用户级线程的执行环境，其中保存着 coroutine 执行所需要的栈、寄存器、信号等信息；通过它，我们可以很方便地在 uthread 之间进行切换&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ucontext_t&lt;/code&gt;在 Linux 5.15 中其定义如下：&lt;/p&gt;
&lt;figure class="code" data-lang="c"&gt;
 &lt;figcaption&gt;&lt;span class="code-lang"&gt;c&lt;/span&gt;&lt;button class="code-copy" type="button" aria-label="复制代码"&gt;复制&lt;/button&gt;
 &lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;ucontext_t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;__ctx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uc_flags&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;ucontext_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;uc_link&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;stack_t&lt;/span&gt; &lt;span class="n"&gt;uc_stack&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;mcontext_t&lt;/span&gt; &lt;span class="n"&gt;uc_mcontext&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;sigset_t&lt;/span&gt; &lt;span class="n"&gt;uc_sigmask&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;_libc_fpstate&lt;/span&gt; &lt;span class="n"&gt;__fpregs_mem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;__extension__&lt;/span&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;__ssp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="kt"&gt;ucontext_t&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ss_sp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;ss_flags&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;ss_size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="kt"&gt;stack_t&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;p&gt;其中以 &lt;code&gt;uc&lt;/code&gt; 开头的几个字段是比较常用的：&lt;/p&gt;</description></item><item><title>Seastar: semaphore</title><link>https://chenjianyong.com/zh/blog/2022/seastar-semaphore/</link><pubDate>Wed, 04 May 2022 00:00:00 +0000</pubDate><guid>https://chenjianyong.com/zh/blog/2022/seastar-semaphore/</guid><description>&lt;h2 id="preface"&gt;Preface&lt;/h2&gt;
&lt;p&gt;最近在实现 &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API"&gt;fetch 接口&lt;/a&gt;时, 需要对单个 JS 脚本的单次执行过程中可以发起的 fetch 操作数进行限制(和 CloudFlare Workers &lt;a href="https://developers.cloudflare.com/workers/platform/limits/#simultaneous-open-connections"&gt;类似&lt;/a&gt;):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;总量限制：超过了则后续的 fetch 操作都将直接失败&lt;/li&gt;
&lt;li&gt;并发限制：超过了则后续的 fetch 请求将会被延迟(postpone)执行，直到有其他执行着的 fetch 请求结束&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;第一点很简单, 用一个计数器即可解决; 关键在于第二个, 要将超出了并发限制的 fetch 操作阻塞住, 直到有其他 fetch 操作结束(即返回的 promise 被 resolve)再唤醒它们执行.&lt;/p&gt;
&lt;p&gt;这个需求听起来似乎很熟悉？可以换一种说法，将「同一个时刻可运行的 fetch 请求」视为一种资源，这个资源是可以重复利用的(这一点是并发限制和总量限制的主要区别)：发起一个 fetch 请求相当于拿走一份资源，结束一个 fetch 请求相当于归还一份资源；且这个资源并非无限，所以当资源被拿完之后再想拿就等着直到有人归还资源。&lt;/p&gt;
&lt;p&gt;说到这里就很清晰了，这个问题就是信号量(semaphore)&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;要解决的：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In computer science, a semaphore is a variable or abstract data type used to control access to a common resource by multiple threads and avoid critical section problems in a concurrent system such as a multitasking operating system.&lt;/p&gt;</description></item><item><title>Seastar: 系统调用线程</title><link>https://chenjianyong.com/zh/blog/2022/seastar-%E7%B3%BB%E7%BB%9F%E8%B0%83%E7%94%A8%E7%BA%BF%E7%A8%8B/</link><pubDate>Mon, 18 Apr 2022 00:00:00 +0000</pubDate><guid>https://chenjianyong.com/zh/blog/2022/seastar-%E7%B3%BB%E7%BB%9F%E8%B0%83%E7%94%A8%E7%BA%BF%E7%A8%8B/</guid><description>&lt;h2 id="preface"&gt;Preface&lt;/h2&gt;
&lt;p&gt;在 Seastar 中，文件相关的操作并不直接由 reactor 线程(工作线程)执行，而是被 offload 到一个专门的线程中去执行，为此 Seastar 在 &lt;code&gt;reactor&lt;/code&gt; 中提供了诸多文件操作相关的方法；比如重命名一个文件就可以使用 &lt;code&gt;rename_file&lt;/code&gt; 方法：&lt;/p&gt;
&lt;figure class="code" data-lang="c&amp;#43;&amp;#43;"&gt;
 &lt;figcaption&gt;&lt;span class="code-lang"&gt;c&amp;#43;&amp;#43;&lt;/span&gt;&lt;button class="code-copy" type="button" aria-label="复制代码"&gt;复制&lt;/button&gt;
 &lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c++" data-lang="c++"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;ss&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ss&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rename_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;hello.txt&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;world.txt&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;then_wrapped&lt;/span&gt;&lt;span class="p"&gt;([](&lt;/span&gt;&lt;span class="n"&gt;ss&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;fut&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fut&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;failed&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;rename file failed: {}&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fut&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_exception&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ss&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_ready_future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;p&gt;所有这些文件操作相关的函数都返回 future&lt;/p&gt;
&lt;h2 id="源码剖析"&gt;源码剖析&lt;/h2&gt;
&lt;p&gt;每个 reactor 中都有一个类型为 &lt;code&gt;thread_pool&lt;/code&gt; 的变量，但是我觉得有点名不副实，因为它并不是一个 pool，而只是一个单独的线程——仅仅用于执行文件相关的 syscall，所以叫 syscall thread 或许会更好一些；不过这些都是细枝末节，先看看 &lt;code&gt;rename_file&lt;/code&gt; 的实现：&lt;/p&gt;
&lt;figure class="code" data-lang="c&amp;#43;&amp;#43;"&gt;
 &lt;figcaption&gt;&lt;span class="code-lang"&gt;c&amp;#43;&amp;#43;&lt;/span&gt;&lt;button class="code-copy" type="button" aria-label="复制代码"&gt;复制&lt;/button&gt;
 &lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c++" data-lang="c++"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;reactor&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;rename_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string_view&lt;/span&gt; &lt;span class="n"&gt;old_pathname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string_view&lt;/span&gt; &lt;span class="n"&gt;new_pathname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;noexcept&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// Allocating memory for a sstring can throw, hence the futurize_invoke
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;futurize_invoke&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;old_pathname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_pathname&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;_thread_pool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;submit&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;syscall_result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;old_pathname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sstring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;old_pathname&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;new_pathname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sstring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_pathname&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrap_syscall&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;rename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;old_pathname&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c_str&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;new_pathname&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c_str&lt;/span&gt;&lt;span class="p"&gt;()));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="n"&gt;then&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;old_pathname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sstring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;old_pathname&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;new_pathname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sstring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_pathname&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;syscall_result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;sr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;sr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;throw_fs_exception_if_error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;rename failed&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;old_pathname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_pathname&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;make_ready_future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;p&gt;逻辑非常简单，就是往 syscall thread 中提交一个任务，该任务也不过是简单地调用了一下 &lt;code&gt;rename&lt;/code&gt;&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt; 这个系统调用；如果该调用出错，则抛出异常——当然被 &lt;code&gt;futurize_invoke&lt;/code&gt; 捕获并转换为一个 exceptional future 返回给调用方。&lt;/p&gt;</description></item><item><title>Seastar：核间通信</title><link>https://chenjianyong.com/zh/blog/2022/seastar%E6%A0%B8%E9%97%B4%E9%80%9A%E4%BF%A1/</link><pubDate>Sat, 02 Apr 2022 00:00:00 +0000</pubDate><guid>https://chenjianyong.com/zh/blog/2022/seastar%E6%A0%B8%E9%97%B4%E9%80%9A%E4%BF%A1/</guid><description>&lt;h2 id="preface"&gt;Preface&lt;/h2&gt;
&lt;p&gt;虽然 Seastar 号称 share-nothing&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;，但是现代服务器开发中仍免不了需要核间通信；Seastar 为此在 &lt;code&gt;smp&lt;/code&gt; 类中提供了 &lt;code&gt;submit_to&lt;/code&gt; 方法用于向其他线程的 reactor 提交任务并执行：&lt;/p&gt;
&lt;figure class="code" data-lang="c&amp;#43;&amp;#43;"&gt;
 &lt;figcaption&gt;&lt;span class="code-lang"&gt;c&amp;#43;&amp;#43;&lt;/span&gt;&lt;button class="code-copy" type="button" aria-label="复制代码"&gt;复制&lt;/button&gt;
 &lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c++" data-lang="c++"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;futurize_t&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;invoke_result_t&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Func&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;submit_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Func&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;noexcept&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;p&gt;比如下面的代码：&lt;/p&gt;
&lt;figure class="code" data-lang="c&amp;#43;&amp;#43;"&gt;
 &lt;figcaption&gt;&lt;span class="code-lang"&gt;c&amp;#43;&amp;#43;&lt;/span&gt;&lt;button class="code-copy" type="button" aria-label="复制代码"&gt;复制&lt;/button&gt;
 &lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c++" data-lang="c++"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;ss&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;run on shard-&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;ss&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;this_shard_id&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ss&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;smp&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;submit_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;run on shard-&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;ss&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;this_shard_id&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;p&gt;首先在当前 shard 打印其 id，然后往 id 为 1 的 shard 提交一个异步任务，该异步任务也只是简单地打印出所在 shard 的 id&lt;/p&gt;
&lt;p&gt;使用 &lt;code&gt;app_template&lt;/code&gt; 执行该函数得到结果：&lt;/p&gt;
&lt;figure class="code" data-lang="shell"&gt;
 &lt;figcaption&gt;&lt;span class="code-lang"&gt;shell&lt;/span&gt;&lt;button class="code-copy" type="button" aria-label="复制代码"&gt;复制&lt;/button&gt;
 &lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;% sudo ./my_app -c &lt;span class="m"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;run on shard-0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;run on shard-1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;p&gt;的确第二句 &lt;code&gt;std::cout&lt;/code&gt; 是在 shard-1 上执行的；这里需要注意由于使用了两个 shard，所以至少需要使用两个核(&lt;code&gt;-c 2&lt;/code&gt;)。&lt;/p&gt;
&lt;h2 id="源码剖析"&gt;源码剖析&lt;/h2&gt;
&lt;p&gt;这里涉及到两个核之间的通信，所以有必要先规定几个叫法：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;local core&lt;/strong&gt;/&lt;strong&gt;local shard&lt;/strong&gt;/&lt;strong&gt;local reactor&lt;/strong&gt;：指发起通信的一方&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;remote core&lt;/strong&gt;/&lt;strong&gt;remote shard&lt;/strong&gt;/&lt;strong&gt;remote reactor&lt;/strong&gt;：指接收方&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;前面提到的 &lt;code&gt;submit_to&lt;/code&gt; 函数实际上是以默认的 &lt;code&gt;smp_submit_to_options&lt;/code&gt; 参数调用的下面这个函数：&lt;/p&gt;</description></item><item><title>Seastar: loop utility</title><link>https://chenjianyong.com/zh/blog/2022/seastar-loop-utility/</link><pubDate>Sat, 26 Mar 2022 00:00:00 +0000</pubDate><guid>https://chenjianyong.com/zh/blog/2022/seastar-loop-utility/</guid><description>&lt;h2 id="preface"&gt;Preface&lt;/h2&gt;
&lt;p&gt;循环是绝大多数编程语言中必不可少的控制结构，比如 C++ 对数组中的元素求和：&lt;/p&gt;
&lt;figure class="code" data-lang="c&amp;#43;&amp;#43;"&gt;
 &lt;figcaption&gt;&lt;span class="code-lang"&gt;c&amp;#43;&amp;#43;&lt;/span&gt;&lt;button class="code-copy" type="button" aria-label="复制代码"&gt;复制&lt;/button&gt;
 &lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c++" data-lang="c++"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ints&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;ints&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;ints&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;p&gt;然而在 Seastar 中，写循环却不是一件容易的事情——当然不是上面这种不涉及到任何的异步操作的循环，而是指循环重复执行一个异步操作。比如我们想实现这样一个 &lt;code&gt;search&lt;/code&gt; 函数：它依次从 Google、Bing 和 Baidu 搜索，有一个成功则将其内容输出至标准输出并停止搜索；或许我们可以马上写出下面这样一段代码：&lt;/p&gt;
&lt;figure class="code" data-lang="c&amp;#43;&amp;#43;"&gt;
 &lt;figcaption&gt;&lt;span class="code-lang"&gt;c&amp;#43;&amp;#43;&lt;/span&gt;&lt;button class="code-copy" type="button" aria-label="复制代码"&gt;复制&lt;/button&gt;
 &lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c++" data-lang="c++"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;extern&lt;/span&gt; &lt;span class="n"&gt;ss&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;domains&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;www.google.com&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;www.bing.com&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;www.baidu.com&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;domains&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;fut&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;domains&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;fut&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_failed&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;fut&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get0&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;p&gt;然而 &lt;code&gt;fetch&lt;/code&gt; 函数是一个异步操作，也就是说，这个函数不会阻塞，而是立即返回；而它返回的 &lt;code&gt;future&lt;/code&gt; 很大程度上不是 ready 的，所以我们无法判断其状态，除非我们等待，然而这就失去了异步的意义(而且 Seastar 不允许我们在非 &lt;code&gt;seastar::thread&lt;/code&gt; 环境中等待一个 future)。&lt;/p&gt;
&lt;p&gt;再退一步，就算我们不考虑「有一个成功则返回」这个逻辑，而只是「依次向 Google、Bing 和 Baidu 发起请求」，我们也做不到：&lt;/p&gt;
&lt;figure class="code" data-lang="c&amp;#43;&amp;#43;"&gt;
 &lt;figcaption&gt;&lt;span class="code-lang"&gt;c&amp;#43;&amp;#43;&lt;/span&gt;&lt;button class="code-copy" type="button" aria-label="复制代码"&gt;复制&lt;/button&gt;
 &lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c++" data-lang="c++"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;domains&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;domains&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="n"&gt;then_wrapped&lt;/span&gt;&lt;span class="p"&gt;([](&lt;/span&gt;&lt;span class="n"&gt;ss&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;fut&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fut&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;failed&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;fetch FAILED: &amp;#34;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;fut&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_exception&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;fetch SUCCEEDED: &amp;#34;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;fut&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get0&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;p&gt;还是之前的原因，&lt;code&gt;fetch&lt;/code&gt; 是一个异步操作不会阻塞而是直接返回，所以这里无法保证「在前一个操作完成之后再进行下一个」这个逻辑。&lt;/p&gt;</description></item><item><title>Seastar: FPC(2)</title><link>https://chenjianyong.com/zh/blog/2022/seastar-fpc2/</link><pubDate>Wed, 09 Mar 2022 00:00:00 +0000</pubDate><guid>https://chenjianyong.com/zh/blog/2022/seastar-fpc2/</guid><description>&lt;h2 id="preface"&gt;Preface&lt;/h2&gt;
&lt;p&gt;这里不打算完整地解释 Seastar 中 future&amp;amp;promise 的实现，里面旁枝末节实在太多，比如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;API 的兼容性处理&lt;/li&gt;
&lt;li&gt;针对不同平台的优化&lt;/li&gt;
&lt;li&gt;针对 Debug 编译的特殊处理&lt;/li&gt;
&lt;li&gt;各种 Modern C++ 特性的使用&lt;/li&gt;
&lt;li&gt;针对 GCC/Clang 做的各种编译优化&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所以还是希望抓住其中的一些重难点以及做的一些优化进行分析。&lt;/p&gt;
&lt;p&gt;这个系列的第一篇文章&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;中已经 future&amp;amp;promise 的大致实现流程进行了解释，Seastar 整体思想与之类似，但是还是有一些不同&lt;sup id="fnref:2"&gt;&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref"&gt;2&lt;/a&gt;&lt;/sup&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Seastar 作为一个网络框架，绝大多数时候面对的是重 I/O 的任务，所以它并不使用扩展性并不强的多线程模型，而是采用事件驱动的方式异步执行用户代码&lt;/li&gt;
&lt;li&gt;因为 future&amp;amp;promise 都在同一个线程中操作，所以也不需要加锁，所以忘记前面的 &lt;code&gt;std::mutex&lt;/code&gt; 和 &lt;code&gt;std::condition_variable&lt;/code&gt; 吧&lt;/li&gt;
&lt;li&gt;为了极致的性能，Seastar 中的 future&amp;amp;promise 并不需要动态分配内存，所以也忘记前面的 &lt;code&gt;std::shared_ptr&amp;lt;SharedState&amp;gt;&lt;/code&gt; 吧&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="类层次结构"&gt;类层次结构&lt;/h2&gt;
&lt;p&gt;首先看看 FPC 的类结构，这里直接放出其 UML 图：&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;
 &lt;source type="image/webp" srcset="https://chenjianyong.com/images/blog/seastar/seastar-fpc-uml_hu_a016ba05752c9aee.webp 480w, https://chenjianyong.com/images/blog/seastar/seastar-fpc-uml_hu_fe1e72db127b839d.webp 768w, https://chenjianyong.com/images/blog/seastar/seastar-fpc-uml_hu_bb6f955109cec636.webp 1280w, https://chenjianyong.com/images/blog/seastar/seastar-fpc-uml_hu_7b7466710f4489e3.webp 1540w" sizes="(max-width: 720px) 100vw, 720px"&gt;
 &lt;img src="https://chenjianyong.com/images/blog/seastar/seastar-fpc-uml_hu_3488a1929f2373bd.png"
 alt="seastar-fpc-uml"
 width="1540" height="1168"
 loading="lazy" decoding="async"&gt;
 &lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;非常复杂的层次结构，关于图片有几点注意：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对于模板类，在 UML 图矩形的右上角标注了其模板类型参数&lt;/li&gt;
&lt;li&gt;&lt;code&gt;uninitialized_wrapper_base&lt;/code&gt; 有两种偏特化实现，但是这里只标注了其一&lt;/li&gt;
&lt;li&gt;存在 &lt;code&gt;public&lt;/code&gt; 和 &lt;code&gt;private&lt;/code&gt; 继承，但是在 UML 图中没有表示出来&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;从之前的 &lt;code&gt;SharedState&lt;/code&gt; 我们可以总结出，&lt;code&gt;future&lt;/code&gt; 和 &lt;code&gt;proimise&lt;/code&gt; 的共享状态需要包含 &lt;code&gt;future&lt;/code&gt; 的状态，异常值、数据；在 Seastar 中这一角色由 &lt;code&gt;future_state&lt;/code&gt; 承担：其中数据从 &lt;code&gt;uninitialize_wrapper&lt;/code&gt; 中继承，状态、异常值则从 &lt;code&gt;future_state_base&lt;/code&gt; 中继承。&lt;/p&gt;</description></item><item><title>Seastar: FPC(1)</title><link>https://chenjianyong.com/zh/blog/2022/seastar-fpc1/</link><pubDate>Sun, 06 Mar 2022 00:00:00 +0000</pubDate><guid>https://chenjianyong.com/zh/blog/2022/seastar-fpc1/</guid><description>&lt;h2 id="preface"&gt;Preface&lt;/h2&gt;
&lt;p&gt;主要讲的是 future&amp;amp;promise 一些基本概念以及设计原理，但是因为 Seastar 中的实现&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;非常复杂(毕竟是工业级产品，且经过了 LLVM 大牛的大量优化，多了许多与核心实现其实并没有关系的逻辑)，所以我并不打算直接硬上(其实之前尝试过好几次，但是看完了之后还是迷迷糊糊一知半解，所以打算换一种方法)，而是打算借助 CppCon 2015 上的一个 presentation&lt;sup id="fnref:2"&gt;&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref"&gt;2&lt;/a&gt;&lt;/sup&gt; 来介绍它的基本原理和简易实现；BTW，这个 presentation 的确讲的非常好，力荐！&lt;/p&gt;
&lt;h2 id="future-and-promise"&gt;Future and Promise&lt;/h2&gt;
&lt;p&gt;标题中的 FPC 指的是 &lt;strong&gt;Future&lt;/strong&gt;、&lt;strong&gt;Promise&lt;/strong&gt; 和 &lt;strong&gt;Continuation&lt;/strong&gt; 这三个概念，这是并发编程中非常常见的一种编程模型；首先不管 Continuation 是什么，先了解 Future 和 Promise；Wikipedia 是这样解释&lt;sup id="fnref:3"&gt;&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref"&gt;3&lt;/a&gt;&lt;/sup&gt;的：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In computer science, &lt;strong&gt;future&lt;/strong&gt;, &lt;strong&gt;promise&lt;/strong&gt;, &lt;strong&gt;delay&lt;/strong&gt;, and &lt;strong&gt;deferred&lt;/strong&gt; refer to constructs used for synchronizing program execution in some concurrent programming languages. They describe an object that acts as a proxy for a result that is initially unknown, usually because the computation of its value is not yet complete.&lt;/p&gt;</description></item><item><title>Boost: 侵入式容器</title><link>https://chenjianyong.com/zh/blog/2022/boost-%E4%BE%B5%E5%85%A5%E5%BC%8F%E5%AE%B9%E5%99%A8/</link><pubDate>Sat, 05 Mar 2022 00:00:00 +0000</pubDate><guid>https://chenjianyong.com/zh/blog/2022/boost-%E4%BE%B5%E5%85%A5%E5%BC%8F%E5%AE%B9%E5%99%A8/</guid><description>&lt;h2 id="preface"&gt;Preface&lt;/h2&gt;
&lt;p&gt;最近在为 Lua/JS 子请求实现 HTTP 连接池，池子的大小是固定的，但是创建的连接数是由跑在我们 web server 之上的用户代码(Lua/JS)决定的，所以在空间不够时必然需要淘汰旧的连接。很容易想到 LRU 淘汰算法，通常我们使用哈希表+双向链表实现&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;：哈希表用于存储数据，并且支持 $\mathcal{O}(1)$ 查找；而双向链表用于维护元素的访问时序，并且可以$\mathcal{O}(1)$ 删除。&lt;/p&gt;
&lt;h2 id="侵入式容器"&gt;侵入式容器&lt;/h2&gt;
&lt;p&gt;现在我已经有了哈希表，只是缺一个双向链表记录元素的访问时序。很容易想到 STL 中的 &lt;code&gt;std::list&lt;/code&gt;，这是最常见的选择，但最终我没有用它，而是选择了 &lt;code&gt;boost::intrusive::list&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;std::list&lt;/code&gt;(以及标准库中的其他容器)是非侵入式的，而 &lt;code&gt;boost::intrusive::list&lt;/code&gt; 则是一种侵入式容器。所谓侵入式和非侵入式，其实指的是容器是否入侵了对容器所容纳的元素类型。&lt;/p&gt;
&lt;p&gt;对于 &lt;code&gt;std::list&lt;/code&gt;，其节点和原始对象的关系如下：&lt;/p&gt;
&lt;figure class="code" data-lang="txt"&gt;
 &lt;figcaption&gt;&lt;span class="code-lang"&gt;txt&lt;/span&gt;&lt;button class="code-copy" type="button" aria-label="复制代码"&gt;复制&lt;/button&gt;
 &lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;|--------------|
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| next |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| prev |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| |--------| |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| | OBJECT | |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| |--------| |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;|--------------|&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;p&gt;可以看到，链表节点其实是对原始对象的一层包裹，并加上了前后指针；每次插入一个对象分配节点时时，都需要将原始对象拷贝进去。&lt;/p&gt;
&lt;p&gt;如果原始对象很大，或者它不支持拷贝，那么怎么办呢？此时可以考虑让链表存储对象的指针(比如 &lt;code&gt;std::list&amp;lt;T*&amp;gt;&lt;/code&gt;)，但是这仍免不了额外的内存分配以及数据拷贝(此时有一个指针的拷贝，以及三个指针大小的内存分配，使用智能指针的话则更多，并且还会影响引用计数)。&lt;/p&gt;
&lt;p&gt;而对于 &lt;code&gt;boost::intrusive::list&lt;/code&gt;，其节点和原始对象的关系如下：&lt;/p&gt;
&lt;figure class="code" data-lang="txt"&gt;
 &lt;figcaption&gt;&lt;span class="code-lang"&gt;txt&lt;/span&gt;&lt;button class="code-copy" type="button" aria-label="复制代码"&gt;复制&lt;/button&gt;
 &lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;|--------------|
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| OBJECT |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;|--------------|&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;p&gt;对象即节点，节点即对象；也就是说侵入式容器直接将对象本身作为链表节点，所以并不会产生额外的内存分配以及数据拷贝；而链表之所以是链表，是因为元素存在着指向其他元素的链接，所以直接使用原始对象作为链表节点的话，就需要对象中本身就包含指向其他元素的指针，这是使用侵入式容器的前提(precondition)，所以对象在设计的时候就需要将其考虑进去，所以说它是&lt;strong&gt;侵入式&lt;/strong&gt;的。&lt;/p&gt;
&lt;p&gt;倘若元素只存储在一个容器中，那么二者的效率并没有区别：都需要为对象和前后指针分配内存，无非是原始对象由容器还是对象本身来分配的问题，而且 &lt;code&gt;std::list&lt;/code&gt; 会替用户管理对象的生命周期，使用起来还会更加方便。但是在 LRU 的情况下，对象需要出现在两个容器中，这个时候侵入式容器的价值就体现出来了。&lt;/p&gt;
&lt;p&gt;做一下总结&lt;sup id="fnref:2"&gt;&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref"&gt;2&lt;/a&gt;&lt;/sup&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;非侵入式链表(如 &lt;code&gt;std::list&lt;/code&gt;)：由链表来管理对象的生命周期，且不需要用户维护前后指针，但是缺点在于它需要进行额外的内存分配以及数据拷贝。&lt;/li&gt;
&lt;li&gt;侵入式链表(如&lt;code&gt;boost::intrusive::list&lt;/code&gt;)：需要用户自己在对象中加上前后指针，对象的生命周期由用户自己管理，但是不需要额外的内存分配以及数据拷贝。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;侵入式容器在平常的业务开发中使用的比较少，但是在许多框架中则使用得非常广泛，比如 Linux 内核中的 &lt;code&gt;struct list_head&lt;/code&gt;，Nginx 中的 &lt;code&gt;ngx_queue_t&lt;/code&gt; 和 &lt;code&gt;ngx_rbtree_t&lt;/code&gt;&amp;hellip;&lt;/p&gt;</description></item><item><title>V8: 模板(1)</title><link>https://chenjianyong.com/zh/blog/2022/v8-%E6%A8%A1%E6%9D%BF1/</link><pubDate>Thu, 17 Feb 2022 00:00:00 +0000</pubDate><guid>https://chenjianyong.com/zh/blog/2022/v8-%E6%A8%A1%E6%9D%BF1/</guid><description>&lt;h2 id="preface"&gt;Preface&lt;/h2&gt;
&lt;p&gt;当我们在 web server 中做 v8 扩展开发时，我们在做些什么？&lt;/p&gt;
&lt;p&gt;可以和 OpenResty 中的 Lua 类比，其中很大一部分工作是将 web server 的原生(native)能力暴露在 JS 中供用户使用。在 Lua 中写 C/C++ API 我们只需要遵守它所要求的函数签名以及参数传递机制写函数并将其注入全局环境就足够了，比如：&lt;/p&gt;
&lt;figure class="code" data-lang="c&amp;#43;&amp;#43;"&gt;
 &lt;figcaption&gt;&lt;span class="code-lang"&gt;c&amp;#43;&amp;#43;&lt;/span&gt;&lt;button class="code-copy" type="button" aria-label="复制代码"&gt;复制&lt;/button&gt;
 &lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c++" data-lang="c++"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;ngx_readfile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lua_State&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;L&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;nargs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lua_gettop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;L&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nargs&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;luaL_error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;expecting one argument but seen %d&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nargs&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ngx_str_t&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="cm"&gt;/* ... open file and read its content to text ... */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;lua_pushlstring&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;lua_pushcfunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;L&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ngx_readfile&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;lua_setglobal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;L&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;readfile&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;p&gt;这样我们就可以在 Lua 中使用 &lt;code&gt;readfile()&lt;/code&gt; 直接执行 &lt;code&gt;ngx_readfile&lt;/code&gt; 函数；事实上，Lua 标准库中所有的 API 也是这样暴露出去的。&lt;/p&gt;
&lt;p&gt;V8 中的做法也大同小异，只是通过&lt;strong&gt;模板&lt;/strong&gt;做了封装；这里所说的&lt;strong&gt;模板&lt;/strong&gt;并不是 C++ 中的 Template，而是 V8 中的概念，但既然二者都是一个名字，那必然是有相似之处的；&lt;a href="https://v8.dev/docs/embed#templates"&gt;v8 embed doc&lt;/a&gt; 中对模板的解释是这样的：&lt;/p&gt;</description></item><item><title>Lua: read-only table</title><link>https://chenjianyong.com/zh/blog/2022/lua-read-only-table/</link><pubDate>Sat, 29 Jan 2022 00:00:00 +0000</pubDate><guid>https://chenjianyong.com/zh/blog/2022/lua-read-only-table/</guid><description>&lt;h2 id="preface"&gt;Preface&lt;/h2&gt;
&lt;p&gt;Lua 中的 API 都是以 Lua table 的方式存储并提供给用户使用，拿 OpenResty 中的 &lt;code&gt;ngx.say&lt;/code&gt; API 为例：其中 &lt;code&gt;ngx&lt;/code&gt; 是全局环境(也是一个 Lua table)中一个名为 &lt;code&gt;ngx&lt;/code&gt; 的 key 对应的 value(一个 table)，而 &lt;code&gt;say&lt;/code&gt;，则是 &lt;code&gt;ngx&lt;/code&gt; 这个 table 中一个名为 &lt;code&gt;say&lt;/code&gt; 的 key 对应的 value(一个 C function)；而 Lua 标准库也是如此。&lt;/p&gt;
&lt;p&gt;在 OpenResty 的实现中，每个 Nginx worker 启动时会创建一个 Lua 虚拟机(即 &lt;code&gt;lua_State&lt;/code&gt;)，在初始化该 vm 时，会将 OpenResty 提供的 API 注入 Lua 的全局环境，以及替换掉标准库的一些实现(比如 coroutine API)，具体逻辑在 &lt;code&gt;ngx_http_lua_new_state()&lt;/code&gt; 以及 &lt;code&gt;ngx_http_lua_init_globals()&lt;/code&gt; 这两个函数中；逻辑很简单，主要是一些 Lua table 相关的操作，就不贴代码了。而后每次请求到来时，OpenResty 都会在本进程的 Lua vm 之上创建一个 coroutine 用于服务该请求，而该 coroutine 会使用之前创建好了的全局环境(具体代码可见 &lt;code&gt;ngx_http_lua_content_by_lua()&lt;/code&gt; 函数)；这样用户就可以在脚本中使用 OpenResty 提供的所有 API。&lt;/p&gt;</description></item><item><title>Lua: buffer system</title><link>https://chenjianyong.com/zh/blog/2021/lua-buffer-system/</link><pubDate>Sun, 14 Nov 2021 00:00:00 +0000</pubDate><guid>https://chenjianyong.com/zh/blog/2021/lua-buffer-system/</guid><description>&lt;h2 id="preface"&gt;Preface&lt;/h2&gt;
&lt;p&gt;最近在实现一套和 OpenResty 中的 &lt;code&gt;ngx.re.*&lt;/code&gt; 类似的 API，其中 &lt;code&gt;gsub/sub&lt;/code&gt; 这俩用到了 &lt;code&gt;luaL_Buffer&lt;/code&gt;；在数据量比较小的情况下它工作的很好，可是一旦数据量上去了，程序就开始抛出异常，不过 OpenResty 却可以正常工作，着实困扰了我一阵；查阅资料发现网上说 &lt;code&gt;luaL_Buffer&lt;/code&gt; 的确比较坑，怀疑是不是我用的方式不太对；最终通过看内部实现发现了问题所在，写这篇 blog 记录下&lt;/p&gt;
&lt;h2 id="基本使用"&gt;基本使用&lt;/h2&gt;
&lt;p&gt;可以简单将 &lt;code&gt;luaL_Buffer&lt;/code&gt; 理解为一个 String Builder，即拼接字符串的工具，Lua 它的定义为：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A string buffer allows C code to build Lua strings piecemeal.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;一般是这样使用的：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;声明一个 &lt;code&gt;luaL_Buffer&lt;/code&gt; 类型的变量 &lt;code&gt;b&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;使用 &lt;code&gt;luaL_Bufferinit(L, &amp;amp;b)&lt;/code&gt; 初始化它&lt;/li&gt;
&lt;li&gt;通过 &lt;code&gt;luaL_add*()&lt;/code&gt; 系列函数往该 buffer 中添加一部分字符串&lt;/li&gt;
&lt;li&gt;通过调用 &lt;code&gt;luaL_pushresult(&amp;amp;b)&lt;/code&gt; 结束字符串的构建，调用返回后会将最终得到的字符串放在栈顶&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;此外， manual 对 &lt;code&gt;luaL_Buffer&lt;/code&gt; 还加了一个额外的描述：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;During its normal operation, a string buffer uses a variable number of stack slots. So, while using a buffer, you cannot assume that you know where the top of the stack is. You can use the stack between successive calls to buffer operations as long as that use is balanced; that is, when you call a buffer operation, the stack is at the same level it was immediately after the previous buffer operation. (The only exception to this rule is &lt;a href="https://www.lua.org/manual/5.4/manual.html#luaL_addvalue"&gt;luaL_addvalue&lt;/a&gt; After calling &lt;a href="https://www.lua.org/manual/5.4/manual.html#luaL_pushresult"&gt;luaL_pushresult&lt;/a&gt;, the stack is back to its level when the buffer was initialized, plus the final string on its top.&lt;/p&gt;</description></item><item><title>程序员修炼之道: 务实的哲学</title><link>https://chenjianyong.com/zh/blog/2020/%E7%A8%8B%E5%BA%8F%E5%91%98%E4%BF%AE%E7%82%BC%E4%B9%8B%E9%81%93-%E5%8A%A1%E5%AE%9E%E7%9A%84%E5%93%B2%E5%AD%A6/</link><pubDate>Sat, 19 Sep 2020 00:00:00 +0000</pubDate><guid>https://chenjianyong.com/zh/blog/2020/%E7%A8%8B%E5%BA%8F%E5%91%98%E4%BF%AE%E7%82%BC%E4%B9%8B%E9%81%93-%E5%8A%A1%E5%AE%9E%E7%9A%84%E5%93%B2%E5%AD%A6/</guid><description>&lt;h2 id="preface"&gt;Preface&lt;/h2&gt;
&lt;p&gt;自接触编程以来，我看过的绝大部分书都是关于某项特定技术的，比如 &lt;a href="https://book.douban.com/subject/25708312/"&gt;C++ Primer&lt;/a&gt;、&lt;a href="https://book.douban.com/subject/26745255/"&gt;深入理解 Nginx&lt;/a&gt; 以及 OS、网络等计算机专业课相关的。诚然，这些都是必备的，但是正式工作后，越来越感觉如何成长是一个至关重要的议题，而正好《程序员修炼之道》第二版发布了，所以打算看看这本书，而实际上书的确很棒，仅第一章里面就有许多地方我深有同感，不过许多地方我想的并不全面，也缺乏归纳总结这些思想的能力；还是先摘抄一些我喜欢的段落。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;P.S(1) 20 年并没有看完这本书，22 年重新看并打算看完它；在之前的博客中发现了这篇，想想还是把它贴出来吧，因为第二遍看这本书我还是非常喜欢&lt;/li&gt;
&lt;li&gt;P.S(2) 务实(pragmatic)这个词我非常喜欢，它和靠谱(reliable)一起构成了我对他人的最高评价词，当然我也希望成为这样的人&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="一前言"&gt;一、前言&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;编程是一门技艺。简单地说，就是让计算机做你想让它做的事情（或者是你的用户想让它做的事情）。作为一名程序员，你既在倾听，又在献策；既是传译，又行独裁；你试图捕获难以捉摸的需求，并找到一种表达它们的方式，以便仅靠一台机器就可以从容应付。你试着把工作记录成文档，以便他人理解；你试着将工作工程化，这样别人就能在其上有所建树；更重要的是，你试图在项目时钟的滴答声中完成所有的这些工作。你每天都在创造小奇迹。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;你不应该拘泥于任何特定的技术，而应该拥有足够广泛的背景和经验基础，以便在特定的情况下选择合适的解决方案。你的背景来自对计算机科学基本原理的理解，而你的经验来自广泛的实际项目。理论结合实践会让你变得强大。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;调整方法去寻找适应当前的情况和环境。对所有影响项目因素的相对重要性做出判断，并通过经验找到合适的解决方案。随着工作的进展，你要不断地这样做。务实的程序员不仅把工作做完，并且做得很好。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="二务实的哲学"&gt;二、务实的哲学&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;务实的程序员的特质是什么？是他们面临问题时，在解决方案中透出的态度，风格以及理念。他们总是越过问题的表面，试着将问题放在更宽泛的上下文中综合考虑，从大局着想。毕竟，若不去了解来龙去脉，结合实际从何谈起？又怎能做出明智的妥协和合理的决策？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;当你意识到自己在说“我不知道”时，一定要接着说“——但是我会去搞清楚”。用这样的方式来表达你的不知道是非常好的，因为接着你就可以像一个专家一样承担起责任。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;不要只是因为一些东西非常危急，就去造成附带损害。破窗一扇都嫌太多。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;批判性地分析你读到和听到的东西，问几个值得思考的问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;谁从中受益&lt;/li&gt;
&lt;li&gt;有什么背景：每件事都发生在自己的背景之下，这也是为何“能解决所有问题”的方案通常是不存在的。&lt;/li&gt;
&lt;li&gt;什么时候可以在哪里工作起来：不要停留在一阶思维下（接下来会发生什么），要进行二阶思考（当它结束后还会发生什么？）。&lt;/li&gt;
&lt;li&gt;为什么这是个问题：是否存在一个基础模型以及这个基础模型是怎么工作的？&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;</description></item><item><title>归档</title><link>https://chenjianyong.com/zh/archive/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://chenjianyong.com/zh/archive/</guid><description/></item><item><title>搜索</title><link>https://chenjianyong.com/zh/search/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://chenjianyong.com/zh/search/</guid><description/></item></channel></rss>