Skip to content

異常終了時の再起動後に意図しないデータを読み込んでしまう #28

@yuezato

Description

@yuezato

問題

CannyLS v0.9.3以前では、プロセスの異常終了後に再起動すると本来読み込めるべきでないデータが読み込めてしまう。

状況の詳述

以下のような計算の流れを考える:
(完全なコードについてはこのissueのためのリポジトリをご覧ください)

  1. 2つの異なるlumpid, lump_id1lump_id2を準備する。
  2. まずlump_id1にデータ"hoge"をputする。
    • ここでジャーナル領域のディスクへの同期が行われる。
  3. 次にlump_id1を削除する。
  4. 次にlump_id2にデータ"foo"をputする。
    • この時、既にメモリアロケータは"hoge"のあった領域を再利用可能として認識してしまっているため、ここに"foo"を書き込んでしまう。
  5. プロセスがcrashして再起動する。
  6. lump_id1からデータが読み込める。これだけであればロールバック的な挙動として容認できるが、読み出したデータが"foo"になってしまっている。
let lump_id1 = LumpId::new(1_111);
let lump_data1 = storage.allocate_lump_data_with_bytes(b"hoge").unwrap();
storage.put(&lump_id1, &lump_data1); // lump_id1に"hoge"を書き込む。
storage.journal_sync(); // ジャーナルのディスクへの同期を行う。

storage.delete(&lump_id1); // lump_id1を削除する。
let lump_id2 = LumpId::new(22_222_222);
let lump_data2 = storage.allocate_lump_data_with_bytes(b"foo").unwrap();
storage.put(&lump_id2, &lump_data2); // lump_id2に"foo"を書き込む。

// ここでプロセスがcrashする。

let nvm = track!(FileNvm::open(path))?;
let mut storage = track!(Storage::open(nvm))?;
println!("{:?}", storage.get(&lump_i1).unwrap()); // ===> "foo"

回避策

deleteを行う際には毎回syncを行う。

より良い対応に向けて

上の回避策では大幅にパフォーマンスが低下するため、以下の何れかの条件のもとでより良いパフォーマンスを満たす対応策を打ち出したい:

  • ロールバック的な挙動(すなわち、削除した後で読み込めても、確実に書き込んだ値が返ってくる)は許す
  • アロケータにメモリ位置を解放した通知を行うタイミングを遅らせる(遅らせた分だけ空き容量が今より常に減ったように見えるかもしれない)

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions