Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions crates/tracedecay-application/src/code_index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,9 +209,7 @@ impl CodeIndexExecutionControlV1 for DaemonCodeIndexControlV1 {
// the last published state here is how a second linked worktree kept
// allocating until the cgroup killer. Reclaimers stay off this thread:
// the indexing pool's stack cannot host them.
let Some(state) = pressure.sample_for_checkpoint() else {
return false;
};
let state = pressure.sample_for_checkpoint();
if matches!(state, ResidentMemoryPressureStateV1::OverBudget { .. }) {
self.tripped.store(true, Ordering::Release);
return true;
Expand Down Expand Up @@ -306,4 +304,17 @@ mod tests {
assert!(!shutting_down.load(Ordering::Acquire));
assert!(!control.is_deadline_exceeded());
}

#[test]
fn checkpoint_sampling_failure_preserves_known_pressure() {
let limit = NonZeroU64::new(100 * 1024 * 1024).expect("limit");
let pressure = Arc::new(ResidentMemoryPressureV1::with_sampler(
limit,
Arc::new(|| None),
));
pressure.publish_observed_resident_bytes(limit.get());
let control = DaemonCodeIndexControlV1::default().with_resident_memory(pressure);
assert!(control.is_cancelled());
assert!(control.refused_by_resident_memory());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2385,27 +2385,6 @@ impl LatestCodeTextGenerationV1 {
})
}

/// The published text artifact of this generation's parent, when one is
/// still on disk. A missing parent is a full build, not a failure.
fn published_parent_text_artifact(&self) -> Result<Option<PathBuf>, RetrievalPortError> {
let Some(parent_id) = self.metadata.manifest().parent_generation.clone() else {
return Ok(None);
};
let Some(descriptor) = self.text_artifact_store.published_descriptor(&parent_id)? else {
return Ok(None);
};
let path = code_text_artifact_path(self.text_artifact_store.store_root(), &descriptor)
.map_err(text_artifact_unavailable)?;
match path.symlink_metadata() {
Ok(metadata) if metadata.file_type().is_file() => Ok(Some(path)),
Ok(_) => Err(RetrievalPortError::Contract(
"parent code text artifact is not a regular file".to_owned(),
)),
Err(error) if error.kind() == std::io::ErrorKind::NotFound => Ok(None),
Err(error) => Err(text_artifact_unavailable(error)),
}
}

fn publish_text_progress_boundary(
&self,
build: &CodeTextArtifactBuildV1,
Expand Down Expand Up @@ -2979,56 +2958,33 @@ impl LatestCodeTextGenerationV1 {
let builder_budget =
text_artifact_builder_budget(build_memory_budget, source.staging_window_bytes())?;
let metadata = self.text_projection_metadata()?;
let content_key = text_artifact_content_key(&source, &metadata)?;
let mut builder = if staging_path.exists() {
open_or_replace_incompatible_text_staging(
store,
match CodeLexicalArtifactBuilderV1::open_or_resume_with_memory_budget_and_control(
&staging_path,
&metadata,
metadata.clone(),
builder_budget,
control,
)
} else if let Some(parent_artifact) = self.published_parent_text_artifact()? {
match CodeLexicalArtifactBuilderV1::stage_carried_parent(
&parent_artifact,
&staging_path,
&metadata,
control,
) {
Ok(true) => open_or_replace_incompatible_text_staging(
store,
&staging_path,
&metadata,
builder_budget,
control,
),
Ok(false) => CodeLexicalArtifactBuilderV1::create_with_memory_budget(
&staging_path,
metadata.clone(),
builder_budget,
)
.map_err(map_text_artifact_error),
Err(error) => Err(map_text_artifact_error(error)),
Ok(builder) => Ok(builder),
Err(CodeLexicalArtifactErrorV1::Incompatible(_)) => {
store.discard_incompatible_staging(&staging_path, control)?;
CodeLexicalArtifactBuilderV1::create_with_memory_budget(
&staging_path,
metadata.clone(),
builder_budget,
)
}
Err(error) => Err(error),
}
} else {
CodeLexicalArtifactBuilderV1::create_with_memory_budget(
&staging_path,
metadata.clone(),
builder_budget,
)
.map_err(map_text_artifact_error)
}?;
// A carried staging file already holds the parent's unchanged rows.
// Restrict the sealed source to the occurrences still missing so the
// content key, the receipt, and reported progress describe that work.
if let Some(rebuild) = builder
.carried_rebuild_occurrences()
.map_err(map_text_artifact_error)?
{
source
.restrict_to_file_occurrences(&rebuild)
.map_err(map_sealed_page_source_error)?;
}
let mut content_key = text_artifact_content_key(&source, &metadata)?;
.map_err(map_text_artifact_error)?;
// A staging file sealed before its publication was interrupted keeps
// no source cursor; it is complete and is published as it stands.
if builder
Expand All @@ -3053,8 +3009,6 @@ impl LatestCodeTextGenerationV1 {
Err(VerifiedSealedLexicalCursorRestoreErrorV1::IncompatiblePosition) => {
drop(builder);
store.discard_incompatible_staging(&staging_path, control)?;
source = store.open_sealed_source(&sealed_identity, control)?;
content_key = text_artifact_content_key(&source, &metadata)?;
builder = CodeLexicalArtifactBuilderV1::create_with_memory_budget(
&staging_path,
metadata,
Expand Down Expand Up @@ -3636,34 +3590,6 @@ pub(super) fn sha256_private_file_and_size(
Ok((hasher.finalize().into(), file_metadata.len()))
}

/// Resume `staging_path`, or replace an incompatible file with a fresh build.
fn open_or_replace_incompatible_text_staging(
store: &DaemonCodeTextArtifactStoreV1,
staging_path: &Path,
metadata: &CodeLexicalProjectionMetadataV1,
builder_budget: usize,
control: &dyn CodeIndexExecutionControlV1,
) -> Result<CodeLexicalArtifactBuilderV1, RetrievalPortError> {
match CodeLexicalArtifactBuilderV1::open_or_resume_with_memory_budget_and_control(
staging_path,
metadata.clone(),
builder_budget,
control,
) {
Ok(builder) => Ok(builder),
Err(CodeLexicalArtifactErrorV1::Incompatible(_)) => {
store.discard_incompatible_staging(staging_path, control)?;
CodeLexicalArtifactBuilderV1::create_with_memory_budget(
staging_path,
metadata.clone(),
builder_budget,
)
.map_err(map_text_artifact_error)
}
Err(error) => Err(map_text_artifact_error(error)),
}
}

/// The content key the text artifact of `source` under `metadata` is
/// published with.
fn text_artifact_content_key(
Expand Down Expand Up @@ -3769,7 +3695,6 @@ fn clear_text_artifact_staging_sidecars(staging_path: &Path) -> std::io::Result<
};
// The compacted rewrite's own rollback journal goes before the rewrite,
// for the same reason the staging journal goes before the staging file.
// A parent carry killed before its rename leaves the same pair.
for suffix in [
"-journal",
"-wal",
Expand Down Expand Up @@ -3849,14 +3774,9 @@ mod staging_sidecar_tests {
assert!(!compacting_journal.exists());

let carrying = root.path().join(".text-artifact-ab.staging-carrying");
let carrying_journal = root
.path()
.join(".text-artifact-ab.staging-carrying-journal");
std::fs::write(&carrying, b"torn parent copy").expect("plant torn carry");
std::fs::write(&carrying_journal, b"carry rollback").expect("plant carry journal");
prepare_absent_text_artifact_staging(&staging).expect("clear torn carry");
std::fs::write(&carrying, b"obsolete parent carry").expect("plant carry");
prepare_absent_text_artifact_staging(&staging).expect("clear obsolete carry");
assert!(!carrying.exists());
assert!(!carrying_journal.exists());

std::fs::write(root.path().join(".text-artifact-ab.staging-wal"), b"wal")
.expect("plant wal");
Expand Down
41 changes: 2 additions & 39 deletions crates/tracedecay-code-index/src/production/lexical_page_source.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
use std::{
collections::{BTreeMap, BTreeSet},
num::NonZeroUsize,
sync::Arc,
};
use std::{collections::BTreeMap, num::NonZeroUsize, sync::Arc};

use sha2::{Digest, Sha256};
use tracedecay_domain::{
CodeGenerationSourceCommitmentsV1, CodeSearchChunkGrainV1, CodeSearchChunkV1,
ExactTechnicalTermV1, FileOccurrenceId,
ExactTechnicalTermV1,
};

use crate::{
Expand Down Expand Up @@ -1307,39 +1303,6 @@ impl VerifiedSealedLexicalPageSourceV1 {
&self.metadata
}

/// Emit pages only for `occurrences`, in their existing sealed order.
///
/// The cursor restarts at the first retained file. Unchanged files stay
/// out of this source because their rows are already durable in the
/// parent text artifact the builder carries forward.
pub fn restrict_to_file_occurrences(
&mut self,
occurrences: &BTreeSet<FileOccurrenceId>,
) -> Result<(), CodeIndexProductionErrorV1> {
self.file_source.retain_occurrences(occurrences);
self.admitted_window.clear();
let file_count = u64::try_from(self.file_source.len()).map_err(|_| {
CodeIndexProductionErrorV1::Contract(
"partitioned sealed generation file count exceeds u64".to_owned(),
)
})?;
self.file_count = file_count;
self.first_file_offset = 0;
self.files_end_offset = file_count;
self.file_ranges = (0..file_count)
.map(|file| (file, file.saturating_add(1)))
.collect();
self.lexical_byte_offsets = self.file_source.lexical_byte_offsets()?;
self.total_lexical_units = self.lexical_byte_offsets.last().copied().ok_or_else(|| {
CodeIndexProductionErrorV1::Contract(
"partitioned lexical byte offsets are empty".to_owned(),
)
})?;
self.maximum_file_bytes = self.file_source.maximum_file_bytes();
self.cursor = VerifiedSealedLexicalCursorV1::initial(self.source_state_digest.clone(), 0)?;
Ok(())
}

pub fn format_revision(&self) -> u32 {
self.format_revision
}
Expand Down
12 changes: 0 additions & 12 deletions crates/tracedecay-code-index/src/production/partitioned_codec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1498,18 +1498,6 @@ impl PartitionedLexicalFileSourceV1 {
self.descriptors.len()
}

/// Keep file segments whose occurrence is in `keep`, preserving order.
///
/// Callers use this to feed a successor text build only the files that
/// are not already durable in the parent artifact.
pub(super) fn retain_occurrences(
&mut self,
keep: &std::collections::BTreeSet<tracedecay_domain::FileOccurrenceId>,
) {
self.descriptors
.retain(|descriptor| keep.contains(&descriptor.file_occurrence_id));
}

/// Every input the content of the pages this source emits depends on
/// apart from the generation's route identity: each file segment in
/// order (its key, occurrence, content address, and symbol identities).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ use tracedecay_runtime_core::path_safety::{SqliteDatabasePathError, sqlite_datab
mod builder;
mod clone_census;
mod clone_codec;
mod delta;
mod fingerprints;
mod format;
mod postings;
Expand Down
Loading
Loading