Repository navigation
fix: wal replay recovery - #314
chrollo-lucifer-12 wants to merge 10 commits into
Conversation
|
@chrollo-lucifer-12 any updates? |
|
@chrollo-lucifer-12 please update it and fix conflicts |
Sorry for the delay I'll do it today, i was preoccupied with something |
|
@mattsva @VihaanReddyM i have resolved the conflicts |
There was a problem hiding this comment.
Ive used AI (Claude Sonnet 5.5) to help me debug the CI errors. This is about what we got with your changes I guess.
Note this is just a help, first please make all the CI jobs run smoothly, maybe those AI review helps you, if not, its ok, dont take it too serious.
Please fix @chrollo-lucifer-12, afterwards Iam glade to first review the code another time, and then merge it, if it is fine.
thanks for the review i will do the changes |
|
@mattsva i have done the requested changes, all tests now pass including the tests and ty typecheck. But in ruff checks i get "Use a context manager for opening files". |
There was a problem hiding this comment.
Over all it is good from code quality. It is not mergeable yet, but it is pretty good.
Please fix the changes, that are overall mainly formatting things, i am not sure if you need to add something to the pyproject.toml to make the SIM115 be quite, but that would be okay too.
Also add the better benchmark, so we can really see how big of a change this is.
At all, really good work @chrollo-lucifer-12 .
Any more questions?
| def __init__(self, filename: str): | ||
| self.filename = filename | ||
| self._offset = os.path.getsize(filename) if os.path.isfile(filename) else 0 | ||
| self._file = open(filename, "a+b") |
There was a problem hiding this comment.
ruff SIM115 fails here. The handle is kept open on purpose and closed in close(), so please silence it with a reason:
self._file = open(filename, "a+b") # noqa: SIM115 - kept open, closed in close() or something like this.
| def _ensure_open(self): | ||
| """Return the open WAL file, reopening it if necessary.""" | ||
| if self._file is None: | ||
| self._file = open(self.filename, "a+b") |
There was a problem hiding this comment.
Same as above: add # noqa: SIM115 - reopened lazily, closed in close().
| def close(self) -> None: | ||
| """Close the WAL file if it is open.""" | ||
| f, self._file = self._file, None | ||
| if f is not None: |
There was a problem hiding this comment.
I guess indentation is off (9 spaces), so ruff format --check fails. Running uv run ruff format . fixes it.
(I guess it is somewhere around here, but uv run ruff format . should definitely catch it)
| if line: | ||
| try: | ||
| entries.append(WalEntry.from_dict(json.loads(line.decode()))) | ||
| except (json.JSONDecodeError, UnicodeDecodeError, TypeError, ValueError) as e: |
There was a problem hiding this comment.
This line is too long for ruff format. uv run ruff format . will wrap it.
| self._offset = good_offset | ||
| return entries | ||
|
|
||
| def clear(self) -> None: |
There was a problem hiding this comment.
If self.close() raises, the temp file created above is left behind, because close() runs outside the try block. Please move it inside the try so the temp file is always cleaned up.
It may be good to have a test for those things.
| actual_size = os.path.getsize(self.filename) | ||
| if actual_size > self._offset: | ||
| with open(self.filename, "r+b") as f: | ||
| f.truncate(self._offset) |
There was a problem hiding this comment.
Missing newline at end of file. ruff format adds it. (On all files)
| except OSError: | ||
| pass | ||
| raise | ||
| old_wal = self.wal |
There was a problem hiding this comment.
Closing the old WAL after the swap is fine, and safer than closing it first, since a failed load keeps the old state. Please add a test that the old WAL's handle is closed after a second load().
This is optinal, but I guess/hope it helps
| @@ -0,0 +1,46 @@ | |||
| """Benchmarks for write-ahead log persistence.""" | |||
There was a problem hiding this comment.
This measures only the first append on a fresh file, so it mostly shows fsync cost. Since the change is about reusing the handle, please add a second benchmark that appends many entries to one open WAL, and post before/after numbers (command, OS, Python version, workload).
Make it more telling, please.
thanks, i dont ususally write python more into golang. |
|
Benchmarked WAL handle reuse on Linux (WSL2), Python 3.12.3, using Command: Workload: one append to a fresh WAL, and 1,000 appends using a single open WAL. Benchmark | Before | After -- | -- | -- Single append | 1.845 ms | 1.680 ms 1,000 appends | 1,444.807 ms | 1,353.096 ms Average per append (batch) | 1.445 ms | 1.353 msThe repeated-append benchmark improved by approximately 6.4%. these are the benchmarks |
|
the bottleneck is still fsync, maybe we can try fsync in batches ? @mattsva |
Description
This pr addresses the problems discussed in issue #306
Type of Change
Key Changes
Validation
Added a benchmark test for wal appends.
Running the test shows the following result after doing the said updates:
------------------------------------------------ benchmark 'wal': 1 tests ------------------------------------------------
Name (time in us) Min Max Mean StdDev Median IQR Outliers OPS (Kops/s) Rounds Iterations
test_wal_append 753.3000 946.1000 809.6280 40.9104 797.3000 57.8000 9;2 1.2351 50 1
Checklist
uv run ruff check .anduv run ruff format --check ., or this PR does not change Python.