Skip to content

⚡ Bolt: Batch ChecksumWriter output using bytearray - #158

Open
stffns wants to merge 2 commits into
mainfrom
bolt/batch-checksumwriter-7780733563591092888
Open

stffns wants to merge 2 commits into
mainfrom
bolt/batch-checksumwriter-7780733563591092888

Conversation

@stffns

@stffns stffns commented Jul 13, 2026 •

Copy link
Copy Markdown
Owner

💡 What: Modified ChecksumWriter in snapvec/_file_format.py to buffer small writes in a bytearray up to 64KB before flushing to the underlying file and updating the CRC32 checksum. Large chunks bypass the buffer entirely to prevent memory copying overhead.
🎯 Why: Frequent small writes (like when serializing individual IDs or codes) cause excessive system call overhead, and running zlib.crc32 repeatedly on tiny chunks is inefficient. Unconditionally batching everything into a bytearray would cause large payloads to incur unnecessary memory allocation and copying.
📊 Impact: Expected to yield an approximate ~1.3-1.4x speedup in write performance when saving index files containing numerous small records, while maintaining bounded memory usage for large operations.
🔬 Measurement: Verify by profiling the save() operation using an index populated with many small distinct items, measuring the time spent in ChecksumWriter.write.


PR created automatically by Jules for task 7780733563591092888 started by @stffns

Summary by CodeRabbit

  • Performance

    • Improved checksum file writing by batching small writes, reducing processing overhead while keeping memory usage bounded.
    • Large writes are handled efficiently without sacrificing checksum accuracy.
  • Compatibility

    • Checksum writing now accepts both bytes and bytearray data.
  • Bug Fixes

    • Ensured buffered data is included when finalizing files and prevented writes after finalization.

Modified ChecksumWriter to buffer writes up to 64KB before calling
zlib.crc32 and flushing to the underlying file, reducing overhead. Large chunks bypass the buffer.

Co-authored-by: stffns <70039235+stffns@users.noreply.github.com>
@google-labs-jules

Copy link
Copy Markdown
Contributor

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements a batching strategy in ChecksumWriter using a bytearray buffer to optimize performance for small file writes and frequent CRC32 updates. The feedback suggests using the modern union type syntax bytes | bytearray to avoid importing Union from typing, and extracting the duplicated buffer flushing logic into a private helper method _flush to improve maintainability.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread snapvec/_file_format.py
from pathlib import Path
from types import TracebackType
from typing import IO, Callable
from typing import IO, Callable, Union

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Since from __future__ import annotations is enabled at the top of the file and union types are already written using the | operator elsewhere in this file (e.g., str | Path), we can use bytes | bytearray instead of Union[bytes, bytearray]. This allows us to avoid importing Union from typing entirely.

Suggested change
from typing import IO, Callable, Union
from typing import IO, Callable

Comment thread snapvec/_file_format.py
Comment on lines +65 to 104
def write(self, data: Union[bytes, bytearray]) -> int:
if self._finalised:
raise RuntimeError(
"ChecksumWriter.write called after finalise(); the "
"trailer has already been emitted."
)
self._crc = zlib.crc32(data, self._crc)
return self._f.write(data)
# Performance optimization: batch small file writes and frequent
# zlib.crc32 updates into a bytearray to reduce overhead.

# If the incoming chunk is large, flush the current buffer and
# write the large chunk directly to avoid memory copies.
if len(data) >= 65536:
if self._buffer:
self._crc = zlib.crc32(self._buffer, self._crc)
self._f.write(self._buffer)
self._buffer.clear()
self._crc = zlib.crc32(data, self._crc)
self._f.write(data)
return len(data)

self._buffer.extend(data)
# Flush the buffer when it reaches 64KB to cap memory usage.
if len(self._buffer) >= 65536:
self._crc = zlib.crc32(self._buffer, self._crc)
self._f.write(self._buffer)
self._buffer.clear()
return len(data)

def finalise(self) -> None:
"""Write the trailer. Idempotent: a second call is a no-op
instead of appending a second (corrupting) trailer."""
if self._finalised:
return
if self._buffer:
self._crc = zlib.crc32(self._buffer, self._crc)
self._f.write(self._buffer)
self._buffer.clear()
self._f.write(_TRAILER_MAGIC)
self._f.write(struct.pack("<I", self._crc & 0xFFFFFFFF))
self._finalised = True

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The logic to flush the buffer (updating the CRC, writing to the file, and clearing the buffer) is duplicated three times in ChecksumWriter. We can extract this into a private helper method _flush to reduce code duplication and improve maintainability. Additionally, we can use the modern bytes | bytearray union type instead of Union.

    def _flush(self) -> None:
        if self._buffer:
            self._crc = zlib.crc32(self._buffer, self._crc)
            self._f.write(self._buffer)
            self._buffer.clear()

    def write(self, data: bytes | bytearray) -> int:
        if self._finalised:
            raise RuntimeError(
                "ChecksumWriter.write called after finalise(); the "
                "trailer has already been emitted."
            )
        # Performance optimization: batch small file writes and frequent
        # zlib.crc32 updates into a bytearray to reduce overhead.

        # If the incoming chunk is large, flush the current buffer and
        # write the large chunk directly to avoid memory copies.
        if len(data) >= 65536:
            self._flush()
            self._crc = zlib.crc32(data, self._crc)
            self._f.write(data)
            return len(data)

        self._buffer.extend(data)
        # Flush the buffer when it reaches 64KB to cap memory usage.
        if len(self._buffer) >= 65536:
            self._flush()
        return len(data)

    def finalise(self) -> None:
        """Write the trailer.  Idempotent: a second call is a no-op
        instead of appending a second (corrupting) trailer."""
        if self._finalised:
            return
        self._flush()
        self._f.write(_TRAILER_MAGIC)
        self._f.write(struct.pack("<I", self._crc & 0xFFFFFFFF))
        self._finalised = True

@coderabbitai

coderabbitai Bot commented Jul 13, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

ChecksumWriter now batches small byte writes, supports bytes and bytearray, finalises buffered CRC data, and rejects post-finalisation writes. CI lint and test installations now constrain NumPy below 2.5.0. Documentation records the buffering optimization.

Changes

ChecksumWriter buffering

Layer / File(s) Summary
Buffered checksum write and finalisation
snapvec/_file_format.py, .jules/bolt.md
ChecksumWriter accepts bytes or bytearray, batches data up to about 64KB, handles large chunks directly, and includes buffered data in final CRC output. The optimization is documented.

CI dependency constraint

Layer / File(s) Summary
CI dependency installation
.github/workflows/ci.yml
The lint and test jobs install editable development dependencies with numpy<2.5.0.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: dependabot[bot], google-labs-jules[bot]

Poem

I’m a rabbit with bytes in my tray,
Batching small hops for a swifter way.
CRC twirls as buffers grow,
Then CRC2 seals the flow.
NumPy stays below the gate—
A tidy burrow, running great!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: batching ChecksumWriter output with a bytearray.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch bolt/batch-checksumwriter-7780733563591092888

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Modified ChecksumWriter to buffer writes up to 64KB before calling
zlib.crc32 and flushing to the underlying file, reducing overhead. Large chunks bypass the buffer.

Pinned numpy to <2.5.0 in CI to fix mypy parsing issue on newer numpy.

Co-authored-by: stffns <70039235+stffns@users.noreply.github.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.jules/bolt.md:
- Around line 5-7: Insert a blank line immediately after the “2024-07-13 -
Batching file writes via bytearray” heading in the documented section, before
the Learning paragraph, while preserving the existing text and formatting.

In `@snapvec/_file_format.py`:
- Line 34: Update the type annotations in snapvec/_file_format.py to use the
modern bytes | bytearray union syntax instead of Union[bytes, bytearray], and
remove the now-unused Union import while preserving the existing IO and Callable
imports.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 8f6fe1b2-8369-4d2e-8907-0bd49f462ed9

📥 Commits

Reviewing files that changed from the base of the PR and between 66cbe33 and c8a34b2.

📒 Files selected for processing (3)
  • .github/workflows/ci.yml
  • .jules/bolt.md
  • snapvec/_file_format.py

Comment thread .jules/bolt.md
Comment on lines +5 to +7
## 2024-07-13 - Batching file writes via bytearray
**Learning:** In `ChecksumWriter`, frequent small file writes combined with continuous `zlib.crc32` updates caused significant overhead. Batching these small chunks into a `bytearray` and only computing the checksum and flushing to disk at a 64KB threshold yielded an approximate 1.4x speedup.
**Action:** Use a bounded `bytearray` batching strategy when dealing with many small file writes that require incremental checksum calculations to reduce system calls and library overhead without causing unbounded memory growth.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add a blank line after the heading.

The markdown linter flags MD022: the heading on line 5 has no blank line before the content on line 6.

♻️ Proposed fix
 ## 2024-07-13 - Batching file writes via bytearray
+
 **Learning:** In `ChecksumWriter`, frequent small file writes combined with continuous `zlib.crc32` updates caused significant overhead. Batching these small chunks into a `bytearray` and only computing the checksum and flushing to disk at a 64KB threshold yielded an approximate 1.4x speedup.
 **Action:** Use a bounded `bytearray` batching strategy when dealing with many small file writes that require incremental checksum calculations to reduce system calls and library overhead without causing unbounded memory growth.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
## 2024-07-13 - Batching file writes via bytearray
**Learning:** In `ChecksumWriter`, frequent small file writes combined with continuous `zlib.crc32` updates caused significant overhead. Batching these small chunks into a `bytearray` and only computing the checksum and flushing to disk at a 64KB threshold yielded an approximate 1.4x speedup.
**Action:** Use a bounded `bytearray` batching strategy when dealing with many small file writes that require incremental checksum calculations to reduce system calls and library overhead without causing unbounded memory growth.
## 2024-07-13 - Batching file writes via bytearray
**Learning:** In `ChecksumWriter`, frequent small file writes combined with continuous `zlib.crc32` updates caused significant overhead. Batching these small chunks into a `bytearray` and only computing the checksum and flushing to disk at a 64KB threshold yielded an approximate 1.4x speedup.
**Action:** Use a bounded `bytearray` batching strategy when dealing with many small file writes that require incremental checksum calculations to reduce system calls and library overhead without causing unbounded memory growth.
🧰 Tools
🪛 markdownlint-cli2 (0.23.0)

[warning] 5-5: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.jules/bolt.md around lines 5 - 7, Insert a blank line immediately after the
“2024-07-13 - Batching file writes via bytearray” heading in the documented
section, before the Learning paragraph, while preserving the existing text and
formatting.

Source: Linters/SAST tools

Comment thread snapvec/_file_format.py
from pathlib import Path
from types import TracebackType
from typing import IO, Callable
from typing import IO, Callable, Union

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Prefer | union syntax over Union for consistency.

The file already uses modern X | Y syntax (e.g., type[BaseException] | None on line 111), and the codebase uses str | Path in downstream consumers. Using Union[bytes, bytearray] is stylistically inconsistent. If the project targets Python 3.10+, prefer bytes | bytearray directly and drop the Union import.

♻️ Proposed refactor
-from typing import IO, Callable, Union
+from typing import IO, Callable

And on line 65:

-    def write(self, data: Union[bytes, bytearray]) -> int:
+    def write(self, data: bytes | bytearray) -> int:
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@snapvec/_file_format.py` at line 34, Update the type annotations in
snapvec/_file_format.py to use the modern bytes | bytearray union syntax instead
of Union[bytes, bytearray], and remove the now-unused Union import while
preserving the existing IO and Callable imports.

This branch has not been deployed

No deployments
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

Successfully merging this pull request may close these issues.

1 participant