Register a secondary index on a field for a collection. If `backfill` is true, scans all existing entries and populates the index. Returns the number of entries backfilled (0 if index already existed). Note**: backfill scans all entries synchronously. For large collections (> 10k entries), consider `backfill=false` and rebuilding offline.
(
&mut self,
tenant_id: u64,
collection: &str,
field: &str,
field_position: usize,
backfill: bool,
now_ms: u64,
)
| 16 | /// **Note**: backfill scans all entries synchronously. For large collections |
| 17 | /// (> 10k entries), consider `backfill=false` and rebuilding offline. |
| 18 | pub fn register_index( |
| 19 | &mut self, |
| 20 | tenant_id: u64, |
| 21 | collection: &str, |
| 22 | field: &str, |
| 23 | field_position: usize, |
| 24 | backfill: bool, |
| 25 | now_ms: u64, |
| 26 | ) -> usize { |
| 27 | let tkey = table_key(tenant_id, collection); |
| 28 | let idx_set = self.indexes.entry(tkey).or_default(); |
| 29 | |
| 30 | if !idx_set.add_index(field, field_position) { |
| 31 | return 0; // Already indexed. |
| 32 | } |
| 33 | |
| 34 | if !backfill { |
| 35 | return 0; |
| 36 | } |
| 37 | |
| 38 | // Backfill: collect entries first, then update indexes. |
| 39 | // Two-phase approach avoids borrow conflicts on self.indexes vs self.tables. |
| 40 | let entries_to_backfill: Vec<(Vec<u8>, Vec<u8>)> = match self.tables.get(&tkey) { |
| 41 | Some(table) => { |
| 42 | let mut all = Vec::new(); |
| 43 | let mut cursor = 0; |
| 44 | loop { |
| 45 | let (entries, next) = table.scan(cursor, 1000, now_ms, None); |
| 46 | if entries.is_empty() { |
| 47 | break; |
| 48 | } |
| 49 | all.extend(entries.into_iter().map(|(k, v)| (k.to_vec(), v.to_vec()))); |
| 50 | if next == 0 { |
| 51 | break; |
| 52 | } |
| 53 | cursor = next; |
| 54 | } |
| 55 | all |
| 56 | } |
| 57 | None => return 0, |
| 58 | }; |
| 59 | |
| 60 | // Now update indexes — idx_set is guaranteed to exist (inserted above). |
| 61 | let idx_set = self |
| 62 | .indexes |
| 63 | .get_mut(&tkey) |
| 64 | .expect("index set was inserted at entry point of register_index"); |
| 65 | let mut backfilled = 0; |
| 66 | for (key, value) in &entries_to_backfill { |
| 67 | let field_values = extract_field_values_from_msgpack(value, field); |
| 68 | for fv in &field_values { |
| 69 | let fv_pairs: Vec<(&str, &[u8])> = vec![(field, fv.as_slice())]; |
| 70 | idx_set.on_put(key, &fv_pairs, None); |
| 71 | backfilled += 1; |
| 72 | } |
| 73 | } |
| 74 | |
| 75 | backfilled |