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