Release v0.2.1: performance & memory hardening#3
Merged
Conversation
There was a problem hiding this comment.
Pull request overview
This PR prepares the Root v0.2.1 release, focusing on performance/memory hardening across search, lockfile writing, status behavior, and event history—plus accompanying release documentation and version bumps.
Changes:
- Optimizes search/catalog result structures to reduce allocations (static slices) and refactors
build_v2_lockto take&RootLockV2. - Adds
root history --limit Nplumbing and introducesread_events_with_limit, plus resilience for malformed event lines. - Implements content-aware lockfile writes (skip write if content unchanged) and updates release docs + version metadata to 0.2.1.
Reviewed changes
Copilot reviewed 8 out of 9 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| Docs/Performance/V0_2_1_PERFORMANCE_NOTES.md | Adds performance hardening notes and measured improvements for v0.2.1. |
| Docs/Performance/V0_2_1_BASELINE.md | Adds baseline performance audit used to justify optimizations. |
| crates/root-lockfile/src/lib.rs | Adds content-aware lockfile writes and introduces Default for RootLockV2. |
| crates/root-core/src/lib.rs | Refactors search/catalog data structures, adds bounded history entrypoint, hardens status behavior, and adds extensive tests. |
| crates/root-core/src/events.rs | Adds read_events_with_limit used by history limiting. |
| crates/root-cli/src/main.rs | Exposes root history --limit N in the CLI. |
| CHANGELOG.md | Adds v0.2.1 release notes. |
| Cargo.toml | Bumps workspace version to 0.2.1. |
| Cargo.lock | Updates workspace crate versions to 0.2.1. |
Comments suppressed due to low confidence (1)
crates/root-lockfile/src/lib.rs:105
RootLockV2now derivesDefault, but the derived implementation will setversionto0(notROOT_LOCK_SCHEMA_VERSION) andplatformto an empty string. That makesRootLockV2::default()produce an invalid/meaningless lock unless callers remember to patch those fields, and it also diverges from the serde default (default_root_lock_schema_version) used on deserialization.
/// RootLock v2 JSON format with deterministic Nix resolution metadata.
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, Default)]
pub struct RootLockV2 {
#[serde(default = "default_root_lock_schema_version")]
pub version: u32,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub root_version: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub created_at: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub updated_at: Option<String>,
pub platform: String,
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
108
to
131
| @@ -121,6 +125,9 @@ pub fn read_events() -> Result<Vec<RootEvent>> { | |||
| } | |||
| } | |||
| events.reverse(); | |||
| if let Some(limit) = limit { | |||
| events.truncate(limit); | |||
| } | |||
| Ok(events) | |||
Comment on lines
+1158
to
+1166
| fn search_match_for_package(query: &str, spec: &'static PackageSpec) -> Option<SearchMatch> { | ||
| let query = query.trim().to_lowercase(); | ||
| let query = query.trim(); | ||
| if query.is_empty() { | ||
| return None; | ||
| } | ||
|
|
||
| let query_lower = query.to_lowercase(); | ||
| let query_ref: &str = &query_lower; | ||
|
|
Comment on lines
+4744
to
+4747
| assert!( | ||
| hist.events[0].command == "second" || hist.events[0].command == "first", | ||
| "Events should be in reverse chronological order" | ||
| ); |
Comment on lines
+12
to
+16
| - **Search**: Query is lowercased once instead of per-package (42×). `SearchMatch` and `CatalogEntry` use `&'static [&'static str]` for aliases and binaries, eliminating per-result heap allocations. (Phase 2) | ||
| - **Lockfile**: Content-aware write — `save_lock_v2` and `save_lock` compare serialized output to existing file and skip the write if unchanged. Zero disk I/O when no changes occurred. (Phase 3) | ||
| - **build_v2_lock**: Refactored to accept `&RootLockV2` directly, eliminating wasteful v2→v1→v2 conversion cycle in `install`, `update`, and `lock`. (Phase 3) | ||
| - **Event ledger**: `root history --limit N` added to cap in-memory event loading. `read_events_with_limit(limit)` avoids parsing the entire ledger when a limit is specified. (Phase 4) | ||
| - **Status**: Nix profile check is skipped when Rootfile and lockfile both have zero packages. Status is entirely local-only for empty states. (Phase 5) |
Comment on lines
+28
to
+32
| ### Event Ledger Scalability (Phase 4) | ||
| - **Before**: `read_events()` loaded every event line into memory. | ||
| - **After**: `read_events_with_limit(limit)` added. `history_with_limit(limit)` exposed via CLI as `root history --limit N`. | ||
| - **Gain**: Bounded memory usage for large ledgers. `root history --limit 50` reads and parses only 50 lines after reversing. | ||
|
|
…ent buffer, stronger ordering test
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.
v0.2.1 — Performance & Memory Hardening
No new features. No breaking changes.
This pull request delivers Root v0.2.1, focusing on significant performance, memory, and reliability improvements across the CLI, lockfile handling, search, and event history. The update introduces content-aware lockfile writes, reduces memory allocations in search and catalog operations, adds bounded event history loading, and hardens the status command for empty or missing states. Comprehensive new tests cover these enhancements and edge cases.
Performance and Memory Optimizations
SearchMatch/CatalogEntryuse&'static [&'static str]for aliases and binaries, eliminating per-result heap allocations. [1] [2] [3]save_lock_v2andsave_lock) now compare the new content to the existing file and skip the write if unchanged, resulting in zero disk I/O when no changes occur. [1] [2] [3]build_v2_lockrefactored to accept&RootLockV2directly, eliminating unnecessary conversions. [1] [2]Event History Improvements
root history --limit Nto cap in-memory event loading, withread_events_with_limit(limit)avoiding parsing the entire ledger when a limit is specified. [1] [2] [3] [4] [5]events.jsonlare now gracefully skipped.Reliability and Robustness
RootLockV2now derivesDefaultfor more consistent construction. [1] [2]RootLock::write_to_fileandRootLockV2::write_to_filenow handle existing files gracefully and avoid unnecessary writes. [1] [2] [3]Testing and Documentation
Docs/Performance/V0_2_1_BASELINE.mdandDocs/Performance/V0_2_1_PERFORMANCE_NOTES.md. [1] [2]Miscellaneous
legacy_lock_from_v2,legacy_package_from_v2. [1] [2]