Skip to content

Commit 61e5493

Browse files
committed
semcode: Guard against compaction hang with many fragments
LanceDB compaction encounters a pathological case when a table accumulates thousands of small fragments. The compact operation enters a CPU loop where the main thread spins at 100% CPU utilization while worker threads remain idle. Any table subjected to many small appends without intervening compaction can reach this state. A check now examines fragment count before compaction proceeds. When fragment count exceeds 500, compaction is skipped and a warning directs the user to rebuild the database with --clear. This threshold prevents the hang condition while allowing normal compaction for tables with moderate fragmentation. Prune, index, and checkout operations remain unaffected; only the compact step is gated by this fragment limit. Fixes: 4a16e15 ("semcode-index: optimize database periodically during long-running indexing") Signed-off-by: Chuck Lever <cel@kernel.org>
1 parent 16c30d4 commit 61e5493

1 file changed

Lines changed: 43 additions & 9 deletions

File tree

src/database/schema.rs

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1016,15 +1016,49 @@ impl SchemaManager {
10161016
let mut success = true;
10171017

10181018
// 1. Compact files
1019-
if let Err(e) = table
1020-
.optimize(OptimizeAction::Compact {
1021-
options: Default::default(),
1022-
remap_options: None,
1023-
})
1024-
.await
1025-
{
1026-
tracing::warn!("Failed to compact table {}: {}", table_name, e);
1027-
success = false;
1019+
const MAX_COMPACT_FRAGMENTS: usize = 500;
1020+
1021+
let should_compact = match table.stats().await {
1022+
Ok(stats)
1023+
if stats.fragment_stats.num_fragments
1024+
> MAX_COMPACT_FRAGMENTS =>
1025+
{
1026+
tracing::warn!(
1027+
"Skipping compaction for table {} \
1028+
({} fragments exceeds {} limit -- \
1029+
rebuild with --clear to resolve)",
1030+
table_name,
1031+
stats.fragment_stats.num_fragments,
1032+
MAX_COMPACT_FRAGMENTS
1033+
);
1034+
false
1035+
}
1036+
Ok(_) => true,
1037+
Err(e) => {
1038+
tracing::warn!(
1039+
"Failed to read stats for table {}: {}",
1040+
table_name,
1041+
e
1042+
);
1043+
true
1044+
}
1045+
};
1046+
1047+
if should_compact {
1048+
if let Err(e) = table
1049+
.optimize(OptimizeAction::Compact {
1050+
options: Default::default(),
1051+
remap_options: None,
1052+
})
1053+
.await
1054+
{
1055+
tracing::warn!(
1056+
"Failed to compact table {}: {}",
1057+
table_name,
1058+
e
1059+
);
1060+
success = false;
1061+
}
10281062
}
10291063

10301064
// 2. Prune ALL old versions

0 commit comments

Comments
 (0)