<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Tech on nikki</title>
    <link>https://ynishimi.github.io/tags/tech/</link>
    <description>Recent content in Tech on nikki</description>
    <generator>Hugo</generator>
    <language>ja</language>
    <lastBuildDate>Sun, 15 Feb 2026 15:30:00 +0100</lastBuildDate>
    <atom:link href="https://ynishimi.github.io/tags/tech/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Paxos アルゴリズムを使う</title>
      <link>https://ynishimi.github.io/posts/2026-02-15-paxos/</link>
      <pubDate>Sun, 15 Feb 2026 15:30:00 +0100</pubDate>
      <guid>https://ynishimi.github.io/posts/2026-02-15-paxos/</guid>
      <description>&lt;h2 id=&#34;秋学期のこと&#34;&gt;秋学期のこと&lt;/h2&gt;
&lt;p&gt;秋学期は &lt;a href=&#34;https://edu.epfl.ch/coursebook/en/decentralized-systems-engineering-CS-438&#34;&gt;Decentralized systems engineering&lt;/a&gt; とか &lt;a href=&#34;https://edu.epfl.ch/coursebook/en/distributed-algorithms-CS-451&#34;&gt;Distributed algorithms&lt;/a&gt; のような授業を履修し，分散システム漬けの日々を送りました．
授業では実際に動くP2Pの分散システムをディアゴスティーニ式に作っていく課題が出され（非常に重く，細かい実装のデザインとデバッグで全ての土日が潰れる），講義で習った内容を理解していくというものでした．
このシステムのゴールは，ネットワークで接続された，複数の独立したノード間で合意を取るようなシステムの実装を行うというもの．
実装には &lt;a href=&#34;https://ja.wikipedia.org/wiki/Paxos%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0&#34;&gt;Paxos アルゴリズム&lt;/a&gt; と呼ばれるアルゴリズムを用いました．&lt;/p&gt;</description>
      <content:encoded><![CDATA[<h2 id="秋学期のこと">秋学期のこと</h2>
<p>秋学期は <a href="https://edu.epfl.ch/coursebook/en/decentralized-systems-engineering-CS-438">Decentralized systems engineering</a> とか <a href="https://edu.epfl.ch/coursebook/en/distributed-algorithms-CS-451">Distributed algorithms</a> のような授業を履修し，分散システム漬けの日々を送りました．
授業では実際に動くP2Pの分散システムをディアゴスティーニ式に作っていく課題が出され（非常に重く，細かい実装のデザインとデバッグで全ての土日が潰れる），講義で習った内容を理解していくというものでした．
このシステムのゴールは，ネットワークで接続された，複数の独立したノード間で合意を取るようなシステムの実装を行うというもの．
実装には <a href="https://ja.wikipedia.org/wiki/Paxos%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0">Paxos アルゴリズム</a> と呼ばれるアルゴリズムを用いました．</p>
<h2 id="paxos-とは">Paxos とは</h2>
<p>Paxos アルゴリズムとは，超簡単にいうと &ldquo;信頼できない（ノードに情報が伝わらない可能性がある）ネットワークで，一つの値をみんなで共有する&rdquo; ものだと思っています．
つまり，パケットが途中で失われたりするような環境でも，誰かが提案した値は全員に伝わるか，あるいは否決されるかのどちらかであることを保証するということです．</p>
<p>課題では，分散システムに関する数々の功績を残した Leslie Lamport 氏 <sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> による <a href="https://lamport.azurewebsites.net/pubs/paxos-simple.pdf">Paxos Made Simple</a> の内容に基づき，一件のファイルごとの合意をとるということが求められました．</p>
<p>論文によると， Paxos アルゴリズムは以下のような 2 つのフェーズによって合意を形成します:</p>
<h3 id="phase-1">Phase 1</h3>
<ul>
<li>値を提案するノードが，ある提案番号 n を持つ <em>prepare</em> リクエストをブロードキャストする．</li>
<li><em>prepare</em> リクエストを受け取ったノードは，提案番号 n と，過去に受け取って返答したリクエストの提案番号を比べる． n がこれまでのどの番号よりも大きい場合， n より小さい提案番号を持つ提案を受け取らないという <em>promise</em> を送り返す．また，これまでにすでに受け入れた値があれば，それも返す．</li>
</ul>
<h3 id="phase-2">Phase 2</h3>
<ul>
<li>値を提案するノードが，過半数のノードから <em>promise</em> を受け取った場合，　<em>promise</em> に含まれる，他のノードによってすでに受け入れられた値を見る．もし，そのような値があった場合，そのうち提案番号がもっとも大きい値を提案する値 v とする．そのような値がない場合，任意の値を提案する値 v とする．そして，その値 v を提案番号 n の <em>accept</em> リクエストとしてブロードキャストする．</li>
<li><em>accept</em> リクエストを受け取ったノードは， Phase 1 と同様に提案番号 n と，過去に受け取って返答したリクエストの提案番号を比べ，過去に <em>promise</em> を送り返したどの提案番号よりも n が大きい時は，その提案を受け入れる．</li>
</ul>
<p>Paxos の面白いところは，リーダーのようなものをあらかじめ割り当てることなく動作させることができるという点です．
これは，値を提案する権利と，提案を受け取る権利の両方をノードに与えることによって達成されます．提案番号をノードごとにユニークなものにしておく（例えば n 個のノードが存在する場合，ノード k は提案番号を k, n+k, 2n+k&hellip;, と増やすように決めるなど）ことなどが考えられます．</p>
<h2 id="paxos-を使って-total-order-broadcast-を作る">Paxos を使って Total Order Broadcast を作る</h2>
<p>テスト勉強をしている間，ふとこのような Paxos を使った合意は，例えばネットワークやノードが信頼できないような分散システムでの強い一貫性を保証するようなシステムに使えるのではないかと考えました．
アイデアはこうです:</p>
<ul>
<li>任意の個数の Paxos のインスタンスを使って，好きなだけ値を合意する．</li>
<li>Paxos のインスタンスそれぞれに番号を割り当てる．</li>
<li>合意した値を Paxos のインスタンス番号順に並び替えることにより，全てのノードにおいて，同一の順序で値を受け取ることができる．</li>
</ul>
<p>これは <a href="https://en.wikipedia.org/wiki/Atomic_broadcast">total order broadcast (あるいは atomic broadcast)</a> が持つべき条件を満たしています．
これは， Paxos は合意アルゴリズムであることから， termination （全ての故障していないプロセスは，いつかはある値に対し合意する）の条件を満たしていることからいえます．
これにより，全ての故障していないノードでは，ある時間 t の時点で合意を行っている Paxos のインスタンス全てにおいて合意が形成されるような時間 t&rsquo; があるといえ，これにより，各ノードは Paxos のインスタンス番号に従ってメッセージを順番に受け取っていくことができ， total order broadcast (TOB) の total order 条件（全ての故障していないノードが，同一順序でメッセージを受け取ること）が満たされるからです．</p>
<p>このようなアイデアをベースに， Paxos を使用した TOB のライブラリとしてみました (GitHub のリンクは<a href="https://github.com/ynishimi/paxos-tob">こちら</a>)．
なお，学期中の開発での反省点として，それぞれのコンポーネント同士の依存関係が大きく，バグを見つけるのが非常に大変であったということがありました．
そこで，今回はメッセージ幅やり取りを行うモジュール， Paxos 本体， Paxos を使って 1 件の合意をとるモジュール，合意アルゴリズムを使って TOB を実装するモジュールのように，インタフェースを用いて，他の部分をモックして細かくテストできるような構成を意識しました．</p>
<p>ノードを落としてみたらどうなるか，実際の環境で動かしてみるとどうかなど，これからいろいろ試してみたいと思います．</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Microsoft が彼を獲得するために，彼の拠点だったシリコンバレーに研究所を建てたという逸話もあるとか&hellip;&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded>
    </item>
    <item>
      <title>はじめての コントリビューション</title>
      <link>https://ynishimi.github.io/posts/2025-05-31-gfi/</link>
      <pubDate>Sat, 31 May 2025 22:00:00 +0900</pubDate>
      <guid>https://ynishimi.github.io/posts/2025-05-31-gfi/</guid>
      <description>&lt;p&gt;この度はじめて OSS に Pull request を送り、無事マージされました！
これまで OSS へのコントリビューションにハードルを感じていましたが、いざやってみると思ったよりもハードルが高くありませんでした。
簡単な流れを書いておこうと思います。&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>この度はじめて OSS に Pull request を送り、無事マージされました！
これまで OSS へのコントリビューションにハードルを感じていましたが、いざやってみると思ったよりもハードルが高くありませんでした。
簡単な流れを書いておこうと思います。</p>
<h2 id="やってみる">やってみる</h2>
<h3 id="取り組む-oss-を選ぶ">取り組む OSS を選ぶ</h3>
<p>去年くらいから Rust を少しずつ触っているのですが、便利な開発ツールにいつも感動していました。
今回は <a href="https://github.com/rust-lang/rustfmt">rustfmt</a> という、 rust-lang 配下のコード整形ツールのリポジトリを見てみることにしました。</p>
<h3 id="good-first-issue-をみつける"><code>good first issue</code> をみつける</h3>
<p>さっそくリポジトリの Issue を見ます。 Open な Issue のうち、 <code>good first issue</code> ラベルでフィルタします。
今回は該当するすべての Issue ですでに議論が行われていました&hellip;</p>
<p>ここで諦めかけますが、残った気力で <a href="https://github.com/rust-lang/rustfmt/issues/6202">最新の Issue</a> をのぞいてみます。</p>
<h3 id="issue-の内容を把握する">Issue の内容を把握する</h3>
<p><code>if let</code> の整形エラーが報告されています:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">impl</span><span class="w"> </span><span class="n">EarlyLintPass</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">NeedlessContinue</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="k">fn</span> <span class="nf">check_expr</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span><span class="w"> </span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">cx</span>: <span class="kp">&amp;</span><span class="nc">EarlyContext</span><span class="o">&lt;</span><span class="nb">&#39;_</span><span class="o">&gt;</span><span class="p">,</span><span class="w"> </span><span class="n">expr</span>: <span class="kp">&amp;</span><span class="nc">Expr</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="c1">// 長い pattern です。ここが整形できない様子。
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">ExprKind</span>::<span class="n">Loop</span><span class="p">(</span><span class="n">body</span><span class="p">,</span><span class="w"> </span><span class="n">label</span><span class="p">,</span><span class="w"> </span><span class="o">..</span><span class="p">)</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">ExprKind</span>::<span class="n">While</span><span class="p">(</span><span class="n">_</span><span class="p">,</span><span class="w"> </span><span class="n">body</span><span class="p">,</span><span class="w"> </span><span class="n">label</span><span class="p">)</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">ExprKind</span>::<span class="n">ForLoop</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">body</span><span class="p">,</span><span class="w"> </span><span class="n">label</span><span class="p">,</span><span class="w"> </span><span class="o">..</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="o">=</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="o">&amp;</span><span class="n">expr</span><span class="p">.</span><span class="n">kind</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="o">!</span><span class="n">in_external_macro</span><span class="p">(</span><span class="n">cx</span><span class="p">.</span><span class="n">sess</span><span class="p">,</span><span class="w"> </span><span class="n">expr</span><span class="p">.</span><span class="n">span</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="n">check_final_block_stmt</span><span class="p">(</span><span class="n">cx</span><span class="p">,</span><span class="w"> </span><span class="n">body</span><span class="p">,</span><span class="w"> </span><span class="n">label</span><span class="p">,</span><span class="w"> </span><span class="n">expr</span><span class="p">.</span><span class="n">span</span><span class="p">.</span><span class="n">ctxt</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p><code>max_width = 120</code> と設定したときに、<code>        if let ExprKind::Loop(body, label, ..) | ExprKind::While(_, body, label) | ExprKind::ForLoop { body, label, .. } =</code> （122文字）がうまく整形できないようです。
<code> =</code> の長さ（2文字です）が考慮されていないために、 <code>if let</code> と <code> =</code> の間の整形に文字数を使い過ぎてしまうようです。</p>
<p>この Issue には1年前にアサインされている人がいますが、<a href="https://github.com/rust-lang/rustfmt/pull/6224">Pull request</a> がそのままになっています。
これを見てみると、コードレビューを受けた後、 Git の操作まわりでつまずいてしまっているようです。
怒涛の <code>force push</code> の跡。
初心者の方でしょうか（自分もはじめてのプルリクエストで同じことをしてしまったら、パニックになってしまうと思います）。</p>
<p>Contributor の方がやさしく指導されていますが、その後心が折れてしまったのか目立った動きはありません。
その後、別の方が何度かやり取りされていますが、やや殺伐とした雰囲気です（ヒィー）。</p>
<p>しかし、ほとんど修正が完了している Pull request が放置されているのはもったいない。
代わりに自分が取り組むことにします。</p>
<h3 id="forkclone-してくる">Fork/Clone してくる</h3>
<p>ここから実際の作業に入ります。
この辺は <a href="https://kyotorb.connpass.com/event/311939/">OSS Gate</a> で手取り足取り教えていただいたので余裕です（ <a href="https://github.com/rust-lang-ja/book-ja/pull/246">あのときの Pull request</a> はまだマージされていませんが&hellip;）。</p>
<p>まずは rustfmt を Fork してきます。
手元のマシンに Clone します。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">nishimi@MacBook-Air ~ % ghq get git@github.com:ynishimi/rustfmt.git
</span></span><span class="line"><span class="cl">...
</span></span><span class="line"><span class="cl">warning: the following paths have collided <span class="o">(</span>e.g. <span class="k">case</span>-sensitive paths
</span></span><span class="line"><span class="cl">on a <span class="k">case</span>-insensitive filesystem<span class="o">)</span> and only one from the same
</span></span><span class="line"><span class="cl">colliding group is in the working tree:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="s1">&#39;tests/source/reorder_modules/ABCD/mod.rs&#39;</span>
</span></span><span class="line"><span class="cl">  <span class="s1">&#39;tests/source/reorder_modules/abcd/mod.rs&#39;</span>
</span></span><span class="line"><span class="cl">  <span class="s1">&#39;tests/source/reorder_modules/ZYXW/mod.rs&#39;</span>
</span></span><span class="line"><span class="cl">  <span class="s1">&#39;tests/source/reorder_modules/zyxw/mod.rs&#39;</span>
</span></span><span class="line"><span class="cl">  <span class="s1">&#39;tests/target/reorder_modules/ABCD/mod.rs&#39;</span>
</span></span><span class="line"><span class="cl">  <span class="s1">&#39;tests/target/reorder_modules/abcd/mod.rs&#39;</span>
</span></span><span class="line"><span class="cl">  <span class="s1">&#39;tests/target/reorder_modules/ZYXW/mod.rs&#39;</span>
</span></span><span class="line"><span class="cl">  <span class="s1">&#39;tests/target/reorder_modules/zyxw/mod.rs&#39;</span>
</span></span></code></pre></div><p>ファイルシステムが case-insensitive であることによるファイルの衝突が生じました😢
case-sensitive なボリュームを作成して、 Clone しなおします。</p>
<h3 id="エラーを再現する">エラーを再現する</h3>
<p>準備ができたら、エラーを確認していきます。
<a href="https://github.com/rust-lang/rustfmt/blob/master/Contributing.md">Contributing.md</a> を見て、まずはソースコードから rustfmt を実行する方法を調べます:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">cargo run --bin rustfmt -- path/to/file.rs
</span></span></code></pre></div><p>Issue にあったコードをコピーしてきて rustfmt を実行してみると、確かにエラーが生じました:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">nishimi@MacBook-Air rustfmt % cargo run --bin rustfmt -- ../test_fmt/src/test.rs 
</span></span><span class="line"><span class="cl">   Compiling rustfmt-nightly v1.8.0 <span class="o">(</span>/Volumes/dev/rustfmt<span class="o">)</span>
</span></span><span class="line"><span class="cl">    Finished <span class="sb">`</span>dev<span class="sb">`</span> profile <span class="o">[</span>unoptimized + debuginfo<span class="o">]</span> target<span class="o">(</span>s<span class="o">)</span> in 2.41s
</span></span><span class="line"><span class="cl">     Running <span class="sb">`</span>target/debug/rustfmt ../test_fmt/src/test.rs<span class="sb">`</span>
</span></span><span class="line"><span class="cl">Warning: the <span class="sb">`</span>version<span class="sb">`</span> option is deprecated. Use <span class="sb">`</span><span class="nv">style_edition</span><span class="o">=</span><span class="s2">&#34;2024&#34;</span><span class="sb">`</span> instead.
</span></span><span class="line"><span class="cl">error<span class="o">[</span>internal<span class="o">]</span>: line formatted, but exceeded maximum width <span class="o">(</span>maximum: <span class="m">120</span> <span class="o">(</span>see <span class="sb">`</span>max_width<span class="sb">`</span> option<span class="o">)</span>, found: 122<span class="o">)</span>
</span></span><span class="line"><span class="cl"> --&gt; /Volumes/dev/test_fmt/src/test.rs:3:3:121
</span></span><span class="line"><span class="cl">  <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="m">3</span> <span class="p">|</span>         <span class="k">if</span> <span class="nb">let</span> ExprKind::Loop<span class="o">(</span>body, label, ..<span class="o">)</span> <span class="p">|</span> ExprKind::While<span class="o">(</span>_, body, label<span class="o">)</span> <span class="p">|</span> ExprKind::ForLoop <span class="o">{</span> body, label, .. <span class="o">}</span> <span class="o">=</span>
</span></span><span class="line"><span class="cl">  <span class="p">|</span>                                                                                                                         ^^
</span></span><span class="line"><span class="cl">  <span class="p">|</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">warning: rustfmt has failed to format. See previous <span class="m">1</span> errors.
</span></span></code></pre></div><h3 id="コードを修正する">コードを修正する</h3>
<p>では、コードを修正していきます。
<code>git checkout -b max_width_split</code> で作業用のブランチを作成しました。</p>
<p>今回はすでにレビュー済みの Pull request が存在しているため、これを参考に修正していきます。
Pull request でも触れられていましたが、今回の変更は<code>StyleEdition::Edition2027</code>以上でのみ有効となるように <a href="https://github.com/rust-lang/rustfmt/blob/master/Contributing.md#gate-formatting-changes">Gate</a> しておきます。</p>
<h3 id="テストを作成する">テストを作成する</h3>
<p>rustfmt では <a href="https://github.com/rust-lang/rustfmt/blob/master/Contributing.md#create-test-cases">テストケースの作成</a> が必要のようです。
<code>./tests/source/</code> 下に整形前のコード、 <code>./tests/target/</code> に整形後のコードを置きます。</p>
<p><code>cargo test</code> を実行し、エラーが生じないことを確認できました！</p>
<h3 id="pull-request-を作成する">Pull request を作成する</h3>
<p>これまでの変更をコミットして、 <a href="https://github.com/rust-lang/rustfmt/pull/6572">Pull request</a> を作成します。
今回はもととなる Issue と Pull request に触れながら、変更点をまとめました。</p>
<h3 id="merge-されるのを待つ">Merge されるのを待つ</h3>
<p>無事 Merge されました☺️
今回は簡単な修正でしたが、自分のコードが rustfmt で動いているというのは嬉しいものです。</p>
<p><img alt="無事 Merge されました" loading="lazy" src="/posts/2025-05-31-gfi/successfully_merged.png"></p>
<h2 id="わかったこと">わかったこと</h2>
<h3 id="初心者もいる">初心者もいる</h3>
<p>今回実際にコントリビューションを行ってみて最も感じたのは、自分が思っているよりも初心者の方が多いということでした。
自分が Pull request を作成するにあたって、過去に Merge されたものをいくつか確認しましたが、 Description を描き慣れていない人やコードレビューでガッツリコメントされている人、途中で他の Contributor に助けてもらう人など、いろいろな人がいました。
また rustfmt リポジトリは Contributor の方がやさしくコメントをしてくださるので、あまり経験がない人でも気負わずにコントリビューションが行える環境であると感じました。</p>
<h3 id="issue-は意外と放置されている">Issue は意外と放置されている</h3>
<p>今回扱った Issue のように、何らかの理由で放置されているものは意外とたくさんあるように感じました。
放置されている Issue を拾っていくのは OSS のコントリビューション経験が浅い方でも比較的取り組みやすいと思います。</p>
<h2 id="むすび">むすび</h2>
<p>普段使っているツールの中身を見たり、修正を加えたりするのは楽しい作業でした。
今後も自分ができる範囲でコントリビューションを行っていきたいです。</p>
]]></content:encoded>
    </item>
  </channel>
</rss>
