capsules_extra/
tickv.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//! Tock TicKV capsule.
6//!
7//! This capsule implements the TicKV library in Tock. This is done using the
8//! TicKV library (libraries/tickv).
9//!
10//! This capsule interfaces with flash and exposes the Tock `tickv::kv_system`
11//! interface to others.
12//!
13//! ```text
14//! +-----------------------+
15//! |  Capsule using K-V    |
16//! +-----------------------+
17//!
18//!    hil::kv::KV
19//!
20//! +-----------------------+
21//! |  TickVKVStore         |
22//! +-----------------------+
23//!
24//!    capsules::tickv::KVSystem
25//!
26//! +-----------------------+
27//! |  TicKV (this file)    |
28//! +-----------------------+
29//!       |             |
30//!   hil::flash        |
31//!               +-----------------+
32//!               | libraries/tickv |
33//!               +-----------------+
34//! ```
35
36use core::cell::Cell;
37use kernel::hil::flash::{self, Flash};
38use kernel::hil::hasher::{self, Hasher};
39use kernel::utilities::cells::{MapCell, OptionalCell, TakeCell};
40use kernel::utilities::leasable_buffer::{SubSlice, SubSliceMut};
41use kernel::ErrorCode;
42use tickv::AsyncTicKV;
43
44/// The type of keys, this should define the output size of the digest
45/// operations.
46pub trait KeyType: Eq + Copy + Clone + Sized + AsRef<[u8]> + AsMut<[u8]> {}
47
48impl KeyType for [u8; 8] {}
49
50/// Implement this trait and use `set_client()` in order to receive callbacks.
51pub trait KVSystemClient<K: KeyType> {
52    /// This callback is called when the append_key operation completes.
53    ///
54    /// - `result`: Nothing on success, 'ErrorCode' on error
55    /// - `unhashed_key`: The unhashed_key buffer
56    /// - `key_buf`: The key_buf buffer
57    fn generate_key_complete(
58        &self,
59        result: Result<(), ErrorCode>,
60        unhashed_key: SubSliceMut<'static, u8>,
61        key_buf: &'static mut K,
62    );
63
64    /// This callback is called when the append_key operation completes.
65    ///
66    /// - `result`: Nothing on success, 'ErrorCode' on error
67    /// - `key`: The key buffer
68    /// - `value`: The value buffer
69    fn append_key_complete(
70        &self,
71        result: Result<(), ErrorCode>,
72        key: &'static mut K,
73        value: SubSliceMut<'static, u8>,
74    );
75
76    /// This callback is called when the get_value operation completes.
77    ///
78    /// - `result`: Nothing on success, 'ErrorCode' on error
79    /// - `key`: The key buffer
80    /// - `ret_buf`: The ret_buf buffer
81    fn get_value_complete(
82        &self,
83        result: Result<(), ErrorCode>,
84        key: &'static mut K,
85        ret_buf: SubSliceMut<'static, u8>,
86    );
87
88    /// This callback is called when the invalidate_key operation completes.
89    ///
90    /// - `result`: Nothing on success, 'ErrorCode' on error
91    /// - `key`: The key buffer
92    fn invalidate_key_complete(&self, result: Result<(), ErrorCode>, key: &'static mut K);
93
94    /// This callback is called when the garbage_collect operation completes.
95    ///
96    /// - `result`: Nothing on success, 'ErrorCode' on error
97    fn garbage_collect_complete(&self, result: Result<(), ErrorCode>);
98}
99
100pub trait KVSystem<'a> {
101    /// The type of the hashed key. For example `[u8; 8]`.
102    type K: KeyType;
103
104    /// Set the client.
105    fn set_client(&self, client: &'a dyn KVSystemClient<Self::K>);
106
107    /// Generate key.
108    ///
109    /// - `unhashed_key`: A unhashed key that should be hashed.
110    /// - `key_buf`: A buffer to store the hashed key output.
111    ///
112    /// On success returns nothing.
113    /// On error the unhashed_key, key_buf and `Result<(), ErrorCode>` will be returned.
114    fn generate_key(
115        &self,
116        unhashed_key: SubSliceMut<'static, u8>,
117        key_buf: &'static mut Self::K,
118    ) -> Result<(), (SubSliceMut<'static, u8>, &'static mut Self::K, ErrorCode)>;
119
120    /// Appends the key/value pair.
121    ///
122    /// If the key already exists in the store and has not been invalidated then
123    /// the append operation will fail. To update an existing key to a new value
124    /// the key must first be invalidated.
125    ///
126    /// - `key`: A hashed key. This key will be used in future to retrieve or
127    ///   remove the `value`.
128    /// - `value`: A buffer containing the data to be stored to flash.
129    ///
130    /// On success nothing will be returned.
131    /// On error the key, value and a `Result<(), ErrorCode>` will be returned.
132    ///
133    /// The possible `Result<(), ErrorCode>`s are:
134    /// - `BUSY`: An operation is already in progress
135    /// - `INVAL`: An invalid parameter was passed
136    /// - `NODEVICE`: No KV store was setup
137    /// - `NOSUPPORT`: The key could not be added due to a collision.
138    /// - `NOMEM`: The key could not be added due to no more space.
139    fn append_key(
140        &self,
141        key: &'static mut Self::K,
142        value: SubSliceMut<'static, u8>,
143    ) -> Result<(), (&'static mut Self::K, SubSliceMut<'static, u8>, ErrorCode)>;
144
145    /// Retrieves the value from a specified key.
146    ///
147    /// - `key`: A hashed key. This key will be used to retrieve the `value`.
148    /// - `ret_buf`: A buffer to store the value to.
149    ///
150    /// On success nothing will be returned.
151    /// On error the key, ret_buf and a `Result<(), ErrorCode>` will be returned.
152    ///
153    /// The possible `Result<(), ErrorCode>`s are:
154    /// - `BUSY`: An operation is already in progress
155    /// - `INVAL`: An invalid parameter was passed
156    /// - `NODEVICE`: No KV store was setup
157    /// - `ENOSUPPORT`: The key could not be found.
158    /// - `SIZE`: The value is longer than the provided buffer.
159    fn get_value(
160        &self,
161        key: &'static mut Self::K,
162        ret_buf: SubSliceMut<'static, u8>,
163    ) -> Result<(), (&'static mut Self::K, SubSliceMut<'static, u8>, ErrorCode)>;
164
165    /// Invalidates the key in flash storage.
166    ///
167    /// - `key`: A hashed key. This key will be used to remove the `value`.
168    ///
169    /// On success nothing will be returned.
170    /// On error the key and a `Result<(), ErrorCode>` will be returned.
171    ///
172    /// The possible `Result<(), ErrorCode>`s are:
173    /// - `BUSY`: An operation is already in progress
174    /// - `INVAL`: An invalid parameter was passed
175    /// - `NODEVICE`: No KV store was setup
176    /// - `ENOSUPPORT`: The key could not be found.
177    fn invalidate_key(
178        &self,
179        key: &'static mut Self::K,
180    ) -> Result<(), (&'static mut Self::K, ErrorCode)>;
181
182    /// Perform a garbage collection on the KV Store.
183    ///
184    /// For implementations that don't require garbage collecting this should
185    /// return `Err(ErrorCode::ALREADY)`.
186    ///
187    /// On success nothing will be returned.
188    /// On error a `Result<(), ErrorCode>` will be returned.
189    ///
190    /// The possible `ErrorCode`s are:
191    /// - `BUSY`: An operation is already in progress.
192    /// - `ALREADY`: Nothing to be done. Callback will not trigger.
193    /// - `INVAL`: An invalid parameter was passed.
194    /// - `NODEVICE`: No KV store was setup.
195    fn garbage_collect(&self) -> Result<(), ErrorCode>;
196}
197
198#[derive(Clone, Copy, PartialEq, Debug)]
199enum Operation {
200    None,
201    Init,
202    GetKey,
203    AppendKey,
204    InvalidateKey,
205    GarbageCollect,
206}
207
208/// Wrapper object that provides the flash interface TicKV expects using the
209/// Tock flash HIL.
210///
211/// Note, TicKV expects a synchronous flash implementation, but the Tock flash
212/// HIL is asynchronous. To mediate this, this wrapper starts a flash
213/// read/write/erase, but returns without the requested operation having
214/// completed. To signal TicKV that this is what happened, this implementation
215/// returns `NotReady` errors. When the underlying flash operation has completed
216/// the `TicKVSystem` object will get the callback and then notify TicKV that
217/// the requested operation is now ready.
218pub struct TickFSFlashCtrl<'a, F: Flash + 'static> {
219    flash: &'a F,
220    flash_read_buffer: TakeCell<'static, F::Page>,
221    region_offset: usize,
222}
223
224impl<'a, F: Flash> TickFSFlashCtrl<'a, F> {
225    pub fn new(
226        flash: &'a F,
227        flash_read_buffer: &'static mut F::Page,
228        region_offset: usize,
229    ) -> TickFSFlashCtrl<'a, F> {
230        Self {
231            flash,
232            flash_read_buffer: TakeCell::new(flash_read_buffer),
233            region_offset,
234        }
235    }
236}
237
238impl<F: Flash, const PAGE_SIZE: usize> tickv::flash_controller::FlashController<PAGE_SIZE>
239    for TickFSFlashCtrl<'_, F>
240{
241    fn read_region(
242        &self,
243        region_number: usize,
244        _buf: &mut [u8; PAGE_SIZE],
245    ) -> Result<(), tickv::error_codes::ErrorCode> {
246        if self
247            .flash
248            .read_page(
249                self.region_offset + region_number,
250                self.flash_read_buffer.take().unwrap(),
251            )
252            .is_err()
253        {
254            Err(tickv::error_codes::ErrorCode::ReadFail)
255        } else {
256            Err(tickv::error_codes::ErrorCode::ReadNotReady(region_number))
257        }
258    }
259
260    fn write(&self, address: usize, buf: &[u8]) -> Result<(), tickv::error_codes::ErrorCode> {
261        let data_buf = self.flash_read_buffer.take().unwrap();
262
263        for (i, d) in buf.iter().enumerate() {
264            data_buf.as_mut()[i + (address % PAGE_SIZE)] = *d;
265        }
266
267        if self
268            .flash
269            .write_page(self.region_offset + (address / PAGE_SIZE), data_buf)
270            .is_err()
271        {
272            return Err(tickv::error_codes::ErrorCode::WriteFail);
273        }
274
275        Err(tickv::error_codes::ErrorCode::WriteNotReady(address))
276    }
277
278    fn erase_region(&self, region_number: usize) -> Result<(), tickv::error_codes::ErrorCode> {
279        let _ = self.flash.erase_page(self.region_offset + region_number);
280
281        Err(tickv::error_codes::ErrorCode::EraseNotReady(region_number))
282    }
283}
284
285pub type TicKVKeyType = [u8; 8];
286
287/// `TicKVSystem` implements `KVSystem` using the TicKV library.
288pub struct TicKVSystem<'a, F: Flash + 'static, H: Hasher<'a, 8>, const PAGE_SIZE: usize> {
289    /// Underlying asynchronous TicKV implementation.
290    tickv: AsyncTicKV<'a, TickFSFlashCtrl<'a, F>, PAGE_SIZE>,
291    /// Hash engine that converts key strings to 8 byte keys.
292    hasher: &'a H,
293    /// Track our internal asynchronous state machine.
294    operation: Cell<Operation>,
295    /// The operation to run _after_ initialization has completed.
296    next_operation: Cell<Operation>,
297    /// Holder for the key string passed from the caller until the operation
298    /// completes.
299    unhashed_key_buffer: MapCell<SubSliceMut<'static, u8>>,
300    /// Holder for the hashed key used in the given operation.
301    key_buffer: TakeCell<'static, [u8; 8]>,
302    /// Holder for a buffer containing a value being read from or written to the
303    /// key-value store.
304    value_buffer: MapCell<SubSliceMut<'static, u8>>,
305    /// Callback client when the `KVSystem` operation completes.
306    client: OptionalCell<&'a dyn KVSystemClient<TicKVKeyType>>,
307}
308
309impl<'a, F: Flash, H: Hasher<'a, 8>, const PAGE_SIZE: usize> TicKVSystem<'a, F, H, PAGE_SIZE> {
310    pub fn new(
311        flash: &'a F,
312        hasher: &'a H,
313        tickfs_read_buf: &'static mut [u8; PAGE_SIZE],
314        flash_read_buffer: &'static mut F::Page,
315        region_offset: usize,
316        flash_size: usize,
317    ) -> TicKVSystem<'a, F, H, PAGE_SIZE> {
318        let tickv = AsyncTicKV::<TickFSFlashCtrl<F>, PAGE_SIZE>::new(
319            TickFSFlashCtrl::new(flash, flash_read_buffer, region_offset),
320            tickfs_read_buf,
321            flash_size,
322        );
323
324        Self {
325            tickv,
326            hasher,
327            operation: Cell::new(Operation::None),
328            next_operation: Cell::new(Operation::None),
329            unhashed_key_buffer: MapCell::empty(),
330            key_buffer: TakeCell::empty(),
331            value_buffer: MapCell::empty(),
332            client: OptionalCell::empty(),
333        }
334    }
335
336    pub fn initialise(&self) {
337        let _ret = self.tickv.initialise(0x7bc9f7ff4f76f244);
338        self.operation.set(Operation::Init);
339    }
340
341    fn complete_init(&self) {
342        self.operation.set(Operation::None);
343        match self.next_operation.get() {
344            Operation::None | Operation::Init => {}
345            Operation::GetKey => {
346                if let Err((key, value, error)) = self.get_value(
347                    self.key_buffer.take().unwrap(),
348                    self.value_buffer.take().unwrap(),
349                ) {
350                    self.client.map(move |cb| {
351                        cb.get_value_complete(Err(error), key, value);
352                    });
353                }
354            }
355            Operation::AppendKey => {
356                if let Err((key, value, error)) = self.append_key(
357                    self.key_buffer.take().unwrap(),
358                    self.value_buffer.take().unwrap(),
359                ) {
360                    self.client.map(move |cb| {
361                        cb.append_key_complete(Err(error), key, value);
362                    });
363                }
364            }
365            Operation::InvalidateKey => {
366                if let Err((key, error)) = self.invalidate_key(self.key_buffer.take().unwrap()) {
367                    self.client.map(move |cb| {
368                        cb.invalidate_key_complete(Err(error), key);
369                    });
370                }
371            }
372            Operation::GarbageCollect => {
373                if let Err(error) = self.garbage_collect() {
374                    self.client.map(move |cb| {
375                        cb.garbage_collect_complete(Err(error));
376                    });
377                }
378            }
379        }
380        self.next_operation.set(Operation::None);
381    }
382}
383
384impl<'a, F: Flash, H: Hasher<'a, 8>, const PAGE_SIZE: usize> hasher::Client<8>
385    for TicKVSystem<'a, F, H, PAGE_SIZE>
386{
387    fn add_mut_data_done(&self, _result: Result<(), ErrorCode>, data: SubSliceMut<'static, u8>) {
388        self.unhashed_key_buffer.replace(data);
389        self.hasher.run(self.key_buffer.take().unwrap()).unwrap();
390    }
391
392    fn add_data_done(&self, _result: Result<(), ErrorCode>, _data: SubSlice<'static, u8>) {}
393
394    fn hash_done(&self, _result: Result<(), ErrorCode>, digest: &'static mut [u8; 8]) {
395        self.client.map(move |cb| {
396            cb.generate_key_complete(Ok(()), self.unhashed_key_buffer.take().unwrap(), digest);
397        });
398
399        self.hasher.clear_data();
400    }
401}
402
403impl<'a, F: Flash, H: Hasher<'a, 8>, const PAGE_SIZE: usize> flash::Client<F>
404    for TicKVSystem<'a, F, H, PAGE_SIZE>
405{
406    fn read_complete(&self, pagebuffer: &'static mut F::Page, _result: Result<(), flash::Error>) {
407        self.tickv.set_read_buffer(pagebuffer.as_mut());
408        self.tickv
409            .tickv
410            .controller
411            .flash_read_buffer
412            .replace(pagebuffer);
413        let (ret, tickv_buf, tickv_buf_len) = self.tickv.continue_operation();
414
415        // If we got the buffer back from TicKV then store it.
416        tickv_buf.map(|buf| {
417            let mut val_buf = SubSliceMut::new(buf);
418            if tickv_buf_len > 0 {
419                // Length of zero means nothing was inserted into the buffer so
420                // no need to slice it.
421                val_buf.slice(0..tickv_buf_len);
422            }
423            self.value_buffer.replace(val_buf);
424        });
425
426        match self.operation.get() {
427            Operation::Init => match ret {
428                Ok(tickv::success_codes::SuccessCode::Complete)
429                | Ok(tickv::success_codes::SuccessCode::Written) => {
430                    self.complete_init();
431                }
432                _ => {}
433            },
434            Operation::GetKey => {
435                match ret {
436                    Ok(tickv::success_codes::SuccessCode::Complete)
437                    | Ok(tickv::success_codes::SuccessCode::Written) => {
438                        // We successfully got the key-value object and we can
439                        // call the callback with the retrieved value.
440                        self.operation.set(Operation::None);
441                        self.client.map(|cb| {
442                            cb.get_value_complete(
443                                Ok(()),
444                                self.key_buffer.take().unwrap(),
445                                self.value_buffer.take().unwrap(),
446                            );
447                        });
448                    }
449                    Err(tickv::error_codes::ErrorCode::BufferTooSmall(_)) => {
450                        // Notify the upper layer using the `SIZE` error that
451                        // the entire value was not read into the buffer as
452                        // there was not enough room to store the entire value.
453                        // The buffer still contains the portion of the value
454                        // that would fit.
455                        self.operation.set(Operation::None);
456                        self.client.map(|cb| {
457                            cb.get_value_complete(
458                                Err(ErrorCode::SIZE),
459                                self.key_buffer.take().unwrap(),
460                                self.value_buffer.take().unwrap(),
461                            );
462                        });
463                    }
464                    Err(tickv::error_codes::ErrorCode::ReadNotReady(_)) => {
465                        // Need to do another flash read.
466                        //
467                        // `self.operation` will still be `GetKey`, so this will automatically
468                        // be retried by the primary state machine.
469                    }
470                    Err(tickv::error_codes::ErrorCode::EraseNotReady(_)) | Ok(_) => {}
471                    Err(e) => {
472                        let get_tock_err = match e {
473                            tickv::error_codes::ErrorCode::KeyNotFound => ErrorCode::NOSUPPORT,
474                            _ => ErrorCode::FAIL,
475                        };
476                        self.operation.set(Operation::None);
477                        self.client.map(|cb| {
478                            cb.get_value_complete(
479                                Err(get_tock_err),
480                                self.key_buffer.take().unwrap(),
481                                self.value_buffer.take().unwrap(),
482                            );
483                        });
484                    }
485                }
486            }
487            Operation::AppendKey => {
488                match ret {
489                    Ok(tickv::success_codes::SuccessCode::Complete)
490                    | Ok(tickv::success_codes::SuccessCode::Written) => {
491                        // Nothing to do at this point as we need to wait
492                        // for the flash write to complete.
493                        self.operation.set(Operation::None);
494                    }
495                    Ok(tickv::success_codes::SuccessCode::Queued) => {}
496                    Err(tickv::error_codes::ErrorCode::ReadNotReady(_))
497                    | Err(tickv::error_codes::ErrorCode::WriteNotReady(_))
498                    | Err(tickv::error_codes::ErrorCode::EraseNotReady(_)) => {
499                        // Need to do another flash operation.
500                    }
501                    Err(e) => {
502                        self.operation.set(Operation::None);
503
504                        let tock_hil_error = match e {
505                            tickv::error_codes::ErrorCode::KeyAlreadyExists => ErrorCode::NOSUPPORT,
506                            tickv::error_codes::ErrorCode::RegionFull => ErrorCode::NOMEM,
507                            tickv::error_codes::ErrorCode::FlashFull => ErrorCode::NOMEM,
508                            _ => ErrorCode::FAIL,
509                        };
510                        self.client.map(|cb| {
511                            cb.append_key_complete(
512                                Err(tock_hil_error),
513                                self.key_buffer.take().unwrap(),
514                                self.value_buffer.take().unwrap(),
515                            );
516                        });
517                    }
518                }
519            }
520            Operation::InvalidateKey => match ret {
521                Ok(tickv::success_codes::SuccessCode::Complete)
522                | Ok(tickv::success_codes::SuccessCode::Written) => {
523                    // Need to wait for flash write to complete.
524                    self.operation.set(Operation::None);
525                }
526                Ok(tickv::success_codes::SuccessCode::Queued) => {}
527                Err(tickv::error_codes::ErrorCode::ReadNotReady(_))
528                | Err(tickv::error_codes::ErrorCode::WriteNotReady(_))
529                | Err(tickv::error_codes::ErrorCode::EraseNotReady(_)) => {
530                    // Need to do another flash operation.
531                }
532                Err(e) => {
533                    self.operation.set(Operation::None);
534
535                    let tock_hil_error = match e {
536                        tickv::error_codes::ErrorCode::KeyNotFound => ErrorCode::NOSUPPORT,
537                        _ => ErrorCode::FAIL,
538                    };
539                    self.client.map(|cb| {
540                        cb.invalidate_key_complete(
541                            Err(tock_hil_error),
542                            self.key_buffer.take().unwrap(),
543                        );
544                    });
545                }
546            },
547            Operation::GarbageCollect => match ret {
548                Ok(tickv::success_codes::SuccessCode::Complete)
549                | Ok(tickv::success_codes::SuccessCode::Written) => {
550                    self.operation.set(Operation::None);
551                    self.client.map(|cb| {
552                        cb.garbage_collect_complete(Ok(()));
553                    });
554                }
555                _ => {}
556            },
557            _ => unreachable!(),
558        }
559    }
560
561    fn write_complete(&self, pagebuffer: &'static mut F::Page, _result: Result<(), flash::Error>) {
562        self.tickv
563            .tickv
564            .controller
565            .flash_read_buffer
566            .replace(pagebuffer);
567
568        match self.operation.get() {
569            Operation::Init => {
570                self.complete_init();
571            }
572            Operation::AppendKey => {
573                self.operation.set(Operation::None);
574                self.client.map(|cb| {
575                    cb.append_key_complete(
576                        Ok(()),
577                        self.key_buffer.take().unwrap(),
578                        self.value_buffer.take().unwrap(),
579                    );
580                });
581            }
582            Operation::InvalidateKey => {
583                self.operation.set(Operation::None);
584                self.client.map(|cb| {
585                    cb.invalidate_key_complete(Ok(()), self.key_buffer.take().unwrap());
586                });
587            }
588            _ => unreachable!(),
589        }
590    }
591
592    fn erase_complete(&self, _result: Result<(), flash::Error>) {
593        let (ret, tickv_buf, tickv_buf_len) = self.tickv.continue_operation();
594
595        // If we got the buffer back from TicKV then store it.
596        tickv_buf.map(|buf| {
597            let mut val_buf = SubSliceMut::new(buf);
598            if tickv_buf_len > 0 {
599                // Length of zero means nothing was inserted into the buffer so
600                // no need to slice it.
601                val_buf.slice(0..tickv_buf_len);
602            }
603            self.value_buffer.replace(val_buf);
604        });
605
606        match self.operation.get() {
607            Operation::Init => match ret {
608                Ok(tickv::success_codes::SuccessCode::Complete)
609                | Ok(tickv::success_codes::SuccessCode::Written) => {
610                    self.complete_init();
611                }
612                _ => {}
613            },
614            Operation::GarbageCollect => match ret {
615                Ok(tickv::success_codes::SuccessCode::Complete)
616                | Ok(tickv::success_codes::SuccessCode::Written) => {
617                    self.operation.set(Operation::None);
618                    self.client.map(|cb| {
619                        cb.garbage_collect_complete(Ok(()));
620                    });
621                }
622                _ => {}
623            },
624            _ => unreachable!(),
625        }
626    }
627}
628
629impl<'a, F: Flash, H: Hasher<'a, 8>, const PAGE_SIZE: usize> KVSystem<'a>
630    for TicKVSystem<'a, F, H, PAGE_SIZE>
631{
632    type K = TicKVKeyType;
633
634    fn set_client(&self, client: &'a dyn KVSystemClient<Self::K>) {
635        self.client.set(client);
636    }
637
638    fn generate_key(
639        &self,
640        unhashed_key: SubSliceMut<'static, u8>,
641        key: &'static mut Self::K,
642    ) -> Result<(), (SubSliceMut<'static, u8>, &'static mut Self::K, ErrorCode)> {
643        match self.hasher.add_mut_data(unhashed_key) {
644            Ok(_) => {
645                self.key_buffer.replace(key);
646                Ok(())
647            }
648            Err((e, buf)) => Err((buf, key, e)),
649        }
650    }
651
652    fn append_key(
653        &self,
654        key: &'static mut Self::K,
655        value: SubSliceMut<'static, u8>,
656    ) -> Result<(), (&'static mut [u8; 8], SubSliceMut<'static, u8>, ErrorCode)> {
657        match self.operation.get() {
658            Operation::None => {
659                self.operation.set(Operation::AppendKey);
660
661                let length = value.len();
662                match self
663                    .tickv
664                    .append_key(u64::from_be_bytes(*key), value.take(), length)
665                {
666                    Ok(_ret) => {
667                        self.key_buffer.replace(key);
668                        Ok(())
669                    }
670                    Err((buf, e)) => {
671                        let tock_error = match e {
672                            tickv::error_codes::ErrorCode::ObjectTooLarge => ErrorCode::SIZE,
673                            _ => ErrorCode::FAIL,
674                        };
675                        Err((key, SubSliceMut::new(buf), tock_error))
676                    }
677                }
678            }
679            Operation::Init => {
680                // The init process is still occurring.
681                // We can save this request and start it after init
682                self.next_operation.set(Operation::AppendKey);
683                self.key_buffer.replace(key);
684                self.value_buffer.replace(value);
685                Ok(())
686            }
687            _ => {
688                // An operation is already in process.
689                Err((key, value, ErrorCode::BUSY))
690            }
691        }
692    }
693
694    fn get_value(
695        &self,
696        key: &'static mut Self::K,
697        value: SubSliceMut<'static, u8>,
698    ) -> Result<(), (&'static mut [u8; 8], SubSliceMut<'static, u8>, ErrorCode)> {
699        if value.is_sliced() {
700            return Err((key, value, ErrorCode::SIZE));
701        }
702        match self.operation.get() {
703            Operation::None => {
704                self.operation.set(Operation::GetKey);
705
706                match self.tickv.get_key(u64::from_be_bytes(*key), value.take()) {
707                    Ok(_ret) => {
708                        self.key_buffer.replace(key);
709                        Ok(())
710                    }
711                    Err((buf, _e)) => Err((key, SubSliceMut::new(buf), ErrorCode::FAIL)),
712                }
713            }
714            Operation::Init => {
715                // The init process is still occurring.
716                // We can save this request and start it after init
717                self.next_operation.set(Operation::GetKey);
718                self.key_buffer.replace(key);
719                self.value_buffer.replace(value);
720                Ok(())
721            }
722            _ => {
723                // An operation is already in process.
724                Err((key, value, ErrorCode::BUSY))
725            }
726        }
727    }
728
729    fn invalidate_key(
730        &self,
731        key: &'static mut Self::K,
732    ) -> Result<(), (&'static mut Self::K, ErrorCode)> {
733        match self.operation.get() {
734            Operation::None => {
735                self.operation.set(Operation::InvalidateKey);
736
737                match self.tickv.invalidate_key(u64::from_be_bytes(*key)) {
738                    Ok(_ret) => {
739                        self.key_buffer.replace(key);
740                        Ok(())
741                    }
742                    Err(_e) => Err((key, ErrorCode::FAIL)),
743                }
744            }
745            Operation::Init => {
746                // The init process is still occurring.
747                // We can save this request and start it after init.
748                self.next_operation.set(Operation::InvalidateKey);
749                self.key_buffer.replace(key);
750                Ok(())
751            }
752            _ => {
753                // An operation is already in process.
754                Err((key, ErrorCode::BUSY))
755            }
756        }
757    }
758
759    fn garbage_collect(&self) -> Result<(), ErrorCode> {
760        match self.operation.get() {
761            Operation::None => {
762                self.operation.set(Operation::GarbageCollect);
763                self.tickv
764                    .garbage_collect()
765                    .and(Ok(()))
766                    .or(Err(ErrorCode::FAIL))
767            }
768            Operation::Init => {
769                // The init process is still occurring.
770                // We can save this request and start it after init.
771                self.next_operation.set(Operation::GarbageCollect);
772                Ok(())
773            }
774            _ => {
775                // An operation is already in process.
776                Err(ErrorCode::BUSY)
777            }
778        }
779    }
780}