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                match self.get_value(
347                    self.key_buffer.take().unwrap(),
348                    self.value_buffer.take().unwrap(),
349                ) {
350                    Err((key, value, error)) => {
351                        self.client.map(move |cb| {
352                            cb.get_value_complete(Err(error), key, value);
353                        });
354                    }
355                    _ => {}
356                }
357            }
358            Operation::AppendKey => {
359                match self.append_key(
360                    self.key_buffer.take().unwrap(),
361                    self.value_buffer.take().unwrap(),
362                ) {
363                    Err((key, value, error)) => {
364                        self.client.map(move |cb| {
365                            cb.append_key_complete(Err(error), key, value);
366                        });
367                    }
368                    _ => {}
369                }
370            }
371            Operation::InvalidateKey => {
372                match self.invalidate_key(self.key_buffer.take().unwrap()) {
373                    Err((key, error)) => {
374                        self.client.map(move |cb| {
375                            cb.invalidate_key_complete(Err(error), key);
376                        });
377                    }
378                    _ => {}
379                }
380            }
381            Operation::GarbageCollect => match self.garbage_collect() {
382                Err(error) => {
383                    self.client.map(move |cb| {
384                        cb.garbage_collect_complete(Err(error));
385                    });
386                }
387                _ => {}
388            },
389        }
390        self.next_operation.set(Operation::None);
391    }
392}
393
394impl<'a, F: Flash, H: Hasher<'a, 8>, const PAGE_SIZE: usize> hasher::Client<8>
395    for TicKVSystem<'a, F, H, PAGE_SIZE>
396{
397    fn add_mut_data_done(&self, _result: Result<(), ErrorCode>, data: SubSliceMut<'static, u8>) {
398        self.unhashed_key_buffer.replace(data);
399        self.hasher.run(self.key_buffer.take().unwrap()).unwrap();
400    }
401
402    fn add_data_done(&self, _result: Result<(), ErrorCode>, _data: SubSlice<'static, u8>) {}
403
404    fn hash_done(&self, _result: Result<(), ErrorCode>, digest: &'static mut [u8; 8]) {
405        self.client.map(move |cb| {
406            cb.generate_key_complete(Ok(()), self.unhashed_key_buffer.take().unwrap(), digest);
407        });
408
409        self.hasher.clear_data();
410    }
411}
412
413impl<'a, F: Flash, H: Hasher<'a, 8>, const PAGE_SIZE: usize> flash::Client<F>
414    for TicKVSystem<'a, F, H, PAGE_SIZE>
415{
416    fn read_complete(&self, pagebuffer: &'static mut F::Page, _result: Result<(), flash::Error>) {
417        self.tickv.set_read_buffer(pagebuffer.as_mut());
418        self.tickv
419            .tickv
420            .controller
421            .flash_read_buffer
422            .replace(pagebuffer);
423        let (ret, tickv_buf, tickv_buf_len) = self.tickv.continue_operation();
424
425        // If we got the buffer back from TicKV then store it.
426        tickv_buf.map(|buf| {
427            let mut val_buf = SubSliceMut::new(buf);
428            if tickv_buf_len > 0 {
429                // Length of zero means nothing was inserted into the buffer so
430                // no need to slice it.
431                val_buf.slice(0..tickv_buf_len);
432            }
433            self.value_buffer.replace(val_buf);
434        });
435
436        match self.operation.get() {
437            Operation::Init => match ret {
438                Ok(tickv::success_codes::SuccessCode::Complete)
439                | Ok(tickv::success_codes::SuccessCode::Written) => {
440                    self.complete_init();
441                }
442                _ => {}
443            },
444            Operation::GetKey => {
445                match ret {
446                    Ok(tickv::success_codes::SuccessCode::Complete)
447                    | Ok(tickv::success_codes::SuccessCode::Written) => {
448                        // We successfully got the key-value object and we can
449                        // call the callback with the retrieved value.
450                        self.operation.set(Operation::None);
451                        self.client.map(|cb| {
452                            cb.get_value_complete(
453                                Ok(()),
454                                self.key_buffer.take().unwrap(),
455                                self.value_buffer.take().unwrap(),
456                            );
457                        });
458                    }
459                    Err(tickv::error_codes::ErrorCode::BufferTooSmall(_)) => {
460                        // Notify the upper layer using the `SIZE` error that
461                        // the entire value was not read into the buffer as
462                        // there was not enough room to store the entire value.
463                        // The buffer still contains the portion of the value
464                        // that would fit.
465                        self.operation.set(Operation::None);
466                        self.client.map(|cb| {
467                            cb.get_value_complete(
468                                Err(ErrorCode::SIZE),
469                                self.key_buffer.take().unwrap(),
470                                self.value_buffer.take().unwrap(),
471                            );
472                        });
473                    }
474                    Err(tickv::error_codes::ErrorCode::ReadNotReady(_)) => {
475                        // Need to do another flash read.
476                        //
477                        // `self.operation` will still be `GetKey`, so this will automatically
478                        // be retried by the primary state machine.
479                    }
480                    Err(tickv::error_codes::ErrorCode::EraseNotReady(_)) | Ok(_) => {}
481                    Err(e) => {
482                        let get_tock_err = match e {
483                            tickv::error_codes::ErrorCode::KeyNotFound => ErrorCode::NOSUPPORT,
484                            _ => ErrorCode::FAIL,
485                        };
486                        self.operation.set(Operation::None);
487                        self.client.map(|cb| {
488                            cb.get_value_complete(
489                                Err(get_tock_err),
490                                self.key_buffer.take().unwrap(),
491                                self.value_buffer.take().unwrap(),
492                            );
493                        });
494                    }
495                }
496            }
497            Operation::AppendKey => {
498                match ret {
499                    Ok(tickv::success_codes::SuccessCode::Complete)
500                    | Ok(tickv::success_codes::SuccessCode::Written) => {
501                        // Nothing to do at this point as we need to wait
502                        // for the flash write to complete.
503                        self.operation.set(Operation::None);
504                    }
505                    Ok(tickv::success_codes::SuccessCode::Queued) => {}
506                    Err(tickv::error_codes::ErrorCode::ReadNotReady(_))
507                    | Err(tickv::error_codes::ErrorCode::WriteNotReady(_))
508                    | Err(tickv::error_codes::ErrorCode::EraseNotReady(_)) => {
509                        // Need to do another flash operation.
510                    }
511                    Err(e) => {
512                        self.operation.set(Operation::None);
513
514                        let tock_hil_error = match e {
515                            tickv::error_codes::ErrorCode::KeyAlreadyExists => ErrorCode::NOSUPPORT,
516                            tickv::error_codes::ErrorCode::RegionFull => ErrorCode::NOMEM,
517                            tickv::error_codes::ErrorCode::FlashFull => ErrorCode::NOMEM,
518                            _ => ErrorCode::FAIL,
519                        };
520                        self.client.map(|cb| {
521                            cb.append_key_complete(
522                                Err(tock_hil_error),
523                                self.key_buffer.take().unwrap(),
524                                self.value_buffer.take().unwrap(),
525                            );
526                        });
527                    }
528                }
529            }
530            Operation::InvalidateKey => match ret {
531                Ok(tickv::success_codes::SuccessCode::Complete)
532                | Ok(tickv::success_codes::SuccessCode::Written) => {
533                    // Need to wait for flash write to complete.
534                    self.operation.set(Operation::None);
535                }
536                Ok(tickv::success_codes::SuccessCode::Queued) => {}
537                Err(tickv::error_codes::ErrorCode::ReadNotReady(_))
538                | Err(tickv::error_codes::ErrorCode::WriteNotReady(_))
539                | Err(tickv::error_codes::ErrorCode::EraseNotReady(_)) => {
540                    // Need to do another flash operation.
541                }
542                Err(e) => {
543                    self.operation.set(Operation::None);
544
545                    let tock_hil_error = match e {
546                        tickv::error_codes::ErrorCode::KeyNotFound => ErrorCode::NOSUPPORT,
547                        _ => ErrorCode::FAIL,
548                    };
549                    self.client.map(|cb| {
550                        cb.invalidate_key_complete(
551                            Err(tock_hil_error),
552                            self.key_buffer.take().unwrap(),
553                        );
554                    });
555                }
556            },
557            Operation::GarbageCollect => match ret {
558                Ok(tickv::success_codes::SuccessCode::Complete)
559                | Ok(tickv::success_codes::SuccessCode::Written) => {
560                    self.operation.set(Operation::None);
561                    self.client.map(|cb| {
562                        cb.garbage_collect_complete(Ok(()));
563                    });
564                }
565                _ => {}
566            },
567            _ => unreachable!(),
568        }
569    }
570
571    fn write_complete(&self, pagebuffer: &'static mut F::Page, _result: Result<(), flash::Error>) {
572        self.tickv
573            .tickv
574            .controller
575            .flash_read_buffer
576            .replace(pagebuffer);
577
578        match self.operation.get() {
579            Operation::Init => {
580                self.complete_init();
581            }
582            Operation::AppendKey => {
583                self.operation.set(Operation::None);
584                self.client.map(|cb| {
585                    cb.append_key_complete(
586                        Ok(()),
587                        self.key_buffer.take().unwrap(),
588                        self.value_buffer.take().unwrap(),
589                    );
590                });
591            }
592            Operation::InvalidateKey => {
593                self.operation.set(Operation::None);
594                self.client.map(|cb| {
595                    cb.invalidate_key_complete(Ok(()), self.key_buffer.take().unwrap());
596                });
597            }
598            _ => unreachable!(),
599        }
600    }
601
602    fn erase_complete(&self, _result: Result<(), flash::Error>) {
603        let (ret, tickv_buf, tickv_buf_len) = self.tickv.continue_operation();
604
605        // If we got the buffer back from TicKV then store it.
606        tickv_buf.map(|buf| {
607            let mut val_buf = SubSliceMut::new(buf);
608            if tickv_buf_len > 0 {
609                // Length of zero means nothing was inserted into the buffer so
610                // no need to slice it.
611                val_buf.slice(0..tickv_buf_len);
612            }
613            self.value_buffer.replace(val_buf);
614        });
615
616        match self.operation.get() {
617            Operation::Init => match ret {
618                Ok(tickv::success_codes::SuccessCode::Complete)
619                | Ok(tickv::success_codes::SuccessCode::Written) => {
620                    self.complete_init();
621                }
622                _ => {}
623            },
624            Operation::GarbageCollect => match ret {
625                Ok(tickv::success_codes::SuccessCode::Complete)
626                | Ok(tickv::success_codes::SuccessCode::Written) => {
627                    self.operation.set(Operation::None);
628                    self.client.map(|cb| {
629                        cb.garbage_collect_complete(Ok(()));
630                    });
631                }
632                _ => {}
633            },
634            _ => unreachable!(),
635        }
636    }
637}
638
639impl<'a, F: Flash, H: Hasher<'a, 8>, const PAGE_SIZE: usize> KVSystem<'a>
640    for TicKVSystem<'a, F, H, PAGE_SIZE>
641{
642    type K = TicKVKeyType;
643
644    fn set_client(&self, client: &'a dyn KVSystemClient<Self::K>) {
645        self.client.set(client);
646    }
647
648    fn generate_key(
649        &self,
650        unhashed_key: SubSliceMut<'static, u8>,
651        key: &'static mut Self::K,
652    ) -> Result<(), (SubSliceMut<'static, u8>, &'static mut Self::K, ErrorCode)> {
653        match self.hasher.add_mut_data(unhashed_key) {
654            Ok(_) => {
655                self.key_buffer.replace(key);
656                Ok(())
657            }
658            Err((e, buf)) => Err((buf, key, e)),
659        }
660    }
661
662    fn append_key(
663        &self,
664        key: &'static mut Self::K,
665        value: SubSliceMut<'static, u8>,
666    ) -> Result<(), (&'static mut [u8; 8], SubSliceMut<'static, u8>, ErrorCode)> {
667        match self.operation.get() {
668            Operation::None => {
669                self.operation.set(Operation::AppendKey);
670
671                let length = value.len();
672                match self
673                    .tickv
674                    .append_key(u64::from_be_bytes(*key), value.take(), length)
675                {
676                    Ok(_ret) => {
677                        self.key_buffer.replace(key);
678                        Ok(())
679                    }
680                    Err((buf, e)) => {
681                        let tock_error = match e {
682                            tickv::error_codes::ErrorCode::ObjectTooLarge => ErrorCode::SIZE,
683                            _ => ErrorCode::FAIL,
684                        };
685                        Err((key, SubSliceMut::new(buf), tock_error))
686                    }
687                }
688            }
689            Operation::Init => {
690                // The init process is still occurring.
691                // We can save this request and start it after init
692                self.next_operation.set(Operation::AppendKey);
693                self.key_buffer.replace(key);
694                self.value_buffer.replace(value);
695                Ok(())
696            }
697            _ => {
698                // An operation is already in process.
699                Err((key, value, ErrorCode::BUSY))
700            }
701        }
702    }
703
704    fn get_value(
705        &self,
706        key: &'static mut Self::K,
707        value: SubSliceMut<'static, u8>,
708    ) -> Result<(), (&'static mut [u8; 8], SubSliceMut<'static, u8>, ErrorCode)> {
709        if value.is_sliced() {
710            return Err((key, value, ErrorCode::SIZE));
711        }
712        match self.operation.get() {
713            Operation::None => {
714                self.operation.set(Operation::GetKey);
715
716                match self.tickv.get_key(u64::from_be_bytes(*key), value.take()) {
717                    Ok(_ret) => {
718                        self.key_buffer.replace(key);
719                        Ok(())
720                    }
721                    Err((buf, _e)) => Err((key, SubSliceMut::new(buf), ErrorCode::FAIL)),
722                }
723            }
724            Operation::Init => {
725                // The init process is still occurring.
726                // We can save this request and start it after init
727                self.next_operation.set(Operation::GetKey);
728                self.key_buffer.replace(key);
729                self.value_buffer.replace(value);
730                Ok(())
731            }
732            _ => {
733                // An operation is already in process.
734                Err((key, value, ErrorCode::BUSY))
735            }
736        }
737    }
738
739    fn invalidate_key(
740        &self,
741        key: &'static mut Self::K,
742    ) -> Result<(), (&'static mut Self::K, ErrorCode)> {
743        match self.operation.get() {
744            Operation::None => {
745                self.operation.set(Operation::InvalidateKey);
746
747                match self.tickv.invalidate_key(u64::from_be_bytes(*key)) {
748                    Ok(_ret) => {
749                        self.key_buffer.replace(key);
750                        Ok(())
751                    }
752                    Err(_e) => Err((key, ErrorCode::FAIL)),
753                }
754            }
755            Operation::Init => {
756                // The init process is still occurring.
757                // We can save this request and start it after init.
758                self.next_operation.set(Operation::InvalidateKey);
759                self.key_buffer.replace(key);
760                Ok(())
761            }
762            _ => {
763                // An operation is already in process.
764                Err((key, ErrorCode::BUSY))
765            }
766        }
767    }
768
769    fn garbage_collect(&self) -> Result<(), ErrorCode> {
770        match self.operation.get() {
771            Operation::None => {
772                self.operation.set(Operation::GarbageCollect);
773                self.tickv
774                    .garbage_collect()
775                    .and(Ok(()))
776                    .or(Err(ErrorCode::FAIL))
777            }
778            Operation::Init => {
779                // The init process is still occurring.
780                // We can save this request and start it after init.
781                self.next_operation.set(Operation::GarbageCollect);
782                Ok(())
783            }
784            _ => {
785                // An operation is already in process.
786                Err(ErrorCode::BUSY)
787            }
788        }
789    }
790}