]>
Commit | Line | Data |
---|---|---|
57172ffb | 1 | /* redisclient.h -- a C++ client library for redis. |
2 | * | |
3 | * Copyright (c) 2009, Brian Hammond <brian at fictorial dot com> | |
4 | * All rights reserved. | |
5 | * | |
6 | * Redistribution and use in source and binary forms, with or without | |
7 | * modification, are permitted provided that the following conditions are met: | |
8 | * | |
9 | * * Redistributions of source code must retain the above copyright notice, | |
10 | * this list of conditions and the following disclaimer. | |
11 | * * Redistributions in binary form must reproduce the above copyright | |
12 | * notice, this list of conditions and the following disclaimer in the | |
13 | * documentation and/or other materials provided with the distribution. | |
14 | * * Neither the name of Redis nor the names of its contributors may be used | |
15 | * to endorse or promote products derived from this software without | |
16 | * specific prior written permission. | |
17 | * | |
18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | |
22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
28 | * POSSIBILITY OF SUCH DAMAGE. | |
29 | */ | |
30 | ||
31 | #ifndef REDISCLIENT_H | |
32 | #define REDISCLIENT_H | |
33 | ||
34 | #include <string> | |
35 | #include <vector> | |
36 | #include <set> | |
37 | #include <stdexcept> | |
38 | #include <ctime> | |
39 | ||
40 | namespace redis | |
41 | { | |
111d9959 | 42 | enum server_role |
43 | { | |
44 | role_master, | |
45 | role_slave | |
46 | }; | |
47 | ||
57172ffb | 48 | struct server_info |
49 | { | |
50 | std::string version; | |
51 | bool bgsave_in_progress; | |
52 | unsigned long connected_clients; | |
53 | unsigned long connected_slaves; | |
54 | unsigned long used_memory; | |
55 | unsigned long changes_since_last_save; | |
56 | unsigned long last_save_time; | |
57 | unsigned long total_connections_received; | |
58 | unsigned long total_commands_processed; | |
59 | unsigned long uptime_in_seconds; | |
60 | unsigned long uptime_in_days; | |
111d9959 | 61 | server_role role; |
57172ffb | 62 | }; |
63 | ||
64 | // Generic error that is thrown when communicating with the redis server. | |
65 | ||
66 | class redis_error | |
67 | { | |
68 | public: | |
69 | redis_error(const std::string & err); | |
70 | operator std::string (); | |
71 | operator const std::string () const; | |
72 | private: | |
73 | std::string err_; | |
74 | }; | |
75 | ||
76 | // Some socket-level I/O or general connection error. | |
77 | ||
78 | class connection_error : public redis_error | |
79 | { | |
80 | public: | |
81 | connection_error(const std::string & err); | |
82 | }; | |
83 | ||
84 | // Redis gave us a reply we were not expecting. | |
85 | // Possibly an internal error (here or in redis, probably here). | |
86 | ||
87 | class protocol_error : public redis_error | |
88 | { | |
89 | public: | |
90 | protocol_error(const std::string & err); | |
91 | }; | |
92 | ||
93 | // A key that you expected to exist does not in fact exist. | |
94 | ||
95 | class key_error : public redis_error | |
96 | { | |
97 | public: | |
98 | key_error(const std::string & err); | |
99 | }; | |
100 | ||
101 | // A value of an expected type or other semantics was found to be invalid. | |
102 | ||
103 | class value_error : public redis_error | |
104 | { | |
105 | public: | |
106 | value_error(const std::string & err); | |
107 | }; | |
108 | ||
109 | // You should construct a 'client' object per connection to a redis-server. | |
110 | // | |
111 | // Please read the online redis command reference: | |
112 | // http://code.google.com/p/redis/wiki/CommandReference | |
113 | // | |
114 | // No provisions for customizing the allocator on the string/bulk value type | |
115 | // (std::string) are provided. If needed, you can always change the | |
116 | // string_type typedef in your local version. | |
117 | ||
118 | class client | |
119 | { | |
120 | public: | |
121 | typedef std::string string_type; | |
122 | typedef std::vector<string_type> string_vector; | |
123 | typedef std::set<string_type> string_set; | |
124 | ||
125 | typedef long int_type; | |
126 | ||
127 | explicit client(const string_type & host = "localhost", | |
128 | unsigned int port = 6379); | |
129 | ||
130 | ~client(); | |
131 | ||
132 | // | |
133 | // Connection handling | |
134 | // | |
135 | ||
136 | void auth(const string_type & pass); | |
137 | ||
138 | // | |
139 | // Commands operating on string values | |
140 | // | |
141 | // Note that empty string values do not denote nonexistent keys but well, | |
142 | // empty values! If a nonexistent key is queried, the value returned will | |
143 | // be missing_value, including when string_vector objects are returned. | |
144 | // | |
145 | ||
146 | static string_type missing_value; | |
147 | ||
148 | // set a key to a string value | |
149 | ||
150 | void set(const string_type & key, const string_type & value); | |
151 | ||
152 | // return the string value of the key | |
153 | ||
154 | string_type get(const string_type & key); | |
155 | ||
156 | // set a key to a string returning the old value of the key | |
157 | ||
158 | string_type getset(const string_type & key, const string_type & value); | |
159 | ||
160 | // multi-get, return the strings values of the keys | |
161 | ||
162 | void mget(const string_vector & keys, string_vector & out); | |
163 | ||
164 | // set a key to a string value if the key does not exist. returns true if | |
165 | // the key was set, else false. This does not throw since you are ok with | |
166 | // this failing if the dst key already exists. | |
167 | ||
168 | bool setnx(const string_type & key, const string_type & value); | |
169 | ||
170 | // increment the integer value of key | |
171 | // returns new value | |
172 | ||
173 | int_type incr(const string_type & key); | |
174 | ||
175 | // increment the integer value of key by integer | |
176 | // returns new value | |
177 | ||
178 | int_type incrby(const string_type & key, int_type by); | |
179 | ||
180 | // decrement the integer value of key | |
181 | // returns new value | |
182 | ||
183 | int_type decr(const string_type & key); | |
184 | ||
185 | // decrement the integer value of key by integer | |
186 | // returns new value | |
187 | ||
188 | int_type decrby(const string_type & key, int_type by); | |
189 | ||
190 | // test if a key exists | |
191 | ||
192 | bool exists(const string_type & key); | |
193 | ||
194 | // delete a key | |
195 | // throws if doesn't exist | |
196 | ||
197 | void del(const string_type & key); | |
198 | ||
199 | enum datatype | |
200 | { | |
201 | datatype_none, // key doesn't exist | |
202 | datatype_string, | |
203 | datatype_list, | |
204 | datatype_set | |
205 | }; | |
206 | ||
207 | // return the type of the value stored at key | |
208 | ||
209 | datatype type(const string_type & key); | |
210 | ||
211 | // | |
212 | // Commands operating on the key space | |
213 | // | |
214 | ||
215 | // find all the keys matching a given pattern | |
216 | // returns numbers of keys appended to 'out' | |
217 | ||
218 | int_type keys(const string_type & pattern, string_vector & out); | |
219 | ||
220 | // return a random key from the key space | |
221 | // returns empty string if db is empty | |
222 | ||
223 | string_type randomkey(); | |
224 | ||
225 | // rename the old key in the new one, destroying the new key if | |
226 | // it already exists | |
227 | ||
228 | void rename(const string_type & old_name, const string_type & new_name); | |
229 | ||
230 | // rename the old key in the new one, if the new key does not already | |
231 | // exist. This does not throw since you are ok with this failing if the | |
232 | // new_name key already exists. | |
233 | ||
234 | bool renamenx(const string_type & old_name, const string_type & new_name); | |
235 | ||
236 | // return the number of keys in the current db | |
237 | ||
238 | int_type dbsize(); | |
239 | ||
240 | // set a time to live in seconds on a key. | |
241 | // fails if there's already a timeout on the key. | |
242 | ||
243 | // NB: there's currently no generic way to remove a timeout on a key | |
244 | ||
245 | void expire(const string_type & key, unsigned int secs); | |
246 | ||
247 | // | |
248 | // Commands operating on lists | |
249 | // | |
250 | ||
251 | // Append an element to the tail of the list value at key | |
252 | ||
253 | void rpush(const string_type & key, const string_type & value); | |
254 | ||
255 | // Append an element to the head of the list value at key | |
256 | ||
257 | void lpush(const string_type & key, const string_type & value); | |
258 | ||
259 | // Return the length of the list value at key | |
260 | // Returns 0 if the list does not exist; see 'exists' | |
261 | ||
262 | int_type llen(const string_type & key); | |
263 | ||
264 | // Fetch a range of elements from the list at key | |
265 | // end can be negative for reverse offsets | |
266 | // Returns number of elements appended to 'out' | |
267 | ||
268 | int_type lrange(const string_type & key, | |
269 | int_type start, | |
270 | int_type end, | |
271 | string_vector & out); | |
272 | ||
273 | // Fetches the entire list at key. | |
274 | ||
275 | int_type get_list(const string_type & key, string_vector & out) | |
276 | { | |
277 | return lrange(key, 0, -1, out); | |
278 | } | |
279 | ||
280 | // Trim the list at key to the specified range of elements | |
281 | ||
282 | void ltrim(const string_type & key, int_type start, int_type end); | |
283 | ||
284 | // Return the element at index position from the list at key | |
285 | ||
286 | string_type lindex(const string_type & key, int_type); | |
287 | ||
288 | // set a new value as the element at index position of the list at key | |
289 | ||
290 | void lset(const string_type & key, | |
291 | int_type index, | |
292 | const string_type &); | |
293 | ||
294 | // If count is zero all the elements are removed. If count is negative | |
295 | // elements are removed from tail to head, instead to go from head to tail | |
296 | // that is the normal behaviour. So for example LREM with count -2 and | |
297 | // hello as value to remove against the list (a,b,c,hello,x,hello,hello) | |
298 | // will lave the list (a,b,c,hello,x). Returns the number of removed | |
299 | // elements if the operation succeeded. | |
300 | // | |
301 | // Note: this will not throw if the number of elements removed != count | |
302 | // since you might want to remove at most count elements by don't care if | |
303 | // < count elements are removed. See lrem_exact(). | |
304 | ||
305 | int_type lrem(const string_type & key, | |
306 | int_type count, | |
307 | const string_type & value); | |
308 | ||
309 | // An extension of 'lrem' that wants to remove exactly 'count' elements. | |
310 | // Throws value_error if 'count' elements are not found & removed from the | |
311 | // list at 'key'. | |
312 | ||
313 | void lrem_exact(const string_type & key, | |
314 | int_type count, | |
315 | const string_type & value) | |
316 | { | |
317 | if (lrem(key, count, value) != count) | |
318 | throw value_error("failed to remove exactly N elements from list"); | |
319 | } | |
320 | ||
321 | // Return and remove (atomically) the first element of the list at key | |
322 | ||
323 | string_type lpop(const string_type & key); | |
324 | ||
325 | // Return and remove (atomically) the last element of the list at key | |
326 | ||
327 | string_type rpop(const string_type & key); | |
328 | ||
329 | // | |
330 | // Commands operating on sets | |
331 | // | |
332 | ||
333 | // Add the specified member to the set value at key | |
334 | // returns true if added, or false if already a member of the set. | |
335 | ||
336 | void sadd(const string_type & key, const string_type & value); | |
337 | ||
338 | // Remove the specified member from the set value at key | |
339 | // returns true if removed or false if value is not a member of the set. | |
340 | ||
341 | void srem(const string_type & key, const string_type & value); | |
342 | ||
343 | // Move the specified member from one set to another atomically | |
344 | // returns true if element was moved, else false (e.g. not found) | |
345 | ||
346 | void smove(const string_type & srckey, | |
347 | const string_type & dstkey, | |
348 | const string_type & value); | |
349 | ||
350 | // Return the number of elements (the cardinality) of the set at key | |
351 | ||
352 | int_type scard(const string_type & key); | |
353 | ||
354 | // Test if the specified value is a member of the set at key | |
355 | // Returns false if key doesn't exist or value is not a member of the set at key | |
356 | ||
357 | bool sismember(const string_type & key, const string_type & value); | |
358 | ||
359 | // Return the intersection between the sets stored at key1, key2, ..., keyN | |
360 | ||
361 | int_type sinter(const string_vector & keys, string_set & out); | |
362 | ||
363 | // Compute the intersection between the sets stored at key1, key2, ..., | |
364 | // keyN, and store the resulting set at dstkey | |
111d9959 | 365 | // Returns the number of items in the intersection |
57172ffb | 366 | |
111d9959 | 367 | int_type sinterstore(const string_type & dstkey, const string_vector & keys); |
57172ffb | 368 | |
369 | // Return the union between the sets stored at key1, key2, ..., keyN | |
370 | ||
371 | int_type sunion(const string_vector & keys, string_set & out); | |
372 | ||
373 | // Compute the union between the sets stored at key1, key2, ..., keyN, | |
374 | // and store the resulting set at dstkey | |
111d9959 | 375 | // Returns the number of items in the intersection |
57172ffb | 376 | |
111d9959 | 377 | int_type sunionstore(const string_type & dstkey, const string_vector & keys); |
57172ffb | 378 | |
379 | // Return all the members of the set value at key | |
380 | ||
381 | int_type smembers(const string_type & key, string_set & out); | |
382 | ||
383 | // | |
384 | // Multiple databases handling commands | |
385 | // | |
386 | ||
387 | // Select the DB having the specified index | |
388 | ||
389 | void select(int_type dbindex); | |
390 | ||
391 | // Move the key from the currently selected DB to the DB having as index | |
392 | // dbindex. Throws if key was already in the db at dbindex or not found in | |
393 | // currently selected db. | |
394 | ||
395 | void move(const string_type & key, int_type dbindex); | |
396 | ||
397 | // Remove all the keys of the currently selected DB | |
398 | ||
399 | void flushdb(); | |
400 | ||
401 | // Remove all the keys from all the databases | |
402 | ||
403 | void flushall(); | |
404 | ||
405 | // | |
406 | // Sorting | |
407 | // Just go read http://code.google.com/p/redis/wiki/SortCommand | |
408 | // | |
409 | ||
410 | enum sort_order | |
411 | { | |
412 | sort_order_ascending, | |
413 | sort_order_descending | |
414 | }; | |
415 | ||
416 | int_type sort(const string_type & key, | |
417 | string_vector & out, | |
418 | sort_order order = sort_order_ascending, | |
419 | bool lexicographically = false); | |
420 | ||
421 | int_type sort(const string_type & key, | |
422 | string_vector & out, | |
423 | int_type limit_start, | |
424 | int_type limit_end, | |
425 | sort_order order = sort_order_ascending, | |
426 | bool lexicographically = false); | |
427 | ||
428 | int_type sort(const string_type & key, | |
429 | string_vector & out, | |
430 | const string_type & by_pattern, | |
431 | int_type limit_start, | |
432 | int_type limit_end, | |
d7fc9edb | 433 | const string_vector & get_patterns, |
57172ffb | 434 | sort_order order = sort_order_ascending, |
435 | bool lexicographically = false); | |
436 | ||
437 | // | |
438 | // Persistence control commands | |
439 | // | |
440 | ||
441 | // Synchronously save the DB on disk | |
442 | ||
443 | void save(); | |
444 | ||
445 | // Asynchronously save the DB on disk | |
446 | ||
447 | void bgsave(); | |
448 | ||
449 | // Return the UNIX time stamp of the last successfully saving of the | |
450 | // dataset on disk | |
451 | ||
452 | time_t lastsave(); | |
453 | ||
454 | // Synchronously save the DB on disk, then shutdown the server. This | |
455 | // object's connection to the server will be lost on success. Otherwise, | |
456 | // redis_error is raised. Thus, on success, you should delete or otherwise | |
457 | // no longer use the object. | |
458 | ||
459 | void shutdown(); | |
460 | ||
461 | // | |
462 | // Remote server control commands | |
463 | // | |
464 | ||
465 | // Provide information and statistics about the server | |
466 | ||
467 | void info(server_info & out); | |
468 | ||
469 | private: | |
470 | client(const client &); | |
471 | client & operator=(const client &); | |
472 | ||
473 | void send_(const std::string &); | |
474 | void recv_ok_reply_(); | |
475 | void recv_int_ok_reply_(); | |
476 | std::string recv_single_line_reply_(); | |
477 | int_type recv_bulk_reply_(char prefix); | |
478 | std::string recv_bulk_reply_(); | |
479 | int_type recv_multi_bulk_reply_(string_vector & out); | |
480 | int_type recv_multi_bulk_reply_(string_set & out); | |
481 | int_type recv_int_reply_(); | |
482 | ||
483 | private: | |
484 | int socket_; | |
485 | }; | |
486 | } | |
487 | ||
488 | #endif |