-
Notifications
You must be signed in to change notification settings - Fork 110
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Use a transactional write in storage
1 parent
21af329
commit 9c23db2
Showing
5 changed files
with
86 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
from __future__ import annotations | ||
|
||
import os | ||
|
||
|
||
def write_transaction(filename: str | os.PathLike[str], data: bytes) -> None: | ||
"""Writes the data to the filename as a transaction. | ||
Guarantees to not leave half-written or empty files on disk if the write | ||
fails or the process is killed. | ||
""" | ||
swapfile = str(filename) + ".swp" | ||
with open(swapfile, mode="wb") as f: | ||
f.write(data) | ||
|
||
os.rename(swapfile, filename) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
from pathlib import Path | ||
from unittest.mock import mock_open, patch | ||
|
||
import hypothesis.strategies as st | ||
import pytest | ||
from hypothesis import given | ||
|
||
from ert.storage._write_transaction import write_transaction | ||
|
||
|
||
@pytest.mark.usefixtures("use_tmpdir") | ||
@given(st.binary()) | ||
def test_write_transaction(data): | ||
filepath = Path("./file.txt") | ||
write_transaction(filepath, data) | ||
|
||
assert filepath.read_bytes() == data | ||
|
||
|
||
def test_write_transaction_failure(tmp_path): | ||
with patch("builtins.open", mock_open()) as m: | ||
handle = m() | ||
|
||
def ctrlc(_): | ||
raise RuntimeError() | ||
|
||
handle.write = ctrlc | ||
|
||
path = tmp_path / "file.txt" | ||
with pytest.raises(RuntimeError): | ||
write_transaction(path, b"deadbeaf") | ||
|
||
assert not [ | ||
c | ||
for c in m.mock_calls | ||
if path in c.args | ||
or str(path) in c.args | ||
or c.kwargs.get("file") in [path, str(path)] | ||
], "There should be no calls opening the file when an write encounters a RuntimeError" | ||
|
||
|
||
def test_write_transaction_overwrites(tmp_path): | ||
path = tmp_path / "file.txt" | ||
path.write_text("abc") | ||
write_transaction(path, b"deadbeaf") | ||
assert path.read_bytes() == b"deadbeaf" |