Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
yuezato opened this issue Apr 9, 2019 · 3 comments
Assignees

Comments

@yuezato
Copy link
Member

yuezato commented Apr 9, 2019

問題

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を行う。

より良い対応に向けて

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

  • ロールバック的な挙動(すなわち、削除した後で読み込めても、確実に書き込んだ値が返ってくる)は許す
  • アロケータにメモリ位置を解放した通知を行うタイミングを遅らせる(遅らせた分だけ空き容量が今より常に減ったように見えるかもしれない)
@yuezato yuezato changed the title CannyLSの異常終了時の再起動後に意図しないデータを読み込んでしまう 異常終了時の再起動後に意図しないデータを読み込んでしまう Apr 9, 2019
@sile
Copy link
Member

sile commented Apr 9, 2019

これは問題ですね...。
対応としては「アロケータにメモリ位置を解放した通知を行うタイミングを遅らせる」が良さそうに感じました。
(解放依頼はすぐにアロケータに発行せずにジャーナル領域のキューに積んでおいて、unreleased_headの更新タイミングで、永続化されたことが分かっている分に関しては、キューから出して、アロケータに実際の解放依頼を投げる)

@yuezato
Copy link
Member Author

yuezato commented Apr 9, 2019

quickな返信ありがとうございます。
タイミングを遅らせる方針で手元でコード変更しているので、近い内にPRに出来るかと思います。
(ロールバック的な挙動を許す方は書きはしたものの、実装案は特にないです……)

@sile
Copy link
Member

sile commented Apr 9, 2019

👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants