Skip to content

Release v0.2.1: performance & memory hardening#3

Merged
sgr0691 merged 2 commits into
mainfrom
v0.2.1-performance
Jun 23, 2026
Merged

Release v0.2.1: performance & memory hardening#3
sgr0691 merged 2 commits into
mainfrom
v0.2.1-performance

Conversation

@sgr0691

@sgr0691 sgr0691 commented Jun 23, 2026

Copy link
Copy Markdown
Owner

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

  • Search query is now lowercased once per invocation (not per package), and SearchMatch/CatalogEntry use &'static [&'static str] for aliases and binaries, eliminating per-result heap allocations. [1] [2] [3]
  • Lockfile write operations (save_lock_v2 and save_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_lock refactored to accept &RootLockV2 directly, eliminating unnecessary conversions. [1] [2]

Event History Improvements

  • Added root history --limit N to cap in-memory event loading, with read_events_with_limit(limit) avoiding parsing the entire ledger when a limit is specified. [1] [2] [3] [4] [5]
  • Malformed event lines in events.jsonl are now gracefully skipped.

Reliability and Robustness

  • Status command now skips the Nix profile check when both Rootfile and lockfile have zero packages, making status local-only for empty states. Handles missing Rootfile, lockfile, unavailable Nix, and missing profile without panicking.
  • RootLockV2 now derives Default for more consistent construction. [1] [2]
  • RootLock::write_to_file and RootLockV2::write_to_file now handle existing files gracefully and avoid unnecessary writes. [1] [2] [3]

Testing and Documentation

  • 24 new tests added, covering all new behaviors and edge cases.
  • Added detailed performance audit and optimization notes in Docs/Performance/V0_2_1_BASELINE.md and Docs/Performance/V0_2_1_PERFORMANCE_NOTES.md. [1] [2]

Miscellaneous

  • Removed dead code: legacy_lock_from_v2, legacy_package_from_v2. [1] [2]
  • Version bumped to 0.2.1 in workspace metadata.

Copilot AI 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.

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_lock to take &RootLockV2.
  • Adds root history --limit N plumbing and introduces read_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

  • RootLockV2 now derives Default, but the derived implementation will set version to 0 (not ROOT_LOCK_SCHEMA_VERSION) and platform to an empty string. That makes RootLockV2::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 thread crates/root-core/src/events.rs Outdated
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 thread crates/root-core/src/lib.rs Outdated
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 thread crates/root-core/src/lib.rs Outdated
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 thread CHANGELOG.md
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.

@sgr0691 sgr0691 merged commit 0ceee3a into main Jun 23, 2026
1 check passed
@sgr0691 sgr0691 deleted the v0.2.1-performance branch June 23, 2026 04:18
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