/* redisclient.h -- a C++ client library for redis. * * Copyright (c) 2009, Brian Hammond * 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 #include #include #include #include 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_vector; typedef std::set 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