summaryrefslogtreecommitdiff
path: root/client-libraries/cpp/redisclient.h
blob: b1fbb582fb1a76cdcfbdec4a19a0e40e2c3b55a9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
/* redisclient.h -- a C++ client library for redis.
 *
 * Copyright (c) 2009, Brian Hammond <brian at fictorial dot com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   * Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *   * Neither the name of Redis nor the names of its contributors may be used
 *     to endorse or promote products derived from this software without
 *     specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef REDISCLIENT_H
#define REDISCLIENT_H

#include <string>
#include <vector>
#include <set>
#include <stdexcept>
#include <ctime>

namespace redis 
{
  struct server_info 
  {
    std::string version;
    bool bgsave_in_progress;
    unsigned long connected_clients;
    unsigned long connected_slaves;
    unsigned long used_memory;
    unsigned long changes_since_last_save;
    unsigned long last_save_time;
    unsigned long total_connections_received;
    unsigned long total_commands_processed;
    unsigned long uptime_in_seconds;
    unsigned long uptime_in_days;
  };

  // Generic error that is thrown when communicating with the redis server.

  class redis_error 
  {
  public:
    redis_error(const std::string & err);
    operator std::string ();
    operator const std::string () const;
  private:
    std::string err_;
  };

  // Some socket-level I/O or general connection error.

  class connection_error : public redis_error
  {
  public:
    connection_error(const std::string & err);
  };

  // Redis gave us a reply we were not expecting.
  // Possibly an internal error (here or in redis, probably here).

  class protocol_error : public redis_error
  {
  public:
    protocol_error(const std::string & err);
  };

  // A key that you expected to exist does not in fact exist.

  class key_error : public redis_error
  {
  public:
    key_error(const std::string & err);
  };

  // A value of an expected type or other semantics was found to be invalid.

  class value_error : public redis_error
  {
  public:
    value_error(const std::string & err);
  };

  // You should construct a 'client' object per connection to a redis-server.
  //
  // Please read the online redis command reference:
  // http://code.google.com/p/redis/wiki/CommandReference
  //
  // No provisions for customizing the allocator on the string/bulk value type
  // (std::string) are provided.  If needed, you can always change the
  // string_type typedef in your local version.

  class client
  {
  public:
    typedef std::string string_type;
    typedef std::vector<string_type> string_vector;
    typedef std::set<string_type> string_set;

    typedef long int_type;

    explicit client(const string_type & host = "localhost", 
                    unsigned int port = 6379);

    ~client();

    //
    // Connection handling
    // 

    void auth(const string_type & pass);

    //
    // Commands operating on string values
    //
    // Note that empty string values do not denote nonexistent keys but well,
    // empty values!  If a nonexistent key is queried, the value returned will
    // be missing_value, including when string_vector objects are returned.
    //

    static string_type missing_value;

    // set a key to a string value

    void set(const string_type & key, const string_type & value);

    // return the string value of the key

    string_type get(const string_type & key);

    // set a key to a string returning the old value of the key

    string_type getset(const string_type & key, const string_type & value);

    // multi-get, return the strings values of the keys

    void mget(const string_vector & keys, string_vector & out);

    // set a key to a string value if the key does not exist.  returns true if
    // the key was set, else false.  This does not throw since you are ok with
    // this failing if the dst key already exists.

    bool setnx(const string_type & key, const string_type & value);

    // increment the integer value of key
    // returns new value

    int_type incr(const string_type & key);

    // increment the integer value of key by integer
    // returns new value

    int_type incrby(const string_type & key, int_type by);

    // decrement the integer value of key
    // returns new value

    int_type decr(const string_type & key);

    // decrement the integer value of key by integer
    // returns new value

    int_type decrby(const string_type & key, int_type by);

    // test if a key exists

    bool exists(const string_type & key);

    // delete a key
    // throws if doesn't exist

    void del(const string_type & key);

    enum datatype 
    {
      datatype_none,      // key doesn't exist
      datatype_string,
      datatype_list,
      datatype_set
    };

    // return the type of the value stored at key

    datatype type(const string_type & key);

    //
    // Commands operating on the key space
    //

    // find all the keys matching a given pattern
    // returns numbers of keys appended to 'out'

    int_type keys(const string_type & pattern, string_vector & out);

    // return a random key from the key space
    // returns empty string if db is empty

    string_type randomkey();

    // rename the old key in the new one, destroying the new key if 
    // it already exists

    void rename(const string_type & old_name, const string_type & new_name);

    // rename the old key in the new one, if the new key does not already
    // exist.  This does not throw since you are ok with this failing if the
    // new_name key already exists.

    bool renamenx(const string_type & old_name, const string_type & new_name);

    // return the number of keys in the current db

    int_type dbsize();

    // set a time to live in seconds on a key.  
    // fails if there's already a timeout on the key.
    
    // NB: there's currently no generic way to remove a timeout on a key

    void expire(const string_type & key, unsigned int secs);

    //
    // Commands operating on lists
    //

    // Append an element to the tail of the list value at key

    void rpush(const string_type & key, const string_type & value);

    // Append an element to the head of the list value at key

    void lpush(const string_type & key, const string_type & value);

    // Return the length of the list value at key
    // Returns 0 if the list does not exist; see 'exists'

    int_type llen(const string_type & key);

    // Fetch a range of elements from the list at key
    // end can be negative for reverse offsets
    // Returns number of elements appended to 'out'

    int_type lrange(const string_type & key, 
                    int_type start, 
                    int_type end,
                    string_vector & out);

    // Fetches the entire list at key.

    int_type get_list(const string_type & key, string_vector & out)
    {
      return lrange(key, 0, -1, out);
    }

    // Trim the list at key to the specified range of elements

    void ltrim(const string_type & key, int_type start, int_type end);

    // Return the element at index position from the list at key

    string_type lindex(const string_type & key, int_type);

    // set a new value as the element at index position of the list at key

    void lset(const string_type & key, 
              int_type index, 
              const string_type &);

    // If count is zero all the elements are removed. If count is negative
    // elements are removed from tail to head, instead to go from head to tail
    // that is the normal behaviour. So for example LREM with count -2 and
    // hello as value to remove against the list (a,b,c,hello,x,hello,hello)
    // will lave the list (a,b,c,hello,x). Returns the number of removed
    // elements if the operation succeeded. 
    //
    // Note: this will not throw if the number of elements removed != count
    // since you might want to remove at most count elements by don't care if
    // < count elements are removed.  See lrem_exact().

    int_type lrem(const string_type & key, 
                  int_type count, 
                  const string_type & value);

    // An extension of 'lrem' that wants to remove exactly 'count' elements.
    // Throws value_error if 'count' elements are not found & removed from the
    // list at 'key'.

    void lrem_exact(const string_type & key,
                    int_type count,
                    const string_type & value)
    { 
      if (lrem(key, count, value) != count)
        throw value_error("failed to remove exactly N elements from list");
    }

    // Return and remove (atomically) the first element of the list at key

    string_type lpop(const string_type & key);

    // Return and remove (atomically) the last element of the list at key

    string_type rpop(const string_type & key);

    //
    // Commands operating on sets
    //

    // Add the specified member to the set value at key
    // returns true if added, or false if already a member of the set.

    void sadd(const string_type & key, const string_type & value);

    // Remove the specified member from the set value at key
    // returns true if removed or false if value is not a member of the set.

    void srem(const string_type & key, const string_type & value);

    // Move the specified member from one set to another atomically
    // returns true if element was moved, else false (e.g. not found)

    void smove(const string_type & srckey, 
               const string_type & dstkey, 
               const string_type & value);

    // Return the number of elements (the cardinality) of the set at key

    int_type scard(const string_type & key);

    // Test if the specified value is a member of the set at key
    // Returns false if key doesn't exist or value is not a member of the set at key

    bool sismember(const string_type & key, const string_type & value);

    // Return the intersection between the sets stored at key1, key2, ..., keyN

    int_type sinter(const string_vector & keys, string_set & out);

    // Compute the intersection between the sets stored at key1, key2, ..., 
    // keyN, and store the resulting set at dstkey

    void sinterstore(const string_type & dstkey, const string_vector & keys);

    // Return the union between the sets stored at key1, key2, ..., keyN

    int_type sunion(const string_vector & keys, string_set & out);

    // Compute the union between the sets stored at key1, key2, ..., keyN, 
    // and store the resulting set at dstkey

    void sunionstore(const string_type & dstkey, const string_vector & keys);

    // Return all the members of the set value at key

    int_type smembers(const string_type & key, string_set & out);

    //
    // Multiple databases handling commands
    //

    // Select the DB having the specified index

    void select(int_type dbindex);

    // Move the key from the currently selected DB to the DB having as index
    // dbindex.  Throws if key was already in the db at dbindex or not found in
    // currently selected db.

    void move(const string_type & key, int_type dbindex);

    // Remove all the keys of the currently selected DB

    void flushdb();

    // Remove all the keys from all the databases

    void flushall();

    //
    // Sorting
    // Just go read http://code.google.com/p/redis/wiki/SortCommand
    //

    enum sort_order
    {
      sort_order_ascending,
      sort_order_descending
    };

    int_type sort(const string_type & key, 
                  string_vector & out,
                  sort_order order = sort_order_ascending,
                  bool lexicographically = false);

    int_type sort(const string_type & key, 
                  string_vector & out,
                  int_type limit_start, 
                  int_type limit_end, 
                  sort_order order = sort_order_ascending,
                  bool lexicographically = false);

    int_type sort(const string_type & key, 
                  string_vector & out,
                  const string_type & by_pattern, 
                  int_type limit_start, 
                  int_type limit_end, 
                  const string_type & get_pattern, 
                  sort_order order = sort_order_ascending,
                  bool lexicographically = false);

    //
    // Persistence control commands
    //

    // Synchronously save the DB on disk

    void save();

    // Asynchronously save the DB on disk

    void bgsave();

    // Return the UNIX time stamp of the last successfully saving of the 
    // dataset on disk

    time_t lastsave();

    // Synchronously save the DB on disk, then shutdown the server.  This
    // object's connection to the server will be lost on success.  Otherwise,
    // redis_error is raised.  Thus, on success, you should delete or otherwise
    // no longer use the object.

    void shutdown();

    //
    // Remote server control commands
    //

    // Provide information and statistics about the server

    void info(server_info & out);

  private:
    client(const client &);
    client & operator=(const client &);

    void        send_(const std::string &);
    void        recv_ok_reply_();
    void        recv_int_ok_reply_();
    std::string recv_single_line_reply_();
    int_type    recv_bulk_reply_(char prefix);
    std::string recv_bulk_reply_();
    int_type    recv_multi_bulk_reply_(string_vector & out);
    int_type    recv_multi_bulk_reply_(string_set & out);
    int_type    recv_int_reply_();

  private:
    int socket_;
  };
}

#endif