Cursorは2026年8月17日、コードホスティング「Origin」の早期ベータ提供を始めた。翌日に公開した技術資料では、中核のGitストレージを「Continuity」と呼んでいる。通常のGitリポジトリをローカルNVMeに置きながら、プッシュされたパックファイルをS3互換ストレージ上のwrite-ahead log(WAL)にも保存する。正本は遠隔のWAL、ローカルのGitコピーは低遅延で処理するためのウォームキャッシュである。Gitとの互換性を保ったまま、複製数と書き込み待ちの関係を組み直した。

AD

Gitを置き換えず、正本の場所を変えた

Gitの主要データはパックファイルで保存・転送される。履歴を表すcommitとtree、内容を保持するblobなどのオブジェクトはDAGを構成する。あるcommitからファイルへ到達するには、次のポインタを一つずつ読まなければならない。さらにオブジェクトは別のオブジェクトを基準とするデルタ形式で圧縮されることがあり、論理的なDAGの走査にディスク上の読み出しも重なる。ネットワークファイルシステムに置くと、細かな往復遅延がこの連鎖へ入り込む。

ContinuityはGitのデータ形式を残した。プッシュ時にはパックファイルをローカルNVMeへ書き込むと同時に、個別のWALエントリーとしてS3へアップロードする。ただし、アップロードが終わった時点では変更を公開しない。サーバーはGitのreference transactionをローカルでprepareし、WALインデックスにそのエントリーへの参照を記録してから可視化する。Cursorがクライアントへ成功を返すのは、プッシュがWALへ永続化された後だ。

ここでローカルNVMeは正本ではなくなる。NVMe上のGitリポジトリは読み取りを速めるコピーとなり、失われてもWALから再構成できる。DAGの走査やパック生成、デルタ展開、repackは残る。Continuityが変えたのはGitのプロトコルではなく、耐久性と順序をどこで保証するかである。遅延に敏感なGit処理をローカルNVMeへ残し、復旧に必要な全履歴をWALへ寄せた。

3レプリカの床と、巨大モノレポの天井

GitHubは2016年、DGitというリポジトリ保存システムを公表した。後にSpokesと呼ばれるこの方式は、通常のGitリポジトリを3台のローカルSSDへ置く。書き込みを3台へ同期送信し、少なくとも2台が同じ結果を返した場合にcommitする。Gitが得意なローカルディスクアクセスを維持しながら、1台が故障しても読み書きを続けられる構成だった。

クォーラム型の複製は、レプリカを増やすほど書き込みが最も遅いノードの影響を受けやすい。読み取り能力を増やすためにレプリカを足すと、同じ台数が書き込み時の同期相手にもなる。巨大モノレポへCIから大量のcloneやfetchが集中する場面では、読み取りのための水平拡張とプッシュの待ち時間が逆方向に動く。

エージェントは反対側の問題も作る。Cursorによると、エージェントが動く環境では小規模で短命なリポジトリが大量に生まれ、その多くはほとんど使われない。各リポジトリへ3コピーを常設すれば、容量と運用負荷を浪費する。Continuityでは巨大モノレポへ数百のレプリカを割り当てる一方、小さなリポジトリは1コピーで処理できる。休眠したコピーはローカルディスクから削除し、次のアクセス時にWALから戻せるという。

Cursorが「consensusはない」と説明する範囲は、Gitレプリカ間のクォーラムやprimary選出である。順序付けの地点まで消えたわけではない。ContinuityはS3上のWALインデックスをatomic compare-and-swap(CAS)で更新し、このCASをプッシュの直列化点にする。合意形成を消したというより、正しい順序を決める仕事をレプリカ群からオブジェクトストレージ上の一つの更新へ移した設計だ。

AD

UDP通知とETag検証の役割分担

WALインデックスのCASには、競合した更新の片方だけを成功させる仕組みが要る。AWSのS3条件付き書き込みを例に取ると、If-Matchを付けたPUTは指定したETagと現行オブジェクトのETagが一致した場合に成功し、不一致なら412を返す。CursorはWALインデックスをatomic CASで更新すると説明するが、実際に使うAPIやヘッダー名は明記していない。確定しているのは、どのサーバーがプッシュを受けてもCASで更新を直列化し、競合したサーバーは新しいインデックスを取り直す仕組みまでだ。

通常時にリポジトリを置くノードは、リポジトリIDと健全なノード集合からrendezvous hashingで決める。この計算は、全リポジトリと全サーバーの対応を保持する巨大なルーティング表を必要としない。ノードが落ちて割り当て結果が変わっても、次の候補がWALからリポジトリを再構成する。壊れたコピーを正本へ戻す修理より、捨てて作り直す運用を選べる。

更新通知にはUDP gossipを使う。UDPパケットは失われ得るため、Continuityは通知を正しさの根拠にしない。読み取り時にレプリカは、自身が持つWALインデックスのETagでS3へconditional GETを送る。304なら最新であり、そのままcloneやfetchへ応答する。200なら新しいインデックスを取得し、不足したWALを反映してから応答する。

Cursorによれば、メタデータを確認する304応答は平均10ミリ秒未満だった。gossipは速く追いつくための合図であり、S3への確認が古い状態を返さないための検証になる。信頼できない通知経路を性能改善に使い、整合性は別経路で守る分担である。

compactionはなぜ1台に集約できるのか

プッシュのたびに新しいパックファイルが増えると、Gitは目的のオブジェクトを探すために多数のインデックスを調べる。multi-pack indexや段階的な再圧縮は探索コストを抑えるが、パックをまとめ直すcompaction自体は避けられない。Spokes型で各レプリカのローカルGitが正本を担うなら、レプリカごとにcompactionを実行するか、圧縮結果を厳密に同期する必要がある。

Continuityではprimaryだけがcompactionを実行し、その結果もWALへ記録する。ほかのレプリカは圧縮済みのパックをS3からダウンロードする。同じCPU負荷を全レプリカで繰り返す代わりに、1回の計算結果をネットワーク帯域で配る。レプリカ数を増やしてもcompaction回数を同じ比率で増やさずに済むため、読み取り能力をプッシュ性能から切り離しやすい。

Git由来の作業は残る。Cursorの試験でも、S3 Express One Zoneでプッシュ性能が毎秒300件を超えた後は、ローカルGitのcompactionがボトルネックになったとしている。WALへ正本を移しても、パックを作り直すCPU時間はゼロにならない。重い処理を1回に集約し、その結果を再利用できることが利点である。

一方、WALインデックスの大きさや分割方法は公表されていない。書き込みが集中するリポジトリでCASの再試行がどの程度増えるか、S3障害時にどの操作まで続けられるかも分からない。compactionを集約して減らした負荷が、WALインデックスの更新競合へ移っていないかは実運用で確かめる必要がある。

AD

100レプリカと毎秒120・300件の読み方

Cursorの合成ベンチマークでは、読み取りは100レプリカまで直線的に伸び、プッシュ性能は低下しなかったとしている。S3 Standardではcompactionと複製を行いながら毎秒最大120件のプッシュを維持した。S3 Express One Zoneでは毎秒300件を超え、その後はローカルGitのcompactionが上限になったという。

ただし、二つの数値を同じ耐障害条件の比較として並べることはできない。AWSはS3 Standardを複数のAvailability Zone(AZ)へ保存するクラスとする一方、S3 Express One Zoneは単一AZである。毎秒120件と300件超では、ストレージの障害ドメインが異なる。Express One Zoneの試験でAZ間やリージョン間に別の耐久層を設けたかも明らかでない。

公開資料には、リポジトリサイズやオブジェクト数、プッシュの大きさがない。同時実行数とサーバー構成、試行回数、遅延分布も示されていない。100レプリカ、毎秒120・300件、10ミリ秒未満はいずれもCursor自身の測定であり、第三者による再現結果やContinuityの公開コードは確認できない。

Originは早期ベータで、公開SLAや運用時の障害履歴、独立した耐久性監査もまだ判断材料にできない。書き込みが集中した際のCAS失敗率と復旧時間を測り、S3停止時の手順とAZをまたぐ耐久性を確認できれば、Gitコピーをどこまで減らせるかという設計上の約束を実績で評価できる。