@@ -5,57 +5,127 @@ use bytes::Bytes;
5
5
use std:: time:: Duration ;
6
6
use tracing:: { debug, instrument} ;
7
7
8
+ /// Set `key` to hold the string `value`.
9
+ ///
10
+ /// If `key` already holds a value, it is overwritten, regardless of its type.
11
+ /// Any previous time to live associated with the key is discarded on successful
12
+ /// SET operation.
13
+ ///
14
+ /// # Options
15
+ ///
16
+ /// Currently, the following options are supported:
17
+ ///
18
+ /// * EX `seconds` -- Set the specified expire time, in seconds.
19
+ /// * PX `milliseconds` -- Set the specified expire time, in milliseconds.
8
20
#[ derive( Debug ) ]
9
21
pub struct Set {
10
22
/// the lookup key
11
- pub ( crate ) key : String ,
23
+ key : String ,
12
24
13
25
/// the value to be stored
14
- pub ( crate ) value : Bytes ,
26
+ value : Bytes ,
15
27
16
28
/// When to expire the key
17
- pub ( crate ) expire : Option < Duration > ,
29
+ expire : Option < Duration > ,
18
30
}
19
31
20
32
impl Set {
21
- #[ instrument]
22
- pub ( crate ) fn parse_frames ( parse : & mut Parse ) -> Result < Set , ParseError > {
33
+ /// Create a new `Set` command which sets `key` to `value`.
34
+ ///
35
+ /// If `expire` is `Some`, the value should expire after the specified
36
+ /// duration.
37
+ pub ( crate ) fn new ( key : impl ToString , value : Bytes , expire : Option < Duration > ) -> Set {
38
+ Set {
39
+ key : key. to_string ( ) ,
40
+ value,
41
+ expire,
42
+ }
43
+ }
44
+
45
+ /// Parse a `Set` instance from received data.
46
+ ///
47
+ /// The `Parse` argument provides a cursor like API to read fields from a
48
+ /// received `Frame`. At this point, the data has already been received from
49
+ /// the socket.
50
+ ///
51
+ /// The `SET` string has already been consumed.
52
+ ///
53
+ /// # Returns
54
+ ///
55
+ /// Returns the `Set` value on success. If the frame is malformed, `Err` is
56
+ /// returned.
57
+ ///
58
+ /// # Format
59
+ ///
60
+ /// Expects an array frame containing at least 3 entries.
61
+ ///
62
+ /// ```text
63
+ /// SET key value [EX seconds|PX milliseconds]
64
+ /// ```
65
+ pub ( crate ) fn parse_frames ( parse : & mut Parse ) -> crate :: Result < Set > {
23
66
use ParseError :: EndOfStream ;
24
67
68
+ // Read the key to set. This is a required field
25
69
let key = parse. next_string ( ) ?;
70
+
71
+ // Read the value to set. This is a required field.
26
72
let value = parse. next_bytes ( ) ?;
73
+
74
+ // The expiration is optional. If nothing else follows, then it is
75
+ // `None`.
27
76
let mut expire = None ;
28
77
78
+ // Attempt to parse another string.
29
79
match parse. next_string ( ) {
30
80
Ok ( s) if s == "EX" => {
81
+ // An expiration is specified in seconds. The next value is an
82
+ // integer.
31
83
let secs = parse. next_int ( ) ?;
32
84
expire = Some ( Duration :: from_secs ( secs) ) ;
33
85
}
34
86
Ok ( s) if s == "PX" => {
87
+ // An expiration is specified in milliseconds. The next value is
88
+ // an integer.
35
89
let ms = parse. next_int ( ) ?;
36
90
expire = Some ( Duration :: from_millis ( ms) ) ;
37
91
}
38
- Ok ( _) => unimplemented ! ( ) ,
92
+ // Currently, mini-redis does not support any of the other SET
93
+ // options. An error here results in the connection being
94
+ // terminated. Other connections will continue to operate normally.
95
+ Ok ( _) => return Err ( "currently `SET` only supports the expiration option" . into ( ) ) ,
96
+ // The `EndOfStream` error indicates there is no further data to
97
+ // parse. In this case, it is a normal run time situation and
98
+ // indicates there are no specified `SET` options.
39
99
Err ( EndOfStream ) => { }
40
- Err ( err) => return Err ( err) ,
100
+ // All other errors are bubbled up, resulting in the connection
101
+ // being terminated.
102
+ Err ( err) => return Err ( err. into ( ) ) ,
41
103
}
42
104
43
- debug ! ( ?key, ?value, ?expire) ;
44
-
45
105
Ok ( Set { key, value, expire } )
46
106
}
47
107
48
- #[ instrument( skip( db) ) ]
108
+ /// Apply the `Get` command to the specified `Db` instace.
109
+ ///
110
+ /// The response is written to `dst`. This is called by the server in order
111
+ /// to execute a received command.
112
+ #[ instrument( skip( self , db, dst) ) ]
49
113
pub ( crate ) async fn apply ( self , db : & Db , dst : & mut Connection ) -> crate :: Result < ( ) > {
50
- // Set the value
114
+ // Set the value in the shared database state.
51
115
db. set ( self . key , self . value , self . expire ) ;
52
116
117
+ // Create a success response and write it to `dst`.
53
118
let response = Frame :: Simple ( "OK" . to_string ( ) ) ;
54
119
debug ! ( ?response) ;
55
120
dst. write_frame ( & response) . await ?;
121
+
56
122
Ok ( ( ) )
57
123
}
58
124
125
+ /// Converts the command into an equivalent `Frame`.
126
+ ///
127
+ /// This is called by the client when encoding a `Set` command to send to
128
+ /// the server.
59
129
pub ( crate ) fn into_frame ( self ) -> Frame {
60
130
let mut frame = Frame :: array ( ) ;
61
131
frame. push_bulk ( Bytes :: from ( "set" . as_bytes ( ) ) ) ;
0 commit comments