Skip to main content

fast_cache/commands/
get.rs

1//! GET command parsing and execution.
2//!
3//! All GET-specific behavior starts here. Transport-specific implementations
4//! live in `get/*.rs` submodules.
5
6mod engine;
7#[cfg(feature = "server")]
8mod fcnp;
9#[cfg(feature = "server")]
10mod server;
11
12use crate::Result;
13use crate::protocol::{FastCommand, Frame};
14#[cfg(feature = "server")]
15use crate::server::commands::{BorrowedCommandContext, DirectCommandContext};
16use crate::storage::{Command, EngineCommandContext, EngineFrameFuture};
17
18use super::DecodedFastCommand;
19use super::parsing::CommandArity;
20
21/// Command spec registered in the command catalogs.
22pub(crate) struct Get;
23pub(crate) static COMMAND: Get = Get;
24
25/// Owned GET payload used when a RESP frame has already been copied out.
26#[derive(Debug, Clone)]
27pub(crate) struct OwnedGet {
28    key: Vec<u8>,
29}
30
31impl OwnedGet {
32    fn new(key: Vec<u8>) -> Self {
33        Self { key }
34    }
35}
36
37impl super::OwnedCommandData for OwnedGet {
38    type Spec = Get;
39
40    fn route_key(&self) -> Option<&[u8]> {
41        Some(&self.key)
42    }
43
44    fn to_borrowed_command(&self) -> super::BorrowedCommandBox<'_> {
45        Box::new(BorrowedGet::new(&self.key))
46    }
47}
48
49/// Borrowed GET payload used on zero-copy request paths.
50#[derive(Debug, Clone, Copy)]
51pub(crate) struct BorrowedGet<'a> {
52    key: &'a [u8],
53}
54
55impl<'a> BorrowedGet<'a> {
56    fn new(key: &'a [u8]) -> Self {
57        Self { key }
58    }
59}
60
61impl<'a> super::BorrowedCommandData<'a> for BorrowedGet<'a> {
62    type Spec = Get;
63
64    fn route_key(&self) -> Option<&'a [u8]> {
65        Some(self.key)
66    }
67
68    fn to_owned_command(&self) -> Command {
69        Command::new(Box::new(OwnedGet::new(self.key.to_vec())))
70    }
71
72    fn execute_engine<'b>(&'b self, ctx: EngineCommandContext<'b>) -> EngineFrameFuture<'b>
73    where
74        'a: 'b,
75    {
76        let key = self.key;
77        Box::pin(async move { Get::execute_engine_frame(ctx, key).await })
78    }
79
80    #[cfg(feature = "server")]
81    fn execute_borrowed_frame(&self, store: &crate::storage::EmbeddedStore, _now_ms: u64) -> Frame {
82        match store.get(self.key) {
83            Some(value) => Frame::BlobString(value),
84            None => Frame::Null,
85        }
86    }
87
88    #[cfg(feature = "server")]
89    fn execute_borrowed(&self, mut ctx: BorrowedCommandContext<'_, '_, '_>) {
90        if ctx.single_threaded {
91            Get::execute_borrowed_single_threaded(&mut ctx, self.key);
92        } else {
93            Get::execute_borrowed_shared(&mut ctx, self.key);
94        }
95    }
96
97    #[cfg(feature = "server")]
98    fn execute_direct_borrowed(&self, ctx: DirectCommandContext) -> Frame {
99        ctx.get(self.key).map_or(Frame::Null, Frame::BlobString)
100    }
101}
102
103impl super::CommandSpec for Get {
104    const NAME: &'static str = "GET";
105    const MUTATES_VALUE: bool = false;
106}
107
108impl super::OwnedCommandParse for Get {
109    fn parse_owned(parts: &[Vec<u8>]) -> Result<Command> {
110        CommandArity::<Self>::exact(parts.len(), 2)?;
111        Ok(Command::new(Box::new(OwnedGet::new(parts[1].clone()))))
112    }
113}
114
115impl<'a> super::BorrowedCommandParse<'a> for Get {
116    fn parse_borrowed(parts: &[&'a [u8]]) -> Result<super::BorrowedCommandBox<'a>> {
117        CommandArity::<Self>::exact(parts.len(), 2)?;
118        Ok(Box::new(BorrowedGet::new(parts[1])))
119    }
120}
121
122impl DecodedFastCommand for Get {
123    fn matches_decoded_fast(&self, command: &FastCommand<'_>) -> bool {
124        matches!(command, FastCommand::Get { .. })
125    }
126}