Skip to content

[Robustness] 競合更新で DAG が分岐すると同期が永久に失敗する #72

Description

@Yu-da-1

背景

#70 は同期時の operation と DAG ノードの対応付けを、timestamp 近傍マッチから 位置(N番目同士) に変えた。一直線の履歴ではバージョン喪失と再送時の cycle detected を止める。

その対応付けが成立するのは履歴が一直線のときだけである。#70 は長さ不一致をエラーにして誤 stamp を拒否するが、分岐したコンテンツの同期 success path は閉じたままになる。#70 の範囲外として切り出す。

問題

get_operations_with_index は genesis 配下の全 operation を返し、linear_history は分岐点で子を1つしか選ばない。件数がずれると get_operations は失敗する。

失敗した同期 round は再試行されるが、同じ拒否が返るだけである。auto-merge 後も側枝の operation は残るため、長さは二度と一致しない。

G → v2 → v3 → A ─┐
              → B ─┴→ Merge → New
  • operations: 7(A と B の両方 + Merge + New)
  • linear_history: 6(分岐点で A か B の一方)

両枝を持ったノードは Fetch / Push できず、クラスタ全体が両枝を飲み込むと、その genesis を配れるノードがなくなる。

いつ起きるか

可用性のために member が2台以上あるとき。

  1. 同じコンテンツを持つ member が2台以上
  2. 2回の書き込みが、違う member のローカル CRDT に載る
  3. 2回目の時点で、その member が1回目の最新をまだ持っていない

genesis を持つノードはローカル commit する。ゲートウェイ / ALB が PUT を振り分けると、短い間隔の連続保存や、content update と token 無効化(同じ DAG 上の policy 更新)の競合で再現しうる。

一度起きると自己回復しない。ユーザーからは「保存は成功したが他ノードに届かない」「そのコンテンツの同期だけ失敗し続ける」に見える。

関連して、#70 の「誤 CID レプリカは通常同期で治る」も get_history 一致までしか見ていない。誤 CID ノードは head として残り、次のローカル update がゴーストとマージすると、上と同じ同期不能になる。

あるべき修正

位置で組まない。operation が作ったノードを identity で探す。

  • commit 時に op.id → node CID または node_timestamp を operation へ書き戻す
  • あるいは parents + payload で DAG 上のノードを引く

拒否は「ノードが読めない」など本当に stamp できない場合に限定する。分岐・マージ後も get_operations が全 operation を正しい stamp 付きで返せることをテストする。heal 後にローカル update しても他レプリカと履歴が一致することもカバーする。

関連

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions