feat (storage): spill large clipboard entries to disk-backed pointers - #76
Open
madsysharma wants to merge 1 commit into
Open
feat (storage): spill large clipboard entries to disk-backed pointers#76madsysharma wants to merge 1 commit into
madsysharma wants to merge 1 commit into
Conversation
Contributor
Author
|
Hi @shaaravraghu , please review this PR. Thank you. |
Contributor
Author
|
Hi @shaaravraghu , please review this PR. Thank you. |
2 similar comments
Contributor
Author
|
Hi @shaaravraghu , please review this PR. Thank you. |
Contributor
Author
|
Hi @shaaravraghu , please review this PR. Thank you. |
This file contains hidden or 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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
feat(storage): spill large clipboard entries to disk-backed pointers
Closes #28
Summary
Large clipboard payloads (images, binary blobs, rich text) used to be held as fully-resident
Vec<u8>byte arrays in the active ring or static slots. Copying a 50 MB image cost 50 MB of RAM the moment it was captured and kept costing the same whether or not the entry was ever pasted.This PR makes those payloads behave like pointers. When a captured entry's payload is at least a configurable threshold (default 1 MiB), its bytes are written to a blob file under
~/.clipwallet/blobs/<id>.bloband the in-RAM ring/slot holds only a lightweightClipData::Spilleddescriptor (a few dozen bytes). The bytes are read back only at paste time and dropped again the instant the system pasteboard has copied them.This directly addresses the issue's reproduction case: copying a large image and navigating past it without pasting no longer consumes significant RAM.
Design decisions
Resident state never holds large bytes
A new last-position enum variant carries only metadata:
PlainText(kept resident so previews work) andFilePath(already a pointer) are never spilled.Load only at paste, release immediately after
spill::hydratereconstructs the original variant from the blob just long enough to place it on the pasteboard, then it drops.Blob lifecycle via reference-counted GC
Rather than threading disk deletes through every mutation (evict, delete, overwrite, encrypt-to-vault), blob lifetime is a single invariant: a blob whose id is not referenced by any live entry is reclaimed. GC runs:
SIGKILLthat bypassed the graceful path).Durability matches the existing store: blobs are written with the same
write -> fsync -> rename -> fsync-parentdiscipline asstorage::disk.Config
New
~/.clipwallet/config.tomlfield (added with a serde default, so existing configs keep working untouched):Non-zero values are clamped to
[4 KiB, 256 MiB];0disables spilling and keeps every entry resident (prior behavior).Behavior notes
Cmd+Vmirrors the cursor only after an explicit ClipWallet paste, since we intentionally don't materialize large payloads onto the system pasteboard just for navigation. This is the trade-off the issue asks for ("loaded into memory only at the moment of a paste").clipwallet statusnow reports on-disk blob count and total size.Backward compatibility
ClipData::Spilledis the last enum variant, so MessagePack (which encodes variants by index) reads every pre-existingstore/file unchanged.spill_threshold_bytesuses#[serde(default)], so configs written before this change deserialize with the 1 MiB default and no rewrite is required.Testing
The new logic - the
Spilledtype semantics, the spill/hydrate round-trip, blob GC, and config parsing/clamping - is covered by unit tests intypes.rs,spill.rs, andconfig.rs(17 tests total). These pass on the project's macOS target viacargo test(tested on macOS Sonoma)Suggested steps:
cargo run -- run~/.clipwallet/blobs/gains a.blobfile and resident memory does not grow by the image size.Checklist
mainusing thefeature/prefixcargo fmt,cargo clippy,cargo testrun on macOS (reviewer/CI gate)