Skip to content

Optimize blob download and caching with hash verification#14

Merged
greenart7c3 merged 2 commits into
masterfrom
claude/battery-drain-hash-verify-viw8du
Jul 17, 2026
Merged

Optimize blob download and caching with hash verification#14
greenart7c3 merged 2 commits into
masterfrom
claude/battery-drain-hash-verify-viw8du

Conversation

@greenart7c3

Copy link
Copy Markdown
Owner

Summary

This PR improves the performance and reliability of blob downloads and caching by implementing single-pass hash verification during download, increasing buffer sizes, and optimizing the file store's size tracking and pruning logic.

Key Changes

CustomHttpServer.kt:

  • Added Dispatchers.IO context for blocking I/O operations (fetchAndSave and streamFromServer) to prevent blocking Ktor's event-loop threads
  • Implemented single-pass SHA-256 hashing during download instead of re-reading files for verification
  • Increased copy buffer size from 8 KiB to 64 KiB to reduce loop iterations and system calls per megabyte
  • Added hash validation with proper error handling and logging for mismatched downloads
  • Added toHex() utility function for efficient byte array to hex string conversion
  • Updated streamFromServer to only cache blobs if their hash matches the requested hash

AndroidFileStore.kt:

  • Added synchronization lock to prevent race conditions between concurrent downloads and the pruner
  • Optimized size tracking to be maintained incrementally instead of rescanning the directory on every operation
  • Moved Tika instance creation to class initialization (single instance) instead of creating it per MIME type detection
  • Refactored pruneIfNeeded() to only scan the directory when the size limit is actually exceeded
  • Extracted magic numbers into named constants (MAX_CACHE_SIZE_BYTES, PRUNE_TARGET_SIZE_BYTES)
  • Updated moveFile() to properly track size changes when replacing existing files

Notable Implementation Details

  • Hash verification now happens during the download stream, eliminating the need to re-read the file from storage
  • The 64 KiB buffer size reduces CPU overhead and battery consumption during large downloads
  • Thread-safe operations prevent data corruption from concurrent downloads
  • Pruning is now lazy and only occurs when necessary, improving performance for typical usage patterns

https://claude.ai/code/session_01EY7qfJK7UMnQuLyb3jjeQ2

claude added 2 commits July 8, 2026 17:25
The GET proxy path hashed every downloaded chunk but never read the
digest, so all that SHA-256 work was wasted CPU, and the HEAD proxy
path cached blobs without checking them at all. Both now verify the
hash in the same pass as the download (no second read from flash) and
refuse to cache mismatching content, which also avoids serving a bad
blob forever and re-downloading it.

Copies also move from 8 KiB to 64 KiB buffers, cutting loop
iterations, stream syscalls and digest calls per blob by ~8x, and the
blocking OkHttp calls now run on Dispatchers.IO instead of parking a
Ktor CIO event-loop thread for the whole download.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EY7qfJK7UMnQuLyb3jjeQ2
Every downloaded blob triggered two full directory scans (a stat per
cached file each) via pruneIfNeeded + updateSize. The cache size is
now tracked incrementally under a lock, scanned once at startup, and
the directory is only listed when the tracked size actually crosses
the 1 GB prune limit (which also re-syncs the counter).

Also reuse a single Tika instance instead of loading the MIME-type
registry on every detectMimeType call.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EY7qfJK7UMnQuLyb3jjeQ2
@greenart7c3
greenart7c3 merged commit 8249673 into master Jul 17, 2026
1 check passed
@greenart7c3
greenart7c3 deleted the claude/battery-drain-hash-verify-viw8du branch July 17, 2026 08:16
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.

2 participants