fast_cache/commands/
set.rs1mod engine;
7#[cfg(feature = "server")]
8mod fcnp;
9mod options;
10#[cfg(feature = "server")]
11mod server;
12#[cfg(feature = "server")]
13mod storage;
14
15use crate::Result;
16use crate::protocol::{FastCommand, Frame};
17#[cfg(feature = "server")]
18use crate::server::commands::{BorrowedCommandContext, DirectCommandContext};
19#[cfg(feature = "server")]
20use crate::storage::EmbeddedStore;
21use crate::storage::{Command, EngineCommandContext, EngineFrameFuture, RESP_SPANNED_VALUE_MIN};
22
23use super::DecodedFastCommand;
24use super::parsing::CommandArity;
25use options::StorageSetOptions;
26
27pub(crate) struct Set;
29pub(crate) static COMMAND: Set = Set;
30
31#[derive(Debug, Clone)]
33pub(crate) struct OwnedSet {
34 key: Vec<u8>,
35 value: Vec<u8>,
36 ttl_ms: Option<u64>,
37}
38
39impl OwnedSet {
40 fn new(key: Vec<u8>, value: Vec<u8>, ttl_ms: Option<u64>) -> Self {
41 Self { key, value, ttl_ms }
42 }
43}
44
45impl super::OwnedCommandData for OwnedSet {
46 type Spec = Set;
47
48 fn route_key(&self) -> Option<&[u8]> {
49 Some(&self.key)
50 }
51
52 fn to_borrowed_command(&self) -> super::BorrowedCommandBox<'_> {
53 Box::new(BorrowedSet::new(&self.key, &self.value, self.ttl_ms))
54 }
55}
56
57#[derive(Debug, Clone, Copy)]
59pub(crate) struct BorrowedSet<'a> {
60 key: &'a [u8],
61 value: &'a [u8],
62 ttl_ms: Option<u64>,
63}
64
65impl<'a> BorrowedSet<'a> {
66 fn new(key: &'a [u8], value: &'a [u8], ttl_ms: Option<u64>) -> Self {
67 Self { key, value, ttl_ms }
68 }
69}
70
71impl<'a> super::BorrowedCommandData<'a> for BorrowedSet<'a> {
72 type Spec = Set;
73
74 fn route_key(&self) -> Option<&'a [u8]> {
75 Some(self.key)
76 }
77
78 fn supports_spanned_resp(&self) -> bool {
79 self.value.len() >= RESP_SPANNED_VALUE_MIN
80 }
81
82 fn to_owned_command(&self) -> Command {
83 Command::new(Box::new(OwnedSet::new(
84 self.key.to_vec(),
85 self.value.to_vec(),
86 self.ttl_ms,
87 )))
88 }
89
90 fn execute_engine<'b>(&'b self, ctx: EngineCommandContext<'b>) -> EngineFrameFuture<'b>
91 where
92 'a: 'b,
93 {
94 let key = self.key;
95 let value = self.value;
96 let ttl_ms = self.ttl_ms;
97 Box::pin(async move { Set::execute_engine_frame(ctx, key, value, ttl_ms).await })
98 }
99
100 #[cfg(feature = "server")]
101 fn execute_borrowed_frame(&self, store: &EmbeddedStore, _now_ms: u64) -> Frame {
102 store.set(self.key.to_vec(), self.value.to_vec(), self.ttl_ms);
103 Frame::SimpleString("OK".into())
104 }
105
106 #[cfg(feature = "server")]
107 fn execute_borrowed(&self, ctx: BorrowedCommandContext<'_, '_, '_>) {
108 match ctx.single_threaded && !ctx.store.has_redis_objects() {
109 true => {
110 unsafe {
112 ctx.store
113 .set_single_threaded(self.key, self.value, self.ttl_ms)
114 };
115 }
116 false => {
117 ctx.store
118 .set(self.key.to_vec(), self.value.to_vec(), self.ttl_ms);
119 }
120 }
121 ctx.out.extend_from_slice(b"+OK\r\n");
122 }
123
124 #[cfg(feature = "server")]
125 fn execute_direct_borrowed(&self, ctx: DirectCommandContext) -> Frame {
126 ctx.set_owned(self.key.to_vec(), self.value.to_vec(), self.ttl_ms);
127 Frame::SimpleString("OK".into())
128 }
129}
130
131impl super::CommandSpec for Set {
132 const NAME: &'static str = "SET";
133 const MUTATES_VALUE: bool = true;
134}
135
136impl super::OwnedCommandParse for Set {
137 fn parse_owned(parts: &[Vec<u8>]) -> Result<Command> {
138 CommandArity::<Self>::at_least(parts.len(), 3, "key and value")?;
139 let options = StorageSetOptions::parse(parts[3..].iter().map(Vec::as_slice))?;
140 Ok(Command::new(Box::new(OwnedSet::new(
141 parts[1].clone(),
142 parts[2].clone(),
143 options.ttl_ms,
144 ))))
145 }
146}
147
148impl<'a> super::BorrowedCommandParse<'a> for Set {
149 fn parse_borrowed(parts: &[&'a [u8]]) -> Result<super::BorrowedCommandBox<'a>> {
150 CommandArity::<Self>::at_least(parts.len(), 3, "key and value")?;
151 let options = StorageSetOptions::parse(parts[3..].iter().copied())?;
152 Ok(Box::new(BorrowedSet::new(
153 parts[1],
154 parts[2],
155 options.ttl_ms,
156 )))
157 }
158}
159
160impl DecodedFastCommand for Set {
161 fn matches_decoded_fast(&self, command: &FastCommand<'_>) -> bool {
162 matches!(command, FastCommand::Set { .. })
163 }
164}