web-dev-qa-db-ja.com

失敗した書き込みからどのように回復しますか?

私はパッチ可能なゲームのロジックを書いており、パッチには複数のファイルの変更が含まれます。

type UpdateInfo {
    file string
    data []byte
    at   int64
}

func AtomicUpdate(ui <-chan UpdateInfo) error {
    for _, v := range ui {
        file, err := os.OpenFile(v.file, os.O_RDWR|os.O_CREATE, 0)
        if err != nil {
            return err
        }
        _, err = file.WriteAt(v.data, v.at)
        if err != nil {
            return err
        }
    }
}

uiは、一貫した状態を維持するために実行する必要がある変更の単一のアトミックセットを表します。一貫性のない状態の問題は、ユーザーがすべてを再ダウンロードしなければならない可能性があることです。これはかなり悪いですが、大惨事ではありません。

問題は、状態が一貫しないままになっている可能性がある、失敗したAtomicUpdateから回復するための合理的な設計とは何ですか?

また、AtomicUpdateの実行中に何らかの割り込み(ユーザーが電源を切ったなど)が発生する可能性があり、通常のエラー処理もできません。これは懸念事項であり、どうすればそれから回復できますか?

2
Passer By

関連ファイルのグループを更新する最も安全な方法は、このようなアルゴリズムを使用することです

  1. 関連する各ファイル(またはファイルのツリー全体)のコピーを作成します
  2. ファイルのコピーにパッチを適用します
  3. すべてのパッチが適用されたら、元のファイルを(変更された)コピーで置き換えます。ファイルシステムアクションを使用して、このためのファイル/フォルダーの名前を変更します。
  4. パッチの適用中にエラーが発生した場合は、コピーを削除してください。

このように、停電があったとしても、最後のステップでのみ、パッチが部分的に適用されるリスクがあります。この最後のステップは可能な限り高速であり、ツリーレベルでコピーを作成すると、実際にはアトミックになる可能性があります。

これは25年以上前に、地上で軍事戦闘フィールド機器にパッチを適用したことでしょうか-失敗は許されませんでした。私たちが設計したシステムはさまざまな理由でより精巧でしたが、基本的にはいくつかのステップのアイデアを中心に設計されました。

1)「開始中」の「進行中」のファイルを作成します。 2)ファイルをバックアップします。 3)「進行中」のファイル「バックアップ完了」を更新します。 4)パッチファイル5)「進行中」のファイルを削除します。

起動時に「進行中」ファイルが存在する場合は、それを調べて、プロセスのどこで再び失敗したか(または復元して失敗したか)を確認します。エラー検出、ロールフォワード、ロールバックなど、あらゆる種類のオプションが存在します。システムはおそらくハッシュを必要とし、セキュリティ、署名に必要です。

残念ながら、これはプログラミングの問題の1つであり、正しく理解することはそれほど難しくありませんが、間違えることは非常に簡単です。

1
mattnz