capsules_extra/
tickv_kv_store.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! TicKV to Tock key-value store capsule.
6//!
7//! This capsule provides a higher level Key-Value store interface based on an
8//! underlying `tickv::kv_system` storage layer.
9//!
10//! ```text
11//! +-----------------------+
12//! |  Capsule using K-V    |
13//! +-----------------------+
14//!
15//!    hil::kv::KV
16//!
17//! +-----------------------+
18//! | K-V store (this file) |
19//! +-----------------------+
20//!
21//!    capsules::tickv::kv_system
22//!
23//! +-----------------------+
24//! |  K-V library          |
25//! +-----------------------+
26//!
27//!    hil::flash
28//! ```
29
30use crate::tickv::{KVSystem, KVSystemClient, KeyType};
31use kernel::hil::kv;
32use kernel::utilities::cells::{MapCell, OptionalCell, TakeCell};
33use kernel::utilities::leasable_buffer::SubSliceMut;
34use kernel::ErrorCode;
35
36#[derive(Clone, Copy, PartialEq, Debug)]
37enum Operation {
38    Get,
39    Set,
40    Add,
41    Update,
42    Delete,
43    GarbageCollect,
44}
45
46/// `TicKVKVStore` implements the KV interface using the TicKV KVSystem
47/// interface.
48pub struct TicKVKVStore<'a, K: KVSystem<'a> + KVSystem<'a, K = T>, T: 'static + KeyType> {
49    kv: &'a K,
50    hashed_key: TakeCell<'static, T>,
51
52    client: OptionalCell<&'a dyn kv::KVClient>,
53    operation: OptionalCell<Operation>,
54
55    unhashed_key: MapCell<SubSliceMut<'static, u8>>,
56    value: MapCell<SubSliceMut<'static, u8>>,
57}
58
59impl<'a, K: KVSystem<'a, K = T>, T: KeyType> TicKVKVStore<'a, K, T> {
60    pub fn new(kv: &'a K, key: &'static mut T) -> TicKVKVStore<'a, K, T> {
61        Self {
62            kv,
63            hashed_key: TakeCell::new(key),
64            client: OptionalCell::empty(),
65            operation: OptionalCell::empty(),
66            unhashed_key: MapCell::empty(),
67            value: MapCell::empty(),
68        }
69    }
70
71    fn insert(
72        &self,
73        key: SubSliceMut<'static, u8>,
74        value: SubSliceMut<'static, u8>,
75        operation: Operation,
76    ) -> Result<
77        (),
78        (
79            SubSliceMut<'static, u8>,
80            SubSliceMut<'static, u8>,
81            ErrorCode,
82        ),
83    > {
84        if self.operation.is_some() {
85            return Err((key, value, ErrorCode::BUSY));
86        }
87
88        self.operation.set(operation);
89
90        match self.hashed_key.take() {
91            Some(hashed_key) => match self.kv.generate_key(key, hashed_key) {
92                Ok(()) => {
93                    self.value.replace(value);
94                    Ok(())
95                }
96                Err((unhashed_key, hashed_key, _e)) => {
97                    self.operation.clear();
98                    self.hashed_key.replace(hashed_key);
99                    Err((unhashed_key, value, ErrorCode::FAIL))
100                }
101            },
102            None => Err((key, value, ErrorCode::FAIL)),
103        }
104    }
105}
106
107impl<'a, K: KVSystem<'a, K = T>, T: KeyType> kv::KV<'a> for TicKVKVStore<'a, K, T> {
108    fn set_client(&self, client: &'a dyn kv::KVClient) {
109        self.client.set(client);
110    }
111
112    fn get(
113        &self,
114        key: SubSliceMut<'static, u8>,
115        value: SubSliceMut<'static, u8>,
116    ) -> Result<
117        (),
118        (
119            SubSliceMut<'static, u8>,
120            SubSliceMut<'static, u8>,
121            ErrorCode,
122        ),
123    > {
124        if self.operation.is_some() {
125            return Err((key, value, ErrorCode::BUSY));
126        }
127
128        self.operation.set(Operation::Get);
129
130        match self.hashed_key.take() {
131            Some(hashed_key) => match self.kv.generate_key(key, hashed_key) {
132                Ok(()) => {
133                    self.value.replace(value);
134                    Ok(())
135                }
136                Err((unhashed_key, hashed_key, _e)) => {
137                    self.operation.clear();
138                    self.hashed_key.replace(hashed_key);
139                    Err((unhashed_key, value, ErrorCode::FAIL))
140                }
141            },
142            None => Err((key, value, ErrorCode::FAIL)),
143        }
144    }
145
146    fn set(
147        &self,
148        key: SubSliceMut<'static, u8>,
149        value: SubSliceMut<'static, u8>,
150    ) -> Result<
151        (),
152        (
153            SubSliceMut<'static, u8>,
154            SubSliceMut<'static, u8>,
155            ErrorCode,
156        ),
157    > {
158        self.insert(key, value, Operation::Set)
159    }
160
161    fn add(
162        &self,
163        key: SubSliceMut<'static, u8>,
164        value: SubSliceMut<'static, u8>,
165    ) -> Result<
166        (),
167        (
168            SubSliceMut<'static, u8>,
169            SubSliceMut<'static, u8>,
170            ErrorCode,
171        ),
172    > {
173        self.insert(key, value, Operation::Add)
174    }
175
176    fn update(
177        &self,
178        key: SubSliceMut<'static, u8>,
179        value: SubSliceMut<'static, u8>,
180    ) -> Result<
181        (),
182        (
183            SubSliceMut<'static, u8>,
184            SubSliceMut<'static, u8>,
185            ErrorCode,
186        ),
187    > {
188        self.insert(key, value, Operation::Update)
189    }
190
191    fn delete(
192        &self,
193        key: SubSliceMut<'static, u8>,
194    ) -> Result<(), (SubSliceMut<'static, u8>, ErrorCode)> {
195        if self.operation.is_some() {
196            return Err((key, ErrorCode::BUSY));
197        }
198
199        self.operation.set(Operation::Delete);
200
201        match self.hashed_key.take() {
202            Some(hashed_key) => match self.kv.generate_key(key, hashed_key) {
203                Ok(()) => Ok(()),
204                Err((unhashed_key, hashed_key, _e)) => {
205                    self.hashed_key.replace(hashed_key);
206                    self.operation.clear();
207                    Err((unhashed_key, ErrorCode::FAIL))
208                }
209            },
210            None => Err((key, ErrorCode::FAIL)),
211        }
212    }
213
214    fn garbage_collect(&self) -> Result<(), ErrorCode> {
215        if self.operation.is_some() {
216            return Err(ErrorCode::BUSY);
217        }
218
219        self.operation.set(Operation::GarbageCollect);
220
221        if let Err(e) = self.kv.garbage_collect() {
222            self.operation.clear();
223            Err(e)
224        } else {
225            Ok(())
226        }
227    }
228}
229
230impl<'a, K: KVSystem<'a, K = T>, T: KeyType> KVSystemClient<T> for TicKVKVStore<'a, K, T> {
231    fn generate_key_complete(
232        &self,
233        result: Result<(), ErrorCode>,
234        unhashed_key: SubSliceMut<'static, u8>,
235        hashed_key: &'static mut T,
236    ) {
237        self.operation.map(|op| {
238            if result.is_err() {
239                // On error, we re-store our state, run the next pending
240                // operation, and notify the original user that their operation
241                // failed using a callback.
242                self.hashed_key.replace(hashed_key);
243                self.operation.clear();
244
245                match op {
246                    Operation::Get => {
247                        self.value.take().map(|value| {
248                            self.client.map(move |cb| {
249                                cb.get_complete(Err(ErrorCode::FAIL), unhashed_key, value);
250                            });
251                        });
252                    }
253                    Operation::Set => {
254                        self.value.take().map(|value| {
255                            self.client.map(move |cb| {
256                                cb.set_complete(Err(ErrorCode::FAIL), unhashed_key, value);
257                            });
258                        });
259                    }
260                    Operation::Add => {
261                        self.value.take().map(|value| {
262                            self.client.map(move |cb| {
263                                cb.add_complete(Err(ErrorCode::FAIL), unhashed_key, value);
264                            });
265                        });
266                    }
267                    Operation::Update => {
268                        self.value.take().map(|value| {
269                            self.client.map(move |cb| {
270                                cb.update_complete(Err(ErrorCode::FAIL), unhashed_key, value);
271                            });
272                        });
273                    }
274                    Operation::Delete => {
275                        self.client.map(move |cb| {
276                            cb.delete_complete(Err(ErrorCode::FAIL), unhashed_key);
277                        });
278                    }
279                    Operation::GarbageCollect => {}
280                }
281            } else {
282                match op {
283                    Operation::Get => {
284                        self.value
285                            .take()
286                            .map(|value| match self.kv.get_value(hashed_key, value) {
287                                Ok(()) => {
288                                    self.unhashed_key.replace(unhashed_key);
289                                }
290                                Err((key, value, _e)) => {
291                                    self.hashed_key.replace(key);
292                                    self.operation.clear();
293                                    self.client.map(move |cb| {
294                                        cb.get_complete(Err(ErrorCode::FAIL), unhashed_key, value);
295                                    });
296                                }
297                            });
298                    }
299                    Operation::Set => {
300                        self.value.take().map(|value| {
301                            // Try to append which will work if the key is new.
302                            match self.kv.append_key(hashed_key, value) {
303                                Ok(()) => {
304                                    self.unhashed_key.replace(unhashed_key);
305                                }
306                                Err((key, value, e)) => {
307                                    self.hashed_key.replace(key);
308                                    self.operation.clear();
309                                    self.client.map(move |cb| {
310                                        cb.set_complete(Err(e), unhashed_key, value);
311                                    });
312                                }
313                            }
314                        });
315                    }
316                    Operation::Add => {
317                        self.value.take().map(|value| {
318                            // Add only works if the key does not exist, so we
319                            // can go right to append.
320                            match self.kv.append_key(hashed_key, value) {
321                                Ok(()) => {
322                                    self.unhashed_key.replace(unhashed_key);
323                                }
324                                Err((key, value, e)) => {
325                                    self.hashed_key.replace(key);
326                                    self.operation.clear();
327                                    self.client.map(move |cb| {
328                                        cb.add_complete(Err(e), unhashed_key, value);
329                                    });
330                                }
331                            }
332                        });
333                    }
334                    Operation::Update => {
335                        // Update requires the key to exist, so we start by
336                        // trying to delete it.
337                        match self.kv.invalidate_key(hashed_key) {
338                            Ok(()) => {
339                                self.unhashed_key.replace(unhashed_key);
340                            }
341                            Err((key, _e)) => {
342                                self.hashed_key.replace(key);
343                                self.operation.clear();
344                                self.value.take().map(|value| {
345                                    self.client.map(move |cb| {
346                                        cb.update_complete(
347                                            Err(ErrorCode::FAIL),
348                                            unhashed_key,
349                                            value,
350                                        );
351                                    });
352                                });
353                            }
354                        }
355                    }
356                    Operation::Delete => match self.kv.invalidate_key(hashed_key) {
357                        Ok(()) => {
358                            self.unhashed_key.replace(unhashed_key);
359                        }
360                        Err((key, _e)) => {
361                            self.hashed_key.replace(key);
362                            self.operation.clear();
363                            self.client.map(move |cb| {
364                                cb.delete_complete(Err(ErrorCode::FAIL), unhashed_key);
365                            });
366                        }
367                    },
368                    Operation::GarbageCollect => {}
369                }
370            }
371        });
372    }
373
374    fn append_key_complete(
375        &self,
376        result: Result<(), ErrorCode>,
377        key: &'static mut T,
378        value: SubSliceMut<'static, u8>,
379    ) {
380        self.hashed_key.replace(key);
381
382        self.operation.map(|op| match op {
383            Operation::Get | Operation::Delete => {}
384            Operation::Set => {
385                match result {
386                    Err(ErrorCode::NOSUPPORT) => {
387                        // We could not append because of a collision. So now we
388                        // need to delete the existing key.
389                        self.hashed_key.take().map(|hashed_key| {
390                            match self.kv.invalidate_key(hashed_key) {
391                                Ok(()) => {
392                                    self.value.replace(value);
393                                }
394                                Err((key, _e)) => {
395                                    self.hashed_key.replace(key);
396                                    self.operation.clear();
397                                    self.unhashed_key.take().map(|unhashed_key| {
398                                        self.client.map(move |cb| {
399                                            cb.set_complete(
400                                                Err(ErrorCode::FAIL),
401                                                unhashed_key,
402                                                value,
403                                            );
404                                        });
405                                    });
406                                }
407                            }
408                        });
409                    }
410                    _ => {
411                        // On success or any other error we just return the
412                        // result back to the caller via a callback.
413                        self.operation.clear();
414                        self.unhashed_key.take().map(|unhashed_key| {
415                            self.client.map(move |cb| {
416                                cb.set_complete(
417                                    result.map_err(|e| match e {
418                                        ErrorCode::NOMEM => ErrorCode::NOMEM,
419                                        _ => ErrorCode::FAIL,
420                                    }),
421                                    unhashed_key,
422                                    value,
423                                );
424                            });
425                        });
426                    }
427                }
428            }
429            Operation::Add => {
430                self.operation.clear();
431                self.unhashed_key.take().map(|unhashed_key| {
432                    self.client.map(move |cb| {
433                        cb.add_complete(
434                            result.map_err(|e| match e {
435                                ErrorCode::NOSUPPORT => ErrorCode::NOSUPPORT,
436                                ErrorCode::NOMEM => ErrorCode::NOMEM,
437                                _ => ErrorCode::FAIL,
438                            }),
439                            unhashed_key,
440                            value,
441                        );
442                    });
443                });
444            }
445            Operation::Update => {
446                self.operation.clear();
447                self.unhashed_key.take().map(|unhashed_key| {
448                    self.client.map(move |cb| {
449                        cb.update_complete(
450                            result.map_err(|e| match e {
451                                ErrorCode::NOMEM => ErrorCode::NOMEM,
452                                _ => ErrorCode::FAIL,
453                            }),
454                            unhashed_key,
455                            value,
456                        );
457                    });
458                });
459            }
460            Operation::GarbageCollect => {}
461        });
462    }
463
464    fn get_value_complete(
465        &self,
466        result: Result<(), ErrorCode>,
467        key: &'static mut T,
468        ret_buf: SubSliceMut<'static, u8>,
469    ) {
470        self.operation.map(|op| match op {
471            Operation::Get => {
472                self.hashed_key.replace(key);
473                self.operation.clear();
474
475                self.unhashed_key.take().map(|unhashed_key| {
476                    self.client.map(move |cb| {
477                        cb.get_complete(
478                            result.map_err(|e| match e {
479                                ErrorCode::SIZE => ErrorCode::SIZE,
480                                ErrorCode::NOSUPPORT => ErrorCode::NOSUPPORT,
481                                _ => ErrorCode::FAIL,
482                            }),
483                            unhashed_key,
484                            ret_buf,
485                        );
486                    });
487                });
488            }
489            _ => {}
490        });
491    }
492
493    fn invalidate_key_complete(&self, result: Result<(), ErrorCode>, key: &'static mut T) {
494        self.hashed_key.replace(key);
495
496        self.operation.map(|op| match op {
497            Operation::Get | Operation::Add => {}
498            Operation::Set => {
499                // Now that we have deleted the existing key-value we can store
500                // our new key and value.
501                match result {
502                    Ok(()) => {
503                        self.hashed_key.take().map(|hashed_key| {
504                            self.value.take().map(|value| {
505                                match self.kv.append_key(hashed_key, value) {
506                                    Ok(()) => {}
507                                    Err((key, value, e)) => {
508                                        self.hashed_key.replace(key);
509                                        self.operation.clear();
510                                        self.unhashed_key.take().map(|unhashed_key| {
511                                            self.client.map(move |cb| {
512                                                cb.set_complete(Err(e), unhashed_key, value);
513                                            });
514                                        });
515                                    }
516                                }
517                            });
518                        });
519                    }
520                    _ => {
521                        // Some error with delete, signal error.
522                        self.operation.clear();
523                        self.unhashed_key.take().map(|unhashed_key| {
524                            self.value.take().map(|value| {
525                                self.client.map(move |cb| {
526                                    cb.set_complete(Err(ErrorCode::FAIL), unhashed_key, value);
527                                });
528                            });
529                        });
530                    }
531                }
532            }
533            Operation::Update => {
534                // Now that we have deleted the existing key-value we can store
535                // our new key and value.
536                match result {
537                    Ok(()) => {
538                        self.hashed_key.take().map(|hashed_key| {
539                            self.value.take().map(|value| {
540                                match self.kv.append_key(hashed_key, value) {
541                                    Ok(()) => {}
542                                    Err((key, value, _e)) => {
543                                        self.hashed_key.replace(key);
544                                        self.operation.clear();
545                                        self.unhashed_key.take().map(|unhashed_key| {
546                                            self.client.map(move |cb| {
547                                                cb.update_complete(
548                                                    Err(ErrorCode::FAIL),
549                                                    unhashed_key,
550                                                    value,
551                                                );
552                                            });
553                                        });
554                                    }
555                                }
556                            });
557                        });
558                    }
559                    _ => {
560                        // Could not remove which means we can not update.
561                        self.operation.clear();
562                        self.unhashed_key.take().map(|unhashed_key| {
563                            self.value.take().map(|value| {
564                                self.client.map(move |cb| {
565                                    cb.update_complete(
566                                        Err(ErrorCode::NOSUPPORT),
567                                        unhashed_key,
568                                        value,
569                                    );
570                                });
571                            });
572                        });
573                    }
574                }
575            }
576            Operation::Delete => {
577                self.operation.clear();
578                self.unhashed_key.take().map(|unhashed_key| {
579                    self.client.map(move |cb| {
580                        cb.delete_complete(result, unhashed_key);
581                    });
582                });
583            }
584            Operation::GarbageCollect => {}
585        });
586    }
587
588    fn garbage_collect_complete(&self, result: Result<(), ErrorCode>) {
589        self.operation.clear();
590        self.client.map(move |cb| {
591            cb.garbage_collection_complete(result);
592        });
593    }
594}