1use std::collections::HashMap;
2use std::net::IpAddr;
3use std::num::NonZeroUsize;
4
5use lru::LruCache;
6use wp_model_core::model::{DataField, FValueStr, Value};
7
8#[derive(Debug, Clone)]
9pub struct FieldQueryCache {
10 str_idx: HashMap<FValueStr, usize>,
11 i64_idx: HashMap<i64, usize>,
12 ip_idx: HashMap<IpAddr, usize>,
13 cache_data: LruCache<LocalCacheKey, Vec<DataField>>,
14 idx_num: usize,
15 generation: Option<u64>,
16}
17
18pub type QueryLocalCache = FieldQueryCache;
19
20impl Default for FieldQueryCache {
21 fn default() -> Self {
22 Self::with_capacity(100)
23 }
24}
25
26impl FieldQueryCache {
27 pub fn with_capacity(size: usize) -> Self {
28 let size = size.max(1);
29 Self {
30 str_idx: HashMap::new(),
31 i64_idx: HashMap::new(),
32 ip_idx: HashMap::new(),
33 cache_data: LruCache::new(NonZeroUsize::new(size).expect("non-zero cache size")),
34 idx_num: 0,
35 generation: None,
36 }
37 }
38
39 fn get_idx(&self, param: &DataField) -> Option<usize> {
40 match param.get_value() {
41 Value::Chars(v) => self.str_idx.get(v).copied(),
42 Value::Digit(v) => self.i64_idx.get(v).copied(),
43 Value::IpAddr(v) => self.ip_idx.get(v).copied(),
44 _ => None,
45 }
46 }
47
48 fn try_up_idx(&mut self, param: &DataField) -> Option<usize> {
49 match param.get_value() {
50 Value::Chars(v) => {
51 if let Some(idx) = self.str_idx.get(v) {
52 Some(*idx)
53 } else {
54 self.idx_num += 1;
55 self.str_idx.insert(v.clone(), self.idx_num);
56 Some(self.idx_num)
57 }
58 }
59 Value::Digit(v) => {
60 if let Some(idx) = self.i64_idx.get(v) {
61 Some(*idx)
62 } else {
63 self.idx_num += 1;
64 self.i64_idx.insert(*v, self.idx_num);
65 Some(self.idx_num)
66 }
67 }
68 Value::IpAddr(v) => {
69 if let Some(idx) = self.ip_idx.get(v) {
70 Some(*idx)
71 } else {
72 self.idx_num += 1;
73 self.ip_idx.insert(*v, self.idx_num);
74 Some(self.idx_num)
75 }
76 }
77 _ => None,
78 }
79 }
80
81 fn reset(&mut self) {
82 self.str_idx.clear();
83 self.i64_idx.clear();
84 self.ip_idx.clear();
85 self.cache_data.clear();
86 self.idx_num = 0;
87 }
88}
89
90#[derive(PartialEq, Eq, Hash, Debug, Clone)]
91pub enum EnumSizeIndex {
92 Idx1(usize),
93 Idx2(usize, usize),
94 Idx3(usize, usize, usize),
95 Idx4(usize, usize, usize, usize),
96 Idx5(usize, usize, usize, usize, usize),
97 Idx6(usize, usize, usize, usize, usize, usize),
98}
99
100#[derive(PartialEq, Eq, Hash, Debug, Clone)]
101struct LocalCacheKey {
102 scope_hash: u64,
103 idxs: EnumSizeIndex,
104}
105
106pub trait CacheAble<P, T, const N: usize> {
107 fn prepare_generation(&mut self, _generation: u64) {}
108 fn save_scoped(&mut self, _scope_hash: u64, params: &[P; N], result: T) {
109 self.save(params, result);
110 }
111 fn fetch_scoped(&self, _scope_hash: u64, params: &[P; N]) -> Option<&T> {
112 self.fetch(params)
113 }
114 fn save(&mut self, params: &[P; N], result: T);
115 fn fetch(&self, params: &[P; N]) -> Option<&T>;
116}
117
118impl CacheAble<DataField, Vec<DataField>, 1> for FieldQueryCache {
119 fn prepare_generation(&mut self, generation: u64) {
120 if self.generation != Some(generation) {
121 self.reset();
122 self.generation = Some(generation);
123 }
124 }
125 fn save_scoped(&mut self, scope_hash: u64, params: &[DataField; 1], result: Vec<DataField>) {
126 if let Some(i0) = self.try_up_idx(¶ms[0]) {
127 self.cache_data.put(
128 LocalCacheKey {
129 scope_hash,
130 idxs: EnumSizeIndex::Idx1(i0),
131 },
132 result,
133 );
134 }
135 }
136
137 fn fetch_scoped(&self, scope_hash: u64, params: &[DataField; 1]) -> Option<&Vec<DataField>> {
138 if let Some(i0) = self.get_idx(¶ms[0]) {
139 return self.cache_data.peek(&LocalCacheKey {
140 scope_hash,
141 idxs: EnumSizeIndex::Idx1(i0),
142 });
143 }
144 None
145 }
146
147 fn save(&mut self, params: &[DataField; 1], result: Vec<DataField>) {
148 self.save_scoped(0, params, result);
149 }
150
151 fn fetch(&self, params: &[DataField; 1]) -> Option<&Vec<DataField>> {
152 self.fetch_scoped(0, params)
153 }
154}
155
156impl CacheAble<DataField, Vec<DataField>, 2> for FieldQueryCache {
157 fn prepare_generation(&mut self, generation: u64) {
158 if self.generation != Some(generation) {
159 self.reset();
160 self.generation = Some(generation);
161 }
162 }
163
164 fn save_scoped(&mut self, scope_hash: u64, params: &[DataField; 2], result: Vec<DataField>) {
165 if let (Some(i0), Some(i1)) = (self.try_up_idx(¶ms[0]), self.try_up_idx(¶ms[1])) {
166 self.cache_data.put(
167 LocalCacheKey {
168 scope_hash,
169 idxs: EnumSizeIndex::Idx2(i0, i1),
170 },
171 result,
172 );
173 }
174 }
175
176 fn fetch_scoped(&self, scope_hash: u64, params: &[DataField; 2]) -> Option<&Vec<DataField>> {
177 if let (Some(i0), Some(i1)) = (self.get_idx(¶ms[0]), self.get_idx(¶ms[1])) {
178 return self.cache_data.peek(&LocalCacheKey {
179 scope_hash,
180 idxs: EnumSizeIndex::Idx2(i0, i1),
181 });
182 }
183 None
184 }
185
186 fn save(&mut self, params: &[DataField; 2], result: Vec<DataField>) {
187 self.save_scoped(0, params, result);
188 }
189
190 fn fetch(&self, params: &[DataField; 2]) -> Option<&Vec<DataField>> {
191 self.fetch_scoped(0, params)
192 }
193}
194
195impl CacheAble<DataField, Vec<DataField>, 3> for FieldQueryCache {
196 fn prepare_generation(&mut self, generation: u64) {
197 if self.generation != Some(generation) {
198 self.reset();
199 self.generation = Some(generation);
200 }
201 }
202
203 fn save_scoped(&mut self, scope_hash: u64, params: &[DataField; 3], result: Vec<DataField>) {
204 if let (Some(i0), Some(i1), Some(i2)) = (
205 self.try_up_idx(¶ms[0]),
206 self.try_up_idx(¶ms[1]),
207 self.try_up_idx(¶ms[2]),
208 ) {
209 self.cache_data.put(
210 LocalCacheKey {
211 scope_hash,
212 idxs: EnumSizeIndex::Idx3(i0, i1, i2),
213 },
214 result,
215 );
216 }
217 }
218
219 fn fetch_scoped(&self, scope_hash: u64, params: &[DataField; 3]) -> Option<&Vec<DataField>> {
220 if let (Some(i0), Some(i1), Some(i2)) = (
221 self.get_idx(¶ms[0]),
222 self.get_idx(¶ms[1]),
223 self.get_idx(¶ms[2]),
224 ) {
225 return self.cache_data.peek(&LocalCacheKey {
226 scope_hash,
227 idxs: EnumSizeIndex::Idx3(i0, i1, i2),
228 });
229 }
230 None
231 }
232
233 fn save(&mut self, params: &[DataField; 3], result: Vec<DataField>) {
234 self.save_scoped(0, params, result);
235 }
236
237 fn fetch(&self, params: &[DataField; 3]) -> Option<&Vec<DataField>> {
238 self.fetch_scoped(0, params)
239 }
240}
241
242impl CacheAble<DataField, Vec<DataField>, 4> for FieldQueryCache {
243 fn prepare_generation(&mut self, generation: u64) {
244 if self.generation != Some(generation) {
245 self.reset();
246 self.generation = Some(generation);
247 }
248 }
249
250 fn save_scoped(&mut self, scope_hash: u64, params: &[DataField; 4], result: Vec<DataField>) {
251 if let (Some(i0), Some(i1), Some(i2), Some(i3)) = (
252 self.try_up_idx(¶ms[0]),
253 self.try_up_idx(¶ms[1]),
254 self.try_up_idx(¶ms[2]),
255 self.try_up_idx(¶ms[3]),
256 ) {
257 self.cache_data.put(
258 LocalCacheKey {
259 scope_hash,
260 idxs: EnumSizeIndex::Idx4(i0, i1, i2, i3),
261 },
262 result,
263 );
264 }
265 }
266
267 fn fetch_scoped(&self, scope_hash: u64, params: &[DataField; 4]) -> Option<&Vec<DataField>> {
268 if let (Some(i0), Some(i1), Some(i2), Some(i3)) = (
269 self.get_idx(¶ms[0]),
270 self.get_idx(¶ms[1]),
271 self.get_idx(¶ms[2]),
272 self.get_idx(¶ms[3]),
273 ) {
274 return self.cache_data.peek(&LocalCacheKey {
275 scope_hash,
276 idxs: EnumSizeIndex::Idx4(i0, i1, i2, i3),
277 });
278 }
279 None
280 }
281
282 fn save(&mut self, params: &[DataField; 4], result: Vec<DataField>) {
283 self.save_scoped(0, params, result);
284 }
285
286 fn fetch(&self, params: &[DataField; 4]) -> Option<&Vec<DataField>> {
287 self.fetch_scoped(0, params)
288 }
289}
290
291impl CacheAble<DataField, Vec<DataField>, 5> for FieldQueryCache {
292 fn prepare_generation(&mut self, generation: u64) {
293 if self.generation != Some(generation) {
294 self.reset();
295 self.generation = Some(generation);
296 }
297 }
298
299 fn save_scoped(&mut self, scope_hash: u64, params: &[DataField; 5], result: Vec<DataField>) {
300 if let (Some(i0), Some(i1), Some(i2), Some(i3), Some(i4)) = (
301 self.try_up_idx(¶ms[0]),
302 self.try_up_idx(¶ms[1]),
303 self.try_up_idx(¶ms[2]),
304 self.try_up_idx(¶ms[3]),
305 self.try_up_idx(¶ms[4]),
306 ) {
307 self.cache_data.put(
308 LocalCacheKey {
309 scope_hash,
310 idxs: EnumSizeIndex::Idx5(i0, i1, i2, i3, i4),
311 },
312 result,
313 );
314 }
315 }
316
317 fn fetch_scoped(&self, scope_hash: u64, params: &[DataField; 5]) -> Option<&Vec<DataField>> {
318 if let (Some(i0), Some(i1), Some(i2), Some(i3), Some(i4)) = (
319 self.get_idx(¶ms[0]),
320 self.get_idx(¶ms[1]),
321 self.get_idx(¶ms[2]),
322 self.get_idx(¶ms[3]),
323 self.get_idx(¶ms[4]),
324 ) {
325 return self.cache_data.peek(&LocalCacheKey {
326 scope_hash,
327 idxs: EnumSizeIndex::Idx5(i0, i1, i2, i3, i4),
328 });
329 }
330 None
331 }
332
333 fn save(&mut self, params: &[DataField; 5], result: Vec<DataField>) {
334 self.save_scoped(0, params, result);
335 }
336
337 fn fetch(&self, params: &[DataField; 5]) -> Option<&Vec<DataField>> {
338 self.fetch_scoped(0, params)
339 }
340}
341
342impl CacheAble<DataField, Vec<DataField>, 6> for FieldQueryCache {
343 fn prepare_generation(&mut self, generation: u64) {
344 if self.generation != Some(generation) {
345 self.reset();
346 self.generation = Some(generation);
347 }
348 }
349
350 fn save_scoped(&mut self, scope_hash: u64, params: &[DataField; 6], result: Vec<DataField>) {
351 if let (Some(i0), Some(i1), Some(i2), Some(i3), Some(i4), Some(i5)) = (
352 self.try_up_idx(¶ms[0]),
353 self.try_up_idx(¶ms[1]),
354 self.try_up_idx(¶ms[2]),
355 self.try_up_idx(¶ms[3]),
356 self.try_up_idx(¶ms[4]),
357 self.try_up_idx(¶ms[5]),
358 ) {
359 self.cache_data.put(
360 LocalCacheKey {
361 scope_hash,
362 idxs: EnumSizeIndex::Idx6(i0, i1, i2, i3, i4, i5),
363 },
364 result,
365 );
366 }
367 }
368
369 fn fetch_scoped(&self, scope_hash: u64, params: &[DataField; 6]) -> Option<&Vec<DataField>> {
370 if let (Some(i0), Some(i1), Some(i2), Some(i3), Some(i4), Some(i5)) = (
371 self.get_idx(¶ms[0]),
372 self.get_idx(¶ms[1]),
373 self.get_idx(¶ms[2]),
374 self.get_idx(¶ms[3]),
375 self.get_idx(¶ms[4]),
376 self.get_idx(¶ms[5]),
377 ) {
378 return self.cache_data.peek(&LocalCacheKey {
379 scope_hash,
380 idxs: EnumSizeIndex::Idx6(i0, i1, i2, i3, i4, i5),
381 });
382 }
383 None
384 }
385
386 fn save(&mut self, params: &[DataField; 6], result: Vec<DataField>) {
387 self.save_scoped(0, params, result);
388 }
389
390 fn fetch(&self, params: &[DataField; 6]) -> Option<&Vec<DataField>> {
391 self.fetch_scoped(0, params)
392 }
393}