1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// Sonic
//
// Fast, lightweight and schema-less search backend
// Copyright: 2019, Valerian Saliou <valerian@valeriansaliou.name>
// Copyright: 2026, Rémi Bardon <remi@remibardon.name>
// License: Mozilla Public License v2.0 (MPL v2.0)
use linked_hash_set::LinkedHashSet;
use std::iter::FromIterator;
use crate::lexer::TokenLexer;
use crate::store::StoreItem;
use crate::store::fst::StoreFSTActionBuilder;
use crate::store::identifiers::StoreTermHashed;
use crate::store::kv::{StoreKVAcquireMode, StoreKVActionBuilder};
impl super::Executor {
pub fn pop(&self, item: StoreItem, lexer: TokenLexer) -> Result<u32, ()> {
if let StoreItem(collection, Some(bucket), Some(object)) = item {
// Important: acquire database access read lock, and reference it in context. This \
// prevents the database from being erased while using it in this block.
let _kv_read_guard = self.kv_pool.lock_read_access();
let _fst_read_guard = self.fst_pool.lock_read_access();
if let (Ok(kv_store), Ok(fst_store)) = (
self.kv_pool
.acquire(StoreKVAcquireMode::OpenOnly, collection),
self.fst_pool.acquire(collection, bucket),
) {
// Important: acquire bucket store write lock
executor_kv_lock_write!(kv_store);
let (kv_action, fst_action) = (
StoreKVActionBuilder::access(bucket, kv_store),
StoreFSTActionBuilder::access(fst_store),
);
// Try to resolve existing OID to IID (if it does not exist, there is nothing to \
// be flushed)
let oid = object.as_str();
if let Ok(iid_value) = kv_action.get_oid_to_iid(oid) {
let mut count_popped = 0;
if let Some(iid) = iid_value {
// Try to resolve existing search terms from IID, and perform an algebraic \
// AND on all popped terms to generate a list of terms to be cleaned up.
if let Ok(Some(iid_terms_hashed_vec)) = kv_action.get_iid_to_terms(iid) {
tracing::info!(
"got pop executor stored iid-to-terms: {:?}",
iid_terms_hashed_vec
);
let pop_terms: Vec<(String, StoreTermHashed, usize)> = lexer.collect();
let iid_terms_hashed: LinkedHashSet<StoreTermHashed> =
LinkedHashSet::from_iter(iid_terms_hashed_vec.iter().copied());
let remaining_terms: LinkedHashSet<StoreTermHashed> = iid_terms_hashed
.difference(&LinkedHashSet::from_iter(
pop_terms.iter().map(|item| item.1),
))
.copied()
.collect();
tracing::debug!(
"got pop executor terms remaining terms: {:?} for iid: {}",
remaining_terms,
iid
);
count_popped = (iid_terms_hashed.len() - remaining_terms.len()) as u32;
if count_popped > 0 {
if remaining_terms.is_empty() {
tracing::info!("nuke whole bucket for pop executor");
// Flush bucket (batch operation, as it is shared w/ other \
// executors)
executor_ensure_op!(kv_action.batch_flush_bucket(
iid,
oid,
&iid_terms_hashed_vec
));
} else {
tracing::info!("nuke only certain terms for pop executor");
// Nuke IID in Term-to-IIDs list
for (pop_term, pop_term_hashed, _) in &pop_terms {
// Check that term is linked to IID (and should be removed)
if iid_terms_hashed.contains(pop_term_hashed) {
if let Ok(Some(mut pop_term_iids)) =
kv_action.get_term_to_iids(*pop_term_hashed)
{
// Remove IID from list of IIDs to be popped
pop_term_iids.retain(|cur_iid| cur_iid != &iid);
if pop_term_iids.is_empty() {
// IIDs list was empty, delete whole key
executor_ensure_op!(
kv_action
.delete_term_to_iids(*pop_term_hashed)
);
// Pop from FST graph (does not exist anymore)
if fst_action.pop_word(pop_term) {
tracing::debug!(
"pop term hash nuked from graph: {}",
pop_term_hashed
);
}
} else {
// Re-build IIDs list w/o current IID
executor_ensure_op!(
kv_action.set_term_to_iids(
*pop_term_hashed,
&pop_term_iids,
)
);
}
} else {
tracing::error!(
"failed getting term-to-iids in pop executor"
);
}
}
}
// Bump IID-to-Terms list
let remaining_terms_vec: Vec<StoreTermHashed> =
Vec::from_iter(remaining_terms);
executor_ensure_op!(
kv_action.set_iid_to_terms(iid, &remaining_terms_vec)
);
}
}
} else {
tracing::error!("failed getting iid-to-terms in pop executor");
}
}
return Ok(count_popped);
}
}
}
Err(())
}
}