mirror of
https://github.com/openai/codex.git
synced 2026-10-22 17:58:46 +00:00
Report thread storage changes after rollout migration (#38579)
## What changed Measure thread storage before and after `codex migrate-rollouts --apply` and include the formatted sizes in the human-readable migration report. The total includes active and archived rollout files, the thread history database, and its WAL and shared-memory sidecars. Keep dry-run and JSON output unchanged, and omit the storage summary if either measurement fails. GitOrigin-RevId: 1775c0b6849570a814becd94e196dd05908667a1
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
use std::io;
|
||||
use std::io::IsTerminal;
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
use std::time::Duration;
|
||||
use std::time::Instant;
|
||||
|
||||
@@ -73,6 +74,17 @@ pub(crate) async fn run(
|
||||
};
|
||||
let json = command.json;
|
||||
let verbose = command.verbose;
|
||||
let thread_history_db_path = config.sqlite.thread_history_db_path();
|
||||
let thread_storage_before = if mode == RolloutMigrationMode::Apply && !json {
|
||||
thread_storage_bytes(
|
||||
config.codex_home.as_path(),
|
||||
thread_history_db_path.as_path(),
|
||||
)
|
||||
.await
|
||||
.ok()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let state_db = if mode == RolloutMigrationMode::Apply {
|
||||
Some(
|
||||
codex_rollout::state_db::try_init(&config)
|
||||
@@ -97,11 +109,21 @@ pub(crate) async fn run(
|
||||
.await;
|
||||
progress.finish();
|
||||
let report = result?;
|
||||
let thread_storage = match thread_storage_before {
|
||||
Some(before) => thread_storage_bytes(
|
||||
config.codex_home.as_path(),
|
||||
thread_history_db_path.as_path(),
|
||||
)
|
||||
.await
|
||||
.ok()
|
||||
.map(|after| (before, after)),
|
||||
None => None,
|
||||
};
|
||||
|
||||
if json {
|
||||
println!("{}", serde_json::to_string_pretty(&report)?);
|
||||
} else {
|
||||
print_human_report(&report, mode, verbose, progress.elapsed());
|
||||
print_human_report(&report, mode, verbose, progress.elapsed(), thread_storage);
|
||||
}
|
||||
|
||||
if report
|
||||
@@ -272,6 +294,7 @@ fn print_human_report(
|
||||
mode: RolloutMigrationMode,
|
||||
verbose: bool,
|
||||
elapsed: Duration,
|
||||
thread_storage: Option<(u64, u64)>,
|
||||
) {
|
||||
let mut counts = MigrationCounts::default();
|
||||
for outcome in &report.outcomes {
|
||||
@@ -304,6 +327,13 @@ fn print_human_report(
|
||||
counts.failed,
|
||||
),
|
||||
}
|
||||
if let Some((before, after)) = thread_storage {
|
||||
println!(
|
||||
"Disk used for thread storage: {} -> {}",
|
||||
format_bytes(before),
|
||||
format_bytes(after)
|
||||
);
|
||||
}
|
||||
if mode == RolloutMigrationMode::DryRun && counts.eligible > 0 {
|
||||
println!("Run `codex migrate-rollouts --apply` to migrate eligible sessions.");
|
||||
}
|
||||
@@ -367,3 +397,54 @@ fn format_elapsed(elapsed: Duration) -> String {
|
||||
}
|
||||
format!("{hours}h{:02}m{:02}s", minutes % 60, seconds % 60)
|
||||
}
|
||||
|
||||
async fn thread_storage_bytes(codex_home: &Path, thread_history_db_path: &Path) -> io::Result<u64> {
|
||||
let mut bytes = 0_u64;
|
||||
let mut directories = vec![
|
||||
codex_home.join(codex_rollout::SESSIONS_SUBDIR),
|
||||
codex_home.join(codex_rollout::ARCHIVED_SESSIONS_SUBDIR),
|
||||
];
|
||||
while let Some(directory) = directories.pop() {
|
||||
let mut entries = match tokio::fs::read_dir(&directory).await {
|
||||
Ok(entries) => entries,
|
||||
Err(error) if error.kind() == io::ErrorKind::NotFound => continue,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
while let Some(entry) = entries.next_entry().await? {
|
||||
let file_type = entry.file_type().await?;
|
||||
if file_type.is_dir() {
|
||||
directories.push(entry.path());
|
||||
} else if file_type.is_file() {
|
||||
bytes = bytes.saturating_add(entry.metadata().await?.len());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for suffix in ["", "-wal", "-shm"] {
|
||||
let mut path = thread_history_db_path.as_os_str().to_owned();
|
||||
path.push(suffix);
|
||||
match tokio::fs::metadata(path).await {
|
||||
Ok(metadata) => bytes = bytes.saturating_add(metadata.len()),
|
||||
Err(error) if error.kind() == io::ErrorKind::NotFound => {}
|
||||
Err(error) => return Err(error),
|
||||
}
|
||||
}
|
||||
Ok(bytes)
|
||||
}
|
||||
|
||||
fn format_bytes(bytes: u64) -> String {
|
||||
const KIB: f64 = 1024.0;
|
||||
const MIB: f64 = KIB * 1024.0;
|
||||
const GIB: f64 = MIB * 1024.0;
|
||||
|
||||
let bytes = bytes as f64;
|
||||
if bytes >= GIB {
|
||||
format!("{:.1} GB", bytes / GIB)
|
||||
} else if bytes >= MIB {
|
||||
format!("{:.1} MB", bytes / MIB)
|
||||
} else if bytes >= KIB {
|
||||
format!("{:.1} KB", bytes / KIB)
|
||||
} else {
|
||||
format!("{} B", bytes as u64)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user