1
use std::{error::Error as StdError, num::NonZeroUsize, sync::Arc};
2

            
3
use async_trait::async_trait;
4
use lru::LruCache;
5
use tokio::sync::RwLock;
6

            
7
use super::super::{
8
    device::{QueryCond as DeviceQueryCond, QueryOneCond as DeviceQueryOneCond},
9
    device_route::{
10
        DelCachePubQueryCond, DelCacheQueryCond, DeviceRouteCache, DeviceRouteCacheDlData,
11
        DeviceRouteCacheUlData, GetCachePubQueryCond, GetCacheQueryCond, ListOptions,
12
        ListQueryCond,
13
    },
14
    Model,
15
};
16

            
17
pub struct Cache {
18
    model: Arc<dyn Model>,
19
    uldata: Arc<RwLock<LruCache<String, Option<DeviceRouteCacheUlData>>>>,
20
    dldata: Arc<RwLock<LruCache<String, Option<DeviceRouteCacheDlData>>>>,
21
    dldata_pub: Arc<RwLock<LruCache<String, Option<DeviceRouteCacheDlData>>>>,
22
}
23

            
24
pub struct Options {
25
    pub uldata_size: usize,
26
    pub dldata_size: usize,
27
    pub dldata_pub_size: usize,
28
}
29

            
30
const DEF_SIZE: usize = 10_000;
31

            
32
impl Cache {
33
20
    pub fn new(opts: &Options, model: Arc<dyn Model>) -> Self {
34
20
        let (uldata, dldata, dldata_pub) = unsafe {
35
20
            (
36
20
                NonZeroUsize::new_unchecked(opts.uldata_size),
37
20
                NonZeroUsize::new_unchecked(opts.dldata_size),
38
20
                NonZeroUsize::new_unchecked(opts.dldata_pub_size),
39
20
            )
40
20
        };
41
20
        Cache {
42
20
            model,
43
20
            uldata: Arc::new(RwLock::new(LruCache::new(uldata))),
44
20
            dldata: Arc::new(RwLock::new(LruCache::new(dldata))),
45
20
            dldata_pub: Arc::new(RwLock::new(LruCache::new(dldata_pub))),
46
20
        }
47
20
    }
48
}
49

            
50
#[async_trait]
51
impl DeviceRouteCache for Cache {
52
104
    async fn clear(&self) -> Result<(), Box<dyn StdError>> {
53
        // To collect all locks before clearing cache.
54
104
        let mut lock1 = self.uldata.write().await;
55
104
        let mut lock2 = self.dldata.write().await;
56
104
        let mut lock3 = self.dldata_pub.write().await;
57
104
        lock1.clear();
58
104
        lock2.clear();
59
104
        lock3.clear();
60
104
        Ok(())
61
208
    }
62

            
63
    async fn get_uldata(
64
        &self,
65
        device_id: &str,
66
52
    ) -> Result<Option<DeviceRouteCacheUlData>, Box<dyn StdError>> {
67
        {
68
52
            let mut lock = self.uldata.write().await;
69
52
            if let Some(value) = lock.get(device_id) {
70
12
                return Ok(value.clone());
71
40
            }
72
40
        }
73
40

            
74
40
        let opts = ListOptions {
75
40
            cond: &ListQueryCond {
76
40
                device_id: Some(device_id),
77
40
                ..Default::default()
78
40
            },
79
40
            offset: None,
80
40
            limit: None,
81
40
            sort: None,
82
40
            cursor_max: None,
83
40
        };
84
40
        let (mut routes, _) = self.model.device_route().list(&opts, None).await?;
85
40
        let data: Option<DeviceRouteCacheUlData> = match routes.len() {
86
12
            0 => None,
87
            _ => {
88
28
                let mut routes_data = vec![];
89
32
                for r in routes.iter() {
90
32
                    routes_data.push(format!("{}.{}", r.unit_code, r.application_code))
91
                }
92
28
                let _ = routes.pop().unwrap();
93
28
                Some(DeviceRouteCacheUlData {
94
28
                    app_mgr_keys: routes_data,
95
28
                })
96
            }
97
        };
98
40
        let _ = self.set_uldata(device_id, data.as_ref()).await;
99
40
        Ok(data)
100
104
    }
101

            
102
    async fn set_uldata(
103
        &self,
104
        device_id: &str,
105
        value: Option<&DeviceRouteCacheUlData>,
106
40
    ) -> Result<(), Box<dyn StdError>> {
107
40
        let key = device_id.to_string();
108
40
        let mut lock = self.uldata.write().await;
109
40
        let _ = match value {
110
12
            None => lock.push(key, None),
111
28
            Some(value) => lock.push(key, Some(value.clone())),
112
        };
113
40
        Ok(())
114
80
    }
115

            
116
69818
    async fn del_uldata(&self, device_id: &str) -> Result<(), Box<dyn StdError>> {
117
69818
        let mut lock = self.uldata.write().await;
118
69818
        lock.pop(device_id);
119
69818
        Ok(())
120
139636
    }
121

            
122
    async fn get_dldata(
123
        &self,
124
        cond: &GetCacheQueryCond,
125
20
    ) -> Result<Option<DeviceRouteCacheDlData>, Box<dyn StdError>> {
126
20
        let key = format!(
127
20
            "{}.{}.{}",
128
20
            cond.unit_code, cond.network_code, cond.network_addr
129
20
        );
130

            
131
        {
132
20
            let mut lock = self.dldata.write().await;
133
20
            if let Some(value) = lock.get(&key) {
134
4
                match value {
135
2
                    None => return Ok(None),
136
2
                    Some(value) => return Ok(Some(value.clone())),
137
                }
138
16
            }
139
16
        }
140
16

            
141
16
        let dev_cond = DeviceQueryCond {
142
16
            device: Some(DeviceQueryOneCond {
143
16
                unit_code: Some(cond.unit_code),
144
16
                network_code: cond.network_code,
145
16
                network_addr: cond.network_addr,
146
16
            }),
147
16
            ..Default::default()
148
16
        };
149
16
        let device = self.model.device().get(&dev_cond).await?;
150
16
        let data = match device {
151
4
            None => None,
152
12
            Some(device) => match device.unit_code.as_ref() {
153
                // This should not occur!
154
                None => None,
155
12
                Some(unit_code) => Some(DeviceRouteCacheDlData {
156
12
                    net_mgr_key: format!("{}.{}", unit_code, cond.network_code),
157
12
                    network_id: device.network_id,
158
12
                    network_addr: device.network_addr,
159
12
                    device_id: device.device_id,
160
12
                    profile: device.profile,
161
12
                }),
162
            },
163
        };
164
16
        let _ = self.set_dldata(cond, data.as_ref()).await;
165
16
        Ok(data)
166
40
    }
167

            
168
    async fn set_dldata(
169
        &self,
170
        cond: &GetCacheQueryCond,
171
        value: Option<&DeviceRouteCacheDlData>,
172
16
    ) -> Result<(), Box<dyn StdError>> {
173
16
        let key = format!(
174
16
            "{}.{}.{}",
175
16
            cond.unit_code, cond.network_code, cond.network_addr
176
16
        );
177
16
        let mut lock = self.dldata.write().await;
178
16
        let _ = match value {
179
4
            None => lock.push(key, None),
180
12
            Some(value) => lock.push(key, Some(value.clone())),
181
        };
182
16
        Ok(())
183
32
    }
184

            
185
32932
    async fn del_dldata(&self, cond: &DelCacheQueryCond) -> Result<(), Box<dyn StdError>> {
186
32932
        let key = match cond.network_code {
187
            None => {
188
                // Remove all routes of the unit.
189
16
                cond.unit_code.to_string()
190
            }
191
32916
            Some(code) => match cond.network_addr {
192
                None => {
193
                    // Remove all routes of the network.
194
2
                    format!("{}.{}", cond.unit_code, code)
195
                }
196
32914
                Some(addr) => {
197
32914
                    let key = format!("{}.{}.{}", cond.unit_code, code, addr);
198
32914
                    let mut lock = self.dldata.write().await;
199
32914
                    let _ = lock.pop(&key);
200
32914
                    return Ok(());
201
                }
202
            },
203
        };
204
        {
205
18
            let mut lock = self.dldata.write().await;
206
            loop {
207
22
                let mut rm_key = None;
208
22
                for (k, _) in lock.iter() {
209
6
                    if k.starts_with(key.as_str()) {
210
4
                        rm_key = Some(k.clone());
211
4
                        break;
212
2
                    }
213
                }
214
22
                match rm_key {
215
18
                    None => break,
216
4
                    Some(key) => {
217
4
                        let _ = lock.pop(&key);
218
4
                    }
219
                }
220
            }
221
        }
222
18
        Ok(())
223
65864
    }
224

            
225
    async fn get_dldata_pub(
226
        &self,
227
        cond: &GetCachePubQueryCond,
228
22
    ) -> Result<Option<DeviceRouteCacheDlData>, Box<dyn StdError>> {
229
22
        let key = format!("{}.{}", cond.unit_id, cond.device_id);
230

            
231
        {
232
22
            let mut lock = self.dldata_pub.write().await;
233
22
            if let Some(value) = lock.get(&key) {
234
6
                match value {
235
2
                    None => return Ok(None),
236
4
                    Some(value) => return Ok(Some(value.clone())),
237
                }
238
16
            }
239
16
        }
240
16

            
241
16
        let dev_cond = DeviceQueryCond {
242
16
            unit_id: Some(cond.unit_id),
243
16
            device_id: Some(cond.device_id),
244
16
            ..Default::default()
245
16
        };
246
16
        let device = self.model.device().get(&dev_cond).await?;
247
16
        let data = match device {
248
2
            None => None,
249
14
            Some(device) => match device.unit_code.as_ref() {
250
6
                None => Some(DeviceRouteCacheDlData {
251
6
                    net_mgr_key: format!(".{}", device.network_code),
252
6
                    network_id: device.network_id,
253
6
                    network_addr: device.network_addr,
254
6
                    device_id: device.device_id,
255
6
                    profile: device.profile,
256
6
                }),
257
8
                Some(unit_code) => Some(DeviceRouteCacheDlData {
258
8
                    net_mgr_key: format!("{}.{}", unit_code, device.network_code),
259
8
                    network_id: device.network_id,
260
8
                    network_addr: device.network_addr,
261
8
                    device_id: device.device_id,
262
8
                    profile: device.profile,
263
8
                }),
264
            },
265
        };
266
16
        let _ = self.set_dldata_pub(cond, data.as_ref()).await;
267
16
        Ok(data)
268
44
    }
269

            
270
    async fn set_dldata_pub(
271
        &self,
272
        cond: &GetCachePubQueryCond,
273
        value: Option<&DeviceRouteCacheDlData>,
274
16
    ) -> Result<(), Box<dyn StdError>> {
275
16
        let key = format!("{}.{}", cond.unit_id, cond.device_id);
276
16
        let mut lock = self.dldata_pub.write().await;
277
16
        let _ = match value {
278
2
            None => lock.push(key, None),
279
14
            Some(value) => lock.push(key, Some(value.clone())),
280
        };
281
16
        Ok(())
282
32
    }
283

            
284
32930
    async fn del_dldata_pub(&self, cond: &DelCachePubQueryCond) -> Result<(), Box<dyn StdError>> {
285
32930
        let key = match cond.device_id {
286
            None => {
287
                // Remove all routes of the unit.
288
16
                cond.unit_id.to_string()
289
            }
290
32914
            Some(id) => {
291
32914
                let key = format!("{}.{}", cond.unit_id, id);
292
                {
293
32914
                    let mut lock = self.dldata_pub.write().await;
294
32914
                    lock.pop(&key);
295
32914
                }
296
32914
                return Ok(());
297
            }
298
        };
299
        {
300
16
            let mut lock = self.dldata_pub.write().await;
301
            loop {
302
20
                let mut rm_key = None;
303
20
                for (k, _) in lock.iter() {
304
4
                    if k.starts_with(key.as_str()) {
305
4
                        rm_key = Some(k.clone());
306
4
                        break;
307
                    }
308
                }
309
20
                match rm_key {
310
16
                    None => break,
311
4
                    Some(key) => {
312
4
                        let _ = lock.pop(&key);
313
4
                    }
314
                }
315
            }
316
        }
317
16
        Ok(())
318
65860
    }
319
}
320

            
321
impl Default for Options {
322
10
    fn default() -> Self {
323
10
        Options {
324
10
            uldata_size: DEF_SIZE,
325
10
            dldata_size: DEF_SIZE,
326
10
            dldata_pub_size: DEF_SIZE,
327
10
        }
328
10
    }
329
}