Atomically register a new merged segment and remove the source segments that were merged into it. Performing the write and all removals in one redb write transaction ensures the operation is crash-safe: a crash mid-compaction leaves the old segments intact (a subsequent maintenance cycle will retry), and there is never a window where both the old and the new segments coexist on a reader that open
(
backend: &RedbFtsBackend,
tid: u64,
collection: &str,
new_segment_id: &str,
new_segment_data: &[u8],
merged_ids: &[String],
)
| 119 | /// there is never a window where both the old and the new segments coexist |
| 120 | /// on a reader that opens a concurrent read transaction. |
| 121 | pub(super) fn compact_commit( |
| 122 | backend: &RedbFtsBackend, |
| 123 | tid: u64, |
| 124 | collection: &str, |
| 125 | new_segment_id: &str, |
| 126 | new_segment_data: &[u8], |
| 127 | merged_ids: &[String], |
| 128 | ) -> crate::Result<()> { |
| 129 | let write_txn = backend |
| 130 | .db |
| 131 | .begin_write() |
| 132 | .map_err(|e| redb_err("compact txn", e))?; |
| 133 | { |
| 134 | let mut table = write_txn |
| 135 | .open_table(SEGMENTS) |
| 136 | .map_err(|e| redb_err("open segments for compact", e))?; |
| 137 | table |
| 138 | .insert((tid, collection, new_segment_id), new_segment_data) |
| 139 | .map_err(|e| redb_err("insert merged segment", e))?; |
| 140 | for id in merged_ids { |
| 141 | // Propagate remove errors so a failed source-segment removal aborts |
| 142 | // the entire transaction; otherwise we would commit a state in |
| 143 | // which both old and new segments are visible to readers, causing |
| 144 | // double-counted postings during BM25 scoring. |
| 145 | table |
| 146 | .remove((tid, collection, id.as_str())) |
| 147 | .map_err(|e| redb_err("remove merged source segment", e))?; |
| 148 | } |
| 149 | } |
| 150 | write_txn |
| 151 | .commit() |
| 152 | .map_err(|e| redb_err("compact txn commit", e))?; |
| 153 | Ok(()) |
| 154 | } |
| 155 | |
| 156 | /// Enumerate all `(tid, collection)` pairs that have at least one segment |
| 157 | /// stored in the SEGMENTS table. |
no test coverage detected