diff --git a/lib_acl_cpp/include/acl_cpp/redis/redis_string.hpp b/lib_acl_cpp/include/acl_cpp/redis/redis_string.hpp index f6b94dd08523259f0a9b87bf369888b4739f6b5c..8ab266edc2611ff48d4a1a2e202206a593a482e6 100644 --- a/lib_acl_cpp/include/acl_cpp/redis/redis_string.hpp +++ b/lib_acl_cpp/include/acl_cpp/redis/redis_string.hpp @@ -1,533 +1,563 @@ -#pragma once -#include "../acl_cpp_define.hpp" -#include -#include -#include "redis_command.hpp" - -#if !defined(ACL_CLIENT_ONLY) && !defined(ACL_REDIS_DISABLE) - -namespace acl -{ - -class string; -class redis_client; -class redis_result; - -/** - * 所有的字符串对象的命令都已实现 - * all the commands in redis Strings are be implemented. - */ -class ACL_CPP_API redis_string : virtual public redis_command -{ -public: - /** - * see redis_command::redis_command() - */ - redis_string(void); - - /** - * see redis_command::redis_command(redis_client*) - */ - redis_string(redis_client* conn); - - /** - * see redis_command::redis_command(redis_client_cluster*, size_t) - */ - redis_string(redis_client_cluster* cluster, size_t max_conns = 0); - virtual ~redis_string(void); - - ///////////////////////////////////////////////////////////////////// - - /** - * 将字符串值 value 关联到 key - * set the string value of a key - * @param key {const char*} 字符串对象的 key - * the key of a string - * @param value {const char*} 字符串对象的 value - * the value of a string - * @return {bool} 操作是否成功,返回 false 表示出错或该 key 对象非字符串对象 - * true if SET was executed correctly, false if error happened or - * the key's object isn't a string. - */ - bool set(const char* key, const char* value); - bool set(const char* key, size_t key_len, - const char* value, size_t value_len); - - /** - * 将值 value 关联到 key ,并将 key 的生存时间设为 timeout (以秒为单位), - * 如果 key 已经存在, SETEX 命令将覆写旧值 - * set key to hold the strnig value, and set key to timeout after - * a given number of seconds. - * @param key {const char*} 字符串对象的 key - * the key of a string - * @param value {const char*} 字符串对象的 value - * the value of a string - * @param timeout {int} 过期值,单位为秒 - * the timeout in seconds of a string - * @return {bool} 操作是否成功,返回 false 表示出错或该 key 对象非字符串对象 - * true if SETEX was executed correctly, false if error happened - * or the object specified by the key is not a string - */ - bool setex(const char* key, const char* value, int timeout); - bool setex(const char* key, size_t key_len, const char* value, - size_t value_len, int timeout); - - /** - * 将值 value 关联到 key ,并将 key 的生存时间设为 timeout (以毫秒为单位), - * 如果 key 已经存在, SETEX 命令将覆写旧值 - * set key to hold the string value, and set key to timeout after - * a given number of milliseconds. - * @param key {const char*} 字符串对象的 key - * the key of a string - * @param value {const char*} 字符串对象的 value - * the value of a string - * @param timeout {int} 过期值,单位为毫秒 - * the timeout in milliseconds of a string - * @return {bool} 操作是否成功,返回 false 表示出错或该 key 对象非字符串对象 - * true if SETEX was executed correctly, false if error happened - * or the object specified by the key is not a string - */ - bool psetex(const char* key, const char* value, int timeout); - bool psetex(const char* key, size_t key_len, const char* value, - size_t value_len, int timeout); - - /** - * 将 key 的值设为 value ,当且仅当 key 不存在,若给定的 key 已经存在, - * 则 SETNX 不做任何动作 - * set the value of a key, only if the key does not exist. - * @param key {const char*} 字符串对象的 key - * the key of the string - * @param value {const char*} 字符串对象的 value - * the value of the string - * @return {int} 返回值含义如下: - * return the value as below: - * -1:出错或 key 非字符串对象 - * error happened or the object by the key isn't a string - * 0:给定 key 的对象存在 - * the string of the key already exists - * 1:添加成功 - * the command was executed correctly - */ - int setnx(const char* key, const char* value); - int setnx(const char* key, size_t key_len, - const char* value, size_t value_len); - - /** - * 如果 key 已经存在并且是一个字符串, APPEND 命令将 value 追加到 key 原来 - * 的值的末尾;如果 key 不存在, APPEND 就简单地将给定 key 设为 value - * append a value to a key - * @param key {const char*} 字符串对象的 key - * the key of a string - * @param value {const char*} 字符串对象的值 - * the value to be appended to a key - * @return {int} 返回当前该字符串的长度,-1 表示出错或 key 非字符串对象 - * return the length of the string after appending, -1 if error - * happened or the key's object isn't a string - */ - int append(const char* key, const char* value); - int append(const char* key, const char* value, size_t size); - - /** - * 返回 key 所关联的字符串值 - * get the value of a key - * @param key {const char*} 字符串对象的 key - * the key of a string - * @param buf {string&} 操作成功后存储字符串对象的值,如果返回 true 且 - * 该缓冲区为空则表示对应 key 不存在 - * store the value of a key after GET executed correctly, key not - * exist if the buf is empty when return true - * @return {bool} 操作是否成功,返回 false 表示出错或 key 非字符串对象 - * if the GET was executed correctly, false if error happened or - * is is not a string of the key - */ - bool get(const char* key, size_t len, string& buf); - bool get(const char* key, string& buf); - - /** - * 返回 key 所关联的字符串值,当返回的字符串值比较大时,内部会自动进行切片,即将 - * 一个大内存切成一些非连续的小内存,使用者需要根据返回的结果对象重新对结果数据进行 - * 组装,比如可以调用: redis_result::get(size_t, size_t*) 函数获得某个切 - * 片的片断数据,根据 redis_result::get_size() 获得分片数组的长度 - * @param key {const char*} 字符串对象的 key - * @return {bool} 操作是否成功,返回 false 表示出错或 key 非字符串对象 - */ - const redis_result* get(const char* key); - const redis_result* get(const char* key, size_t len); - - /** - * 将给定 key 的值设为 value ,并返回 key 的旧值,当 key 存在但不是 - * 字符串类型时,返回一个错误 - * set the string value of a key and and return its old value - * @param key {const char*} 字符串对象的 key - * the key of string - * @param value {const char*} 设定的新的对象的值 - * the new string value of the key - * @param buf {string&} 存储对象的旧的值 - * store the old string value of the key - * @return {bool} 是否成功 - * if GETSET was executed correctly. - */ - bool getset(const char* key, const char* value, string& buf); - bool getset(const char* key, size_t key_len, const char* value, - size_t value_len, string& buf); - - ///////////////////////////////////////////////////////////////////// - - /** - * 获得指定 key 的字符串对象的值的数据长度 - * get the length of value stored in a key - * @param key {const char*} 字符串对象的 key - * the key of the string - * @return {int} 返回值含义如下: - * return value as below: - * -1:出错或非字符串对象 - * error happened or the it isn't a string of the key - * 0:该 key 不存在 - * the key doesn't exist - * >0:该字符串数据的长度 - * the length of the value stored in a key - */ - int get_strlen(const char* key); - int get_strlen(const char* key, size_t key_len); - - /** - * 用 value 参数覆写(overwrite)给定 key 所储存的字符串值,从偏移量 offset 开始, - * 不存在的 key 当作空白字符串处理 - * overwrite part of a string at key starting at the specified offset - * @param key {const char*} 字符串对象的 key - * the key of a string - * @param offset {unsigned} 偏移量起始位置,该值可以大于字符串的数据长度,此时 - * 是间的空洞将由 \0 补充 - * the specified offset of the string - * @param value {const char*} 覆盖的值 - * the value to be set - * @return {int} 当前字符串对象的数据长度 - * the length of the string after SETRANGE - */ - int setrange(const char* key, unsigned offset, const char* value); - int setrange(const char* key, size_t key_len, unsigned offset, - const char* value, size_t value_len); - - /** - * 返回 key 中字符串值的子字符串,字符串的截取范围由 start 和 end 两个偏移量决定 - * (包括 start 和 end 在内) - * get substring of the string stored at a key - * @param key {const char*} 字符串对象的 key - * the key of string - * @param start {int} 起始下标值 - * the starting offset of the string - * @param end {int} 结束下标值 - * the ending offset of the string - * @param buf {string&} 成功时存储结果 - * store the substring result - * @return {bool} 操作是否成功 - * if GETRANGE was executed correctly. - * 注:下标位置可以为负值,表示从字符串尾部向前开始计数,如 -1 表示最后一个元素 - */ - bool getrange(const char* key, int start, int end, string& buf); - bool getrange(const char* key, size_t key_len, - int start, int end, string& buf); - - ///////////////////////////////////////////////////////////////////// - - /** - * 对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit), - * 位的设置或清除取决于 value 参数,可以是 0 也可以是 1 - * set or clear the bit at offset in the string value stored at key - * @param key {const char*} 字符串对象的 key - * the key of the string - * @param offset {unsigned} 指定偏移量的位置 - * the offset at the string value - * @param bit {bool} 为 true 表示设置标志位,否则为取消标志位 - * set bit if true, or clear bit if false at the specified offset - * @return {bool} 操作是否成功 - * if the command was executed correctly - */ - bool setbit_(const char* key, unsigned offset, bool bit); - bool setbit_(const char* key, size_t len, unsigned offset, bool bit); - - /** - * 对 key 所储存的字符串值,获取指定偏移量上的位(bit),当 offset 比字符串值 - * 的长度大,或者 key 不存在时,返回 0 - * get the bit at offset in the string value stored at key - * @param key {const char*} 字符串对象的 key - * the key of the string - * @param offset {unsigned} 指定偏移量的位置 - * the offset in the string value - * @param bit {int&} 成功后存储指定位置的标志位 - * on success it will stored the bit at the specified offset - * @return {bool} 操作是否成功,返回 false 表示出错或该 key 非字符串对象 - * if the GETBIT was executed correctly, false if error happened, - * or the key doesn't store a string object - */ - bool getbit(const char* key, unsigned offset, int& bit); - bool getbit(const char* key, size_t len, unsigned offset, int& bit); - - /** - * 计算给定字符串中,被设置为 1 的比特位的数量,若指定了 start/end,则计数在指定 - * 区间内进行 - * count set bits in a string - * @param key {const char*} 字符串对象的 key - * the key of a string - * @return {int} 标志位为 1 的数量,-1 表示出错或非字符串对象 - * the count of bits been set, -1 if error happened or it's not - * a string - */ - int bitcount(const char* key); - int bitcount(const char* key, size_t len); - int bitcount(const char* key, int start, int end); - int bitcount(const char* key, size_t len, int start, int end); - - /** - * 对一个或多个 key 求逻辑并,并将结果保存到 destkey - * BITOP AND on multiple source keys and save the result to another key - * @param destkey {const char*} 目标字符串对象的 key - * the key storing the result - * @param keys 源字符串对象集合 - * the source keys - * @return {int} 存储在目标 key 中的字符串的长度 - * the size of the string stored in the destination key, that is - * equal to the size of the longest input string - */ - int bitop_and(const char* destkey, const std::vector& keys); - int bitop_and(const char* destkey, const std::vector& keys); - int bitop_and(const char* destkey, const char* key, ...); - int bitop_and(const char* destkey, const char* keys[], size_t size); - - /** - * 对一个或多个 key 求逻辑或,并将结果保存到 destkey - * BITOP OR on multiple source keys and save the result to another key - * @param destkey {const char*} 目标字符串对象的 key - * the destination key - * @param keys 源字符串对象集合 - * the source keys - * @return {int} - * the size of the string stored in the destination key - */ - int bitop_or(const char* destkey, const std::vector& keys); - int bitop_or(const char* destkey, const std::vector& keys); - int bitop_or(const char* destkey, const char* key, ...); - int bitop_or(const char* destkey, const char* keys[], size_t size); - - /** - * 对一个或多个 key 求逻辑异或,并将结果保存到 destkey - * BITOP XOR on multiple source keys and save the result to another key - * @param destkey {const char*} 目标字符串对象的 key - * the destination key - * @param keys 源字符串对象集合 - * the source keys - * @return {int} - * the size of the string stored in the destination key - */ - int bitop_xor(const char* destkey, const std::vector& keys); - int bitop_xor(const char* destkey, const std::vector& keys); - int bitop_xor(const char* destkey, const char* key, ...); - int bitop_xor(const char* destkey, const char* keys[], size_t size); - - ///////////////////////////////////////////////////////////////////// - - /** - * 同时设置一个或多个 key-value 对 - * set multiple key-value pair - * @param objs key-value 对集合 - * the collection of multiple key-value pair - * @return {bool} 操作是否成功 - * if the command was executed correctly - */ - bool mset(const std::map& objs); - bool mset(const std::vector& keys, - const std::vector& values); - bool mset(const char* keys[], const char* values[], size_t argc); - bool mset(const char* keys[], const size_t keys_len[], - const char* values[], const size_t values_len[], size_t argc); - - ///////////////////////////////////////////////////////////////////// - - /** - * 当且仅当所有给定 key 都不存在时同时设置一个或多个 key-value 对 - * set multiple keys to multiple values only if none of the keys exist - * @param objs key-value 对集合 - * the collection of multile key-value pair - * @return {int} 返回值含义如下: - * return value as below: - * -1:出错或非字符串对象 - * error happened or there were a object of not a string. - * 0:添加的 key 集合中至少有一个已经存在 - * none be set because some of the keys already exist - * 1:添加成功 - * add ok. - */ - int msetnx(const std::map& objs); - int msetnx(const std::vector& keys, - const std::vector& values); - int msetnx(const char* keys[], const char* values[], size_t argc); - int msetnx(const char* keys[], const size_t keys_len[], - const char* values[], const size_t values_len[], size_t argc); - - ///////////////////////////////////////////////////////////////////// - - /** - * 返回所有(一个或多个)给定 key 的值,如果给定的 key 里面,有某个 key 不存在, - * 那么这个 key 返回空串添加进结果数组中 - * get the values of the given keys - * @param keys {const std::vector&} 字符串 key 集合 - * the given keys - * @param out {std::vector*} 非空时存储字符串值集合数组, - * 对于不存在的 key 也会存储一个空串对象 - * acl::string array storing the result. if one key not exists, - * a empty string "" will also be stored in the array. - * @return {bool} 操作是否成功,操作成功后可以通过以下任一种方式获得数据: - * if successul, one of below ways can be used to get the result: - * - * 1、在调用方法中传入非空的存储结果对象的地址 - * input the no-NULL result parameter when call hmget, when - * success, the result will store the values of the given fileds - * - * 2、基类方法 get_value 获得指定下标的元素数据 - * call redis_command::result_value with the specified subscript - * - * 3、基类方法 get_child 获得指定下标的元素对象(redis_result),然后再通过 - * redis_result::argv_to_string 方法获得元素数据 - * redis_result::argv_to_string 方法获得元素数据 - * call redis_command::result_child with specified subscript to - * get redis_result object, then call redis_result::argv_to_string - * with above result to get the values of the give fileds - * - * 4、基类方法 get_result 方法取得总结果集对象 redis_result,然后再通过 - * redis_result::get_child 获得一个元素对象,然后再通过方式 2 中指定 - * 的方法获得该元素的数据 - * call redis_command::get_result with the specified subscript to - * get redis_result object, and use redis_result::get_child to - * get one result object, then call redis_result::argv_to_string - * to get the value of one filed. - * - * 5、基类方法 get_children 获得结果元素数组对象,再通过 redis_result 中 - * 的方法 argv_to_string 从每一个元素对象中获得元素数据 - * use redis_command::get_children to get the redis_result array, - * then use redis_result::argv_to_string to get every value of - * the given fileds - */ - bool mget(const std::vector& keys, - std::vector* out = NULL); - bool mget(const std::vector& keys, - std::vector* out = NULL); - - bool mget(std::vector* result, const char* first_key, ...); - bool mget(const char* keys[], size_t argc, - std::vector* out = NULL); - bool mget(const char* keys[], const size_t keys_len[], size_t argc, - std::vector* out = NULL); - - ///////////////////////////////////////////////////////////////////// - - /** - * 将 key 中储存的数字值增一 - * 1)如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作; - * 2)如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误; - * 3)本操作的值限制在 64 位(bit)有符号数字表示之内 - * increment the integer value of a key by one - * 1) if key not exists, the key's value will be set 0 and INCR - * 2) if key's value is not a number an error will be returned - * 3) the number is a 64 signed integer - * @param key {const char*} 字符串对象的 key - * the given key - * @param result {long long int*} 非空时存储操作结果 - * store the result after INCR if it isn't NULL - * @return {bool} 操作是否成功 - * if the INCR was executed correctly - */ - bool incr(const char* key, long long int* result = NULL); - - /** - * 将 key 所储存的值加上增量 increment - * 1)如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCRBY 命令 - * 2)如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误 - * 3)本操作的值限制在 64 位(bit)有符号数字表示之内 - * increment the integer value of a key by a given amount - * 1) if key not exists, the key's value will be set 0 and INCRBY - * 2) if key's value is not a number an error will be returned - * 3) the number is a 64 signed integer - * @param key {const char*} 字符串对象的 key - * the given key - * @param inc {long long int} 增量值 - * the given amount - * @param result {long long int*} 非空时存储操作结果 - * store the result after INCR if it isn't NULL - * @return {bool} 操作是否成功 - * if the INCRBY was executed correctly - */ - bool incrby(const char* key, long long int inc, - long long int* result = NULL); - - /** - * 为 key 中所储存的值加上浮点数增量 - * 1) 如果 key 不存在,那么 INCRBYFLOAT 会先将 key 的值设为 0 ,再执行加法操作 - * 2) 如果命令执行成功,那么 key 的值会被更新为(执行加法之后的)新值,并且新值会 - * 以字符串的形式返回给调用者 - * 3) 计算结果也最多只能表示小数点的后十七位 - * increment the float value of a key by the given amount - * 1) if key not exists, the key's value will be set 0 and INCRBYFLOAT - * 2) if key's value is not a float an error will be returned - * @param key {const char*} 字符串对象的 key - * the given key - * @param inc {double} 增量值 - * the given amount - * @param result {double*} 非空时存储操作结果 - * store the result after INCR if it isn't NULL - * @return {bool} 操作是否成功 - * if the INCRBYFLOAT was executed correctly - */ - bool incrbyfloat(const char* key, double inc, double* result = NULL); - - /** - * 将 key 中储存的数字值减一 - * 1) 如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 DECR 操作 - * 2) 如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误 - * 3) 本操作的值限制在 64 位(bit)有符号数字表示之内 - * decrement the integer value of a key by one - * 1) if key not exists, the key's value will be set 0 and DECR - * 2) if key's value is not a number an error will be returned - * 3) the number is a 64 signed integer - * @param key {const char*} 字符串对象的 key - * the given key - * @param result {long long int*} 非空时存储操作结果 - * store the result after INCR if it isn't NULL - * @return {bool} 操作是否成功 - * if the DECR was executed correctly - */ - bool decr(const char* key, long long int* result = NULL); - - /** - * 将 key 所储存的值减去减量 decrement - * 1) 如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 DECRBY 操作 - * 2) 如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误 - * 3) 本操作的值限制在 64 位(bit)有符号数字表示之内 - * decrement the integer value of a key by the given amount - * @param key {const char*} 字符串对象的 key - * the given key - * @param dec {long long int} 减量值 - * the given amount - * @param result {long long int*} 非空时存储操作结果 - * store the result after INCR if it isn't NULL - * @return {bool} 操作是否成功 - * if the DECRBY was executed correctly - */ - bool decrby(const char* key, long long int dec, - long long int* result = NULL); - -private: - int bitop(const char* op, const char* destkey, - const std::vector& keys); - int bitop(const char* op, const char* destkey, - const std::vector& keys); - int bitop(const char* op, const char* destkey, - const char* keys[], size_t size); - - bool incoper(const char* cmd, const char* key, long long int* inc, - long long int* result); - -}; - -} // namespace acl - -#endif // !defined(ACL_CLIENT_ONLY) && !defined(ACL_REDIS_DISABLE) +#pragma once +#include "../acl_cpp_define.hpp" +#include +#include +#include "redis_command.hpp" + +#if !defined(ACL_CLIENT_ONLY) && !defined(ACL_REDIS_DISABLE) + +namespace acl +{ + +class string; +class redis_client; +class redis_result; + +/** + * 所有的字符串对象的命令都已实现 + * all the commands in redis Strings are be implemented. + */ +class ACL_CPP_API redis_string : virtual public redis_command +{ +public: + /** + * see redis_command::redis_command() + */ + redis_string(void); + + /** + * see redis_command::redis_command(redis_client*) + */ + redis_string(redis_client* conn); + + /** + * see redis_command::redis_command(redis_client_cluster*, size_t) + */ + redis_string(redis_client_cluster* cluster, size_t max_conns = 0); + virtual ~redis_string(void); + + ///////////////////////////////////////////////////////////////////// + + /** + * 将字符串值 value 关联到 key + * set the string value of a key + * @param key {const char*} 字符串对象的 key + * the key of a string + * @param value {const char*} 字符串对象的 value + * the value of a string + * @return {bool} 操作是否成功,返回 false 表示出错或该 key 对象非字符串对象 + * true if SET was executed correctly, false if error happened or + * the key's object isn't a string. + */ + bool set(const char* key, const char* value); + bool set(const char* key, size_t key_len, + const char* value, size_t value_len); + + #define SETFLAG_EX 0x02 + #define SETFLAG_PX 0x03 + #define SETFLAG_NX 0x08 + #define SETFLAG_XX 0x0C + /** + * 从 Redis 2.6.12 版本开始, SET 命令的行为可以通过一系列参数来修改: + * EX seconds : 将键的过期时间设置为 seconds 秒。 执行 SET key value EX seconds 的效果等同于执行 SETEX key seconds value 。 + * PX milliseconds : 将键的过期时间设置为 milliseconds 毫秒。 执行 SET key value PX milliseconds 的效果等同于执行 PSETEX key milliseconds value 。 + * NX : 只在键不存在时, 才对键进行设置操作。 执行 SET key value NX 的效果等同于执行 SETNX key value 。 + * XX : 只在键已经存在时, 才对键进行设置操作。 + * @Note + * 因为 SET 命令可以通过参数来实现 SETNX 、 SETEX 以及 PSETEX 命令的效果, 所以 Redis 将来的版本可能会移除并废弃 SETNX 、 SETEX 和 PSETEX 这三个命令。 + * @param key {const char*} 字符串对象的 key + * the key of a string + * @param value {const char*} 字符串对象的 value + * the value of a string + * @param timeout {int} 过期值,单位为秒(EX)/毫秒(PX) + * the timeout in seconds of a string + * @param flag {int} 标记,EX/PX | NX/XX + * the flag of a string + * @return {bool} 操作是否成功,返回 false 表示出错或该 key 对象非字符串对象 + * true if SET was executed correctly, false if error happened or + * the key's object isn't a string. + */ + bool set(const char* key, const char* value, + int timeout, int flag); + bool set(const char* key, size_t key_len, + const char* value, size_t value_len, + int timeout, int flag); + + /** + * 将值 value 关联到 key ,并将 key 的生存时间设为 timeout (以秒为单位), + * 如果 key 已经存在, SETEX 命令将覆写旧值 + * set key to hold the strnig value, and set key to timeout after + * a given number of seconds. + * @param key {const char*} 字符串对象的 key + * the key of a string + * @param value {const char*} 字符串对象的 value + * the value of a string + * @param timeout {int} 过期值,单位为秒 + * the timeout in seconds of a string + * @return {bool} 操作是否成功,返回 false 表示出错或该 key 对象非字符串对象 + * true if SETEX was executed correctly, false if error happened + * or the object specified by the key is not a string + */ + bool setex(const char* key, const char* value, int timeout); + bool setex(const char* key, size_t key_len, const char* value, + size_t value_len, int timeout); + + /** + * 将值 value 关联到 key ,并将 key 的生存时间设为 timeout (以毫秒为单位), + * 如果 key 已经存在, SETEX 命令将覆写旧值 + * set key to hold the string value, and set key to timeout after + * a given number of milliseconds. + * @param key {const char*} 字符串对象的 key + * the key of a string + * @param value {const char*} 字符串对象的 value + * the value of a string + * @param timeout {int} 过期值,单位为毫秒 + * the timeout in milliseconds of a string + * @return {bool} 操作是否成功,返回 false 表示出错或该 key 对象非字符串对象 + * true if SETEX was executed correctly, false if error happened + * or the object specified by the key is not a string + */ + bool psetex(const char* key, const char* value, int timeout); + bool psetex(const char* key, size_t key_len, const char* value, + size_t value_len, int timeout); + + /** + * 将 key 的值设为 value ,当且仅当 key 不存在,若给定的 key 已经存在, + * 则 SETNX 不做任何动作 + * set the value of a key, only if the key does not exist. + * @param key {const char*} 字符串对象的 key + * the key of the string + * @param value {const char*} 字符串对象的 value + * the value of the string + * @return {int} 返回值含义如下: + * return the value as below: + * -1:出错或 key 非字符串对象 + * error happened or the object by the key isn't a string + * 0:给定 key 的对象存在 + * the string of the key already exists + * 1:添加成功 + * the command was executed correctly + */ + int setnx(const char* key, const char* value); + int setnx(const char* key, size_t key_len, + const char* value, size_t value_len); + + /** + * 如果 key 已经存在并且是一个字符串, APPEND 命令将 value 追加到 key 原来 + * 的值的末尾;如果 key 不存在, APPEND 就简单地将给定 key 设为 value + * append a value to a key + * @param key {const char*} 字符串对象的 key + * the key of a string + * @param value {const char*} 字符串对象的值 + * the value to be appended to a key + * @return {int} 返回当前该字符串的长度,-1 表示出错或 key 非字符串对象 + * return the length of the string after appending, -1 if error + * happened or the key's object isn't a string + */ + int append(const char* key, const char* value); + int append(const char* key, const char* value, size_t size); + + /** + * 返回 key 所关联的字符串值 + * get the value of a key + * @param key {const char*} 字符串对象的 key + * the key of a string + * @param buf {string&} 操作成功后存储字符串对象的值,如果返回 true 且 + * 该缓冲区为空则表示对应 key 不存在 + * store the value of a key after GET executed correctly, key not + * exist if the buf is empty when return true + * @return {bool} 操作是否成功,返回 false 表示出错或 key 非字符串对象 + * if the GET was executed correctly, false if error happened or + * is is not a string of the key + */ + bool get(const char* key, size_t len, string& buf); + bool get(const char* key, string& buf); + + /** + * 返回 key 所关联的字符串值,当返回的字符串值比较大时,内部会自动进行切片,即将 + * 一个大内存切成一些非连续的小内存,使用者需要根据返回的结果对象重新对结果数据进行 + * 组装,比如可以调用: redis_result::get(size_t, size_t*) 函数获得某个切 + * 片的片断数据,根据 redis_result::get_size() 获得分片数组的长度 + * @param key {const char*} 字符串对象的 key + * @return {bool} 操作是否成功,返回 false 表示出错或 key 非字符串对象 + */ + const redis_result* get(const char* key); + const redis_result* get(const char* key, size_t len); + + /** + * 将给定 key 的值设为 value ,并返回 key 的旧值,当 key 存在但不是 + * 字符串类型时,返回一个错误 + * set the string value of a key and and return its old value + * @param key {const char*} 字符串对象的 key + * the key of string + * @param value {const char*} 设定的新的对象的值 + * the new string value of the key + * @param buf {string&} 存储对象的旧的值 + * store the old string value of the key + * @return {bool} 是否成功 + * if GETSET was executed correctly. + */ + bool getset(const char* key, const char* value, string& buf); + bool getset(const char* key, size_t key_len, const char* value, + size_t value_len, string& buf); + + ///////////////////////////////////////////////////////////////////// + + /** + * 获得指定 key 的字符串对象的值的数据长度 + * get the length of value stored in a key + * @param key {const char*} 字符串对象的 key + * the key of the string + * @return {int} 返回值含义如下: + * return value as below: + * -1:出错或非字符串对象 + * error happened or the it isn't a string of the key + * 0:该 key 不存在 + * the key doesn't exist + * >0:该字符串数据的长度 + * the length of the value stored in a key + */ + int get_strlen(const char* key); + int get_strlen(const char* key, size_t key_len); + + /** + * 用 value 参数覆写(overwrite)给定 key 所储存的字符串值,从偏移量 offset 开始, + * 不存在的 key 当作空白字符串处理 + * overwrite part of a string at key starting at the specified offset + * @param key {const char*} 字符串对象的 key + * the key of a string + * @param offset {unsigned} 偏移量起始位置,该值可以大于字符串的数据长度,此时 + * 是间的空洞将由 \0 补充 + * the specified offset of the string + * @param value {const char*} 覆盖的值 + * the value to be set + * @return {int} 当前字符串对象的数据长度 + * the length of the string after SETRANGE + */ + int setrange(const char* key, unsigned offset, const char* value); + int setrange(const char* key, size_t key_len, unsigned offset, + const char* value, size_t value_len); + + /** + * 返回 key 中字符串值的子字符串,字符串的截取范围由 start 和 end 两个偏移量决定 + * (包括 start 和 end 在内) + * get substring of the string stored at a key + * @param key {const char*} 字符串对象的 key + * the key of string + * @param start {int} 起始下标值 + * the starting offset of the string + * @param end {int} 结束下标值 + * the ending offset of the string + * @param buf {string&} 成功时存储结果 + * store the substring result + * @return {bool} 操作是否成功 + * if GETRANGE was executed correctly. + * 注:下标位置可以为负值,表示从字符串尾部向前开始计数,如 -1 表示最后一个元素 + */ + bool getrange(const char* key, int start, int end, string& buf); + bool getrange(const char* key, size_t key_len, + int start, int end, string& buf); + + ///////////////////////////////////////////////////////////////////// + + /** + * 对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit), + * 位的设置或清除取决于 value 参数,可以是 0 也可以是 1 + * set or clear the bit at offset in the string value stored at key + * @param key {const char*} 字符串对象的 key + * the key of the string + * @param offset {unsigned} 指定偏移量的位置 + * the offset at the string value + * @param bit {bool} 为 true 表示设置标志位,否则为取消标志位 + * set bit if true, or clear bit if false at the specified offset + * @return {bool} 操作是否成功 + * if the command was executed correctly + */ + bool setbit_(const char* key, unsigned offset, bool bit); + bool setbit_(const char* key, size_t len, unsigned offset, bool bit); + + /** + * 对 key 所储存的字符串值,获取指定偏移量上的位(bit),当 offset 比字符串值 + * 的长度大,或者 key 不存在时,返回 0 + * get the bit at offset in the string value stored at key + * @param key {const char*} 字符串对象的 key + * the key of the string + * @param offset {unsigned} 指定偏移量的位置 + * the offset in the string value + * @param bit {int&} 成功后存储指定位置的标志位 + * on success it will stored the bit at the specified offset + * @return {bool} 操作是否成功,返回 false 表示出错或该 key 非字符串对象 + * if the GETBIT was executed correctly, false if error happened, + * or the key doesn't store a string object + */ + bool getbit(const char* key, unsigned offset, int& bit); + bool getbit(const char* key, size_t len, unsigned offset, int& bit); + + /** + * 计算给定字符串中,被设置为 1 的比特位的数量,若指定了 start/end,则计数在指定 + * 区间内进行 + * count set bits in a string + * @param key {const char*} 字符串对象的 key + * the key of a string + * @return {int} 标志位为 1 的数量,-1 表示出错或非字符串对象 + * the count of bits been set, -1 if error happened or it's not + * a string + */ + int bitcount(const char* key); + int bitcount(const char* key, size_t len); + int bitcount(const char* key, int start, int end); + int bitcount(const char* key, size_t len, int start, int end); + + /** + * 对一个或多个 key 求逻辑并,并将结果保存到 destkey + * BITOP AND on multiple source keys and save the result to another key + * @param destkey {const char*} 目标字符串对象的 key + * the key storing the result + * @param keys 源字符串对象集合 + * the source keys + * @return {int} 存储在目标 key 中的字符串的长度 + * the size of the string stored in the destination key, that is + * equal to the size of the longest input string + */ + int bitop_and(const char* destkey, const std::vector& keys); + int bitop_and(const char* destkey, const std::vector& keys); + int bitop_and(const char* destkey, const char* key, ...); + int bitop_and(const char* destkey, const char* keys[], size_t size); + + /** + * 对一个或多个 key 求逻辑或,并将结果保存到 destkey + * BITOP OR on multiple source keys and save the result to another key + * @param destkey {const char*} 目标字符串对象的 key + * the destination key + * @param keys 源字符串对象集合 + * the source keys + * @return {int} + * the size of the string stored in the destination key + */ + int bitop_or(const char* destkey, const std::vector& keys); + int bitop_or(const char* destkey, const std::vector& keys); + int bitop_or(const char* destkey, const char* key, ...); + int bitop_or(const char* destkey, const char* keys[], size_t size); + + /** + * 对一个或多个 key 求逻辑异或,并将结果保存到 destkey + * BITOP XOR on multiple source keys and save the result to another key + * @param destkey {const char*} 目标字符串对象的 key + * the destination key + * @param keys 源字符串对象集合 + * the source keys + * @return {int} + * the size of the string stored in the destination key + */ + int bitop_xor(const char* destkey, const std::vector& keys); + int bitop_xor(const char* destkey, const std::vector& keys); + int bitop_xor(const char* destkey, const char* key, ...); + int bitop_xor(const char* destkey, const char* keys[], size_t size); + + ///////////////////////////////////////////////////////////////////// + + /** + * 同时设置一个或多个 key-value 对 + * set multiple key-value pair + * @param objs key-value 对集合 + * the collection of multiple key-value pair + * @return {bool} 操作是否成功 + * if the command was executed correctly + */ + bool mset(const std::map& objs); + bool mset(const std::vector& keys, + const std::vector& values); + bool mset(const char* keys[], const char* values[], size_t argc); + bool mset(const char* keys[], const size_t keys_len[], + const char* values[], const size_t values_len[], size_t argc); + + ///////////////////////////////////////////////////////////////////// + + /** + * 当且仅当所有给定 key 都不存在时同时设置一个或多个 key-value 对 + * set multiple keys to multiple values only if none of the keys exist + * @param objs key-value 对集合 + * the collection of multile key-value pair + * @return {int} 返回值含义如下: + * return value as below: + * -1:出错或非字符串对象 + * error happened or there were a object of not a string. + * 0:添加的 key 集合中至少有一个已经存在 + * none be set because some of the keys already exist + * 1:添加成功 + * add ok. + */ + int msetnx(const std::map& objs); + int msetnx(const std::vector& keys, + const std::vector& values); + int msetnx(const char* keys[], const char* values[], size_t argc); + int msetnx(const char* keys[], const size_t keys_len[], + const char* values[], const size_t values_len[], size_t argc); + + ///////////////////////////////////////////////////////////////////// + + /** + * 返回所有(一个或多个)给定 key 的值,如果给定的 key 里面,有某个 key 不存在, + * 那么这个 key 返回空串添加进结果数组中 + * get the values of the given keys + * @param keys {const std::vector&} 字符串 key 集合 + * the given keys + * @param out {std::vector*} 非空时存储字符串值集合数组, + * 对于不存在的 key 也会存储一个空串对象 + * acl::string array storing the result. if one key not exists, + * a empty string "" will also be stored in the array. + * @return {bool} 操作是否成功,操作成功后可以通过以下任一种方式获得数据: + * if successul, one of below ways can be used to get the result: + * + * 1、在调用方法中传入非空的存储结果对象的地址 + * input the no-NULL result parameter when call hmget, when + * success, the result will store the values of the given fileds + * + * 2、基类方法 get_value 获得指定下标的元素数据 + * call redis_command::result_value with the specified subscript + * + * 3、基类方法 get_child 获得指定下标的元素对象(redis_result),然后再通过 + * redis_result::argv_to_string 方法获得元素数据 + * redis_result::argv_to_string 方法获得元素数据 + * call redis_command::result_child with specified subscript to + * get redis_result object, then call redis_result::argv_to_string + * with above result to get the values of the give fileds + * + * 4、基类方法 get_result 方法取得总结果集对象 redis_result,然后再通过 + * redis_result::get_child 获得一个元素对象,然后再通过方式 2 中指定 + * 的方法获得该元素的数据 + * call redis_command::get_result with the specified subscript to + * get redis_result object, and use redis_result::get_child to + * get one result object, then call redis_result::argv_to_string + * to get the value of one filed. + * + * 5、基类方法 get_children 获得结果元素数组对象,再通过 redis_result 中 + * 的方法 argv_to_string 从每一个元素对象中获得元素数据 + * use redis_command::get_children to get the redis_result array, + * then use redis_result::argv_to_string to get every value of + * the given fileds + */ + bool mget(const std::vector& keys, + std::vector* out = NULL); + bool mget(const std::vector& keys, + std::vector* out = NULL); + + bool mget(std::vector* result, const char* first_key, ...); + bool mget(const char* keys[], size_t argc, + std::vector* out = NULL); + bool mget(const char* keys[], const size_t keys_len[], size_t argc, + std::vector* out = NULL); + + ///////////////////////////////////////////////////////////////////// + + /** + * 将 key 中储存的数字值增一 + * 1)如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作; + * 2)如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误; + * 3)本操作的值限制在 64 位(bit)有符号数字表示之内 + * increment the integer value of a key by one + * 1) if key not exists, the key's value will be set 0 and INCR + * 2) if key's value is not a number an error will be returned + * 3) the number is a 64 signed integer + * @param key {const char*} 字符串对象的 key + * the given key + * @param result {long long int*} 非空时存储操作结果 + * store the result after INCR if it isn't NULL + * @return {bool} 操作是否成功 + * if the INCR was executed correctly + */ + bool incr(const char* key, long long int* result = NULL); + + /** + * 将 key 所储存的值加上增量 increment + * 1)如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCRBY 命令 + * 2)如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误 + * 3)本操作的值限制在 64 位(bit)有符号数字表示之内 + * increment the integer value of a key by a given amount + * 1) if key not exists, the key's value will be set 0 and INCRBY + * 2) if key's value is not a number an error will be returned + * 3) the number is a 64 signed integer + * @param key {const char*} 字符串对象的 key + * the given key + * @param inc {long long int} 增量值 + * the given amount + * @param result {long long int*} 非空时存储操作结果 + * store the result after INCR if it isn't NULL + * @return {bool} 操作是否成功 + * if the INCRBY was executed correctly + */ + bool incrby(const char* key, long long int inc, + long long int* result = NULL); + + /** + * 为 key 中所储存的值加上浮点数增量 + * 1) 如果 key 不存在,那么 INCRBYFLOAT 会先将 key 的值设为 0 ,再执行加法操作 + * 2) 如果命令执行成功,那么 key 的值会被更新为(执行加法之后的)新值,并且新值会 + * 以字符串的形式返回给调用者 + * 3) 计算结果也最多只能表示小数点的后十七位 + * increment the float value of a key by the given amount + * 1) if key not exists, the key's value will be set 0 and INCRBYFLOAT + * 2) if key's value is not a float an error will be returned + * @param key {const char*} 字符串对象的 key + * the given key + * @param inc {double} 增量值 + * the given amount + * @param result {double*} 非空时存储操作结果 + * store the result after INCR if it isn't NULL + * @return {bool} 操作是否成功 + * if the INCRBYFLOAT was executed correctly + */ + bool incrbyfloat(const char* key, double inc, double* result = NULL); + + /** + * 将 key 中储存的数字值减一 + * 1) 如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 DECR 操作 + * 2) 如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误 + * 3) 本操作的值限制在 64 位(bit)有符号数字表示之内 + * decrement the integer value of a key by one + * 1) if key not exists, the key's value will be set 0 and DECR + * 2) if key's value is not a number an error will be returned + * 3) the number is a 64 signed integer + * @param key {const char*} 字符串对象的 key + * the given key + * @param result {long long int*} 非空时存储操作结果 + * store the result after INCR if it isn't NULL + * @return {bool} 操作是否成功 + * if the DECR was executed correctly + */ + bool decr(const char* key, long long int* result = NULL); + + /** + * 将 key 所储存的值减去减量 decrement + * 1) 如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 DECRBY 操作 + * 2) 如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误 + * 3) 本操作的值限制在 64 位(bit)有符号数字表示之内 + * decrement the integer value of a key by the given amount + * @param key {const char*} 字符串对象的 key + * the given key + * @param dec {long long int} 减量值 + * the given amount + * @param result {long long int*} 非空时存储操作结果 + * store the result after INCR if it isn't NULL + * @return {bool} 操作是否成功 + * if the DECRBY was executed correctly + */ + bool decrby(const char* key, long long int dec, + long long int* result = NULL); + +private: + int bitop(const char* op, const char* destkey, + const std::vector& keys); + int bitop(const char* op, const char* destkey, + const std::vector& keys); + int bitop(const char* op, const char* destkey, + const char* keys[], size_t size); + + bool incoper(const char* cmd, const char* key, long long int* inc, + long long int* result); + +}; + +} // namespace acl + +#endif // !defined(ACL_CLIENT_ONLY) && !defined(ACL_REDIS_DISABLE) diff --git a/lib_acl_cpp/samples/redis/redis_string/redis_string.cpp b/lib_acl_cpp/samples/redis/redis_string/redis_string.cpp index a309951186039cdbcd145b2199245bb75ea738d2..9bbdbf6507744510fc3edc3fe99812591d48d01a 100644 --- a/lib_acl_cpp/samples/redis/redis_string/redis_string.cpp +++ b/lib_acl_cpp/samples/redis/redis_string/redis_string.cpp @@ -1,810 +1,810 @@ -#include "stdafx.h" - -static bool __check_addr = false; -static acl::string __keypre("test_key"); - -static bool test_set(acl::redis_string& redis, int n) -{ - acl::string key; - acl::string value; - - for (int i = 0; i < n; i++) - { - key.format("%s_%d", __keypre.c_str(), i); - value.format("value_%s", key.c_str()); - - redis.clear(); - redis.set_check_addr(__check_addr); - if (redis.set(key.c_str(), value.c_str()) == false) - { - printf("set key: %s error: %s\r\n", - key.c_str(), redis.result_error()); - return false; - } - else if (i < 10) - printf("set key: %s ok\r\n", key.c_str()); - } - - return true; -} - -static bool test_setex(acl::redis_string& redis, int n, int ttl) -{ - acl::string key, value; - - for (int i = 0; i < n; i++) - { - key.format("%s_%d", __keypre.c_str(), i); - value.format("value_%s", key.c_str()); - - redis.clear(); - if (redis.setex(key.c_str(), value.c_str(), ttl) == false) - { - printf("setex key: %s error: %s\r\n", - key.c_str(), redis.result_error()); - return false; - } - else if (i < 10) - printf("setex key: %s, ttl: %d\r\n", key.c_str(), ttl); - } - - return true; -} - -static bool test_setnx(acl::redis_string& redis, int n) -{ - acl::string key; - acl::string value; - - for (int i = 0; i < n; i++) - { - key.format("%s_%d", __keypre.c_str(), i); - value.format("_setnx_%s", key.c_str()); - - redis.clear(); - int ret = redis.setnx(key.c_str(), value.c_str()); - if (ret < 0) - { - printf("setnx key: %s error: %s\r\n", - key.c_str(), redis.result_error()); - return false; - } - printf("%s: ret: %d, key: %s\r\n", __FUNCTION__, ret, - key.c_str()); - } - - return true; -} - -static bool test_append(acl::redis_string& redis, int n) -{ - acl::string key; - acl::string value; - - for (int i = 0; i < n; i++) - { - key.format("%s_%d", __keypre.c_str(), i); - value.format("_append_%d", i); - - redis.clear(); - if (redis.append(key.c_str(), value.c_str()) < 0) - { - printf("append key: %s\r\n", key.c_str()); - return false; - } - } - - return true; -} - -static bool test_get(acl::redis_string& redis, int n) -{ - acl::string key; - acl::string value; - - for (int i = 0; i < n; i++) - { - key.format("%s_%d", __keypre.c_str(), i); - //key.format("key1_%s_%d", __keypre.c_str(), i); - value.clear(); - - redis.clear(); - if (redis.get(key.c_str(), value) == false) - { - printf("get key: %s\r\n", key.c_str()); - return false; - } - else if (i < 10) - printf("key: %s, value: %s, len: %d\r\n", - key.c_str(), value.c_str(), - (int) value.length()); - } - - return true; -} - -static bool test_getset(acl::redis_string& redis, int n) -{ - acl::string key; - acl::string value; - acl::string result; - - for (int i = 0; i < n; i++) - { - key.format("%s_%d", __keypre.c_str(), i); - value.format("getset_%s", key.c_str()); - result.clear(); - - redis.clear(); - if (redis.getset(key.c_str(), value.c_str(), result) == false) - { - printf("getset error: %s, key: %s\r\n", - redis.result_error(), key.c_str()); - return false; - } - else if (i < 10) - printf("getset: key: %s, old value: %s\r\n", - key.c_str(), result.c_str()); - } - - return true; -} - -static bool test_strlen(acl::redis_string& redis, int n) -{ - acl::string key; - - for (int i = 0; i < n; i++) - { - key.format("%s_%d", __keypre.c_str(), i); - - redis.clear(); - int ret = redis.get_strlen(key.c_str()); - if (ret < 0) - { - printf("str_len error: %s, key: %s\r\n", - redis.result_error(), key.c_str()); - return false; - } - else if (i < 10) - printf("key: %s's value's length: %d\r\n", - key.c_str(), ret); - } - - return true; -} - -static bool test_mset(acl::redis_string& redis, int n) -{ - acl::string key1, key2, key3; - acl::string val1, val2, val3; - std::map objs; - - for (int i = 0; i < n; i++) - { - key1.format("key1_%s_%d", __keypre.c_str(), i); - key2.format("key2_%s_%d", __keypre.c_str(), i); - key3.format("key3_%s_%d", __keypre.c_str(), i); - - val1.format("val1_%s", key1.c_str()); - val2.format("val2_%s", key2.c_str()); - val3.format("val3_%s", key3.c_str()); - - objs[key1] = val1; - objs[key2] = val2; - objs[key3] = val3; - - redis.clear(); - if (redis.mset(objs) == false) - { - printf("mset error: %s\r\n", redis.result_error()); - return false; - } - else if (i < 10) - { - printf("mset ok, %s=%s, %s=%s, %s=%s\r\n", - key1.c_str(), val1.c_str(), - key2.c_str(), val2.c_str(), - key3.c_str(), val3.c_str()); - } - objs.clear(); - } - - return true; -} - -static bool test_mget(acl::redis_string& redis, int n) -{ - acl::string key1, key2, key3; - std::vector result; - const char* keys[3]; - - for (int i = 0; i < n; i++) - { - key1.format("key1_%s_%d", __keypre.c_str(), i); - key2.format("key2_%s_%d", __keypre.c_str(), i); - key3.format("key3_%s_%d", __keypre.c_str(), i); - keys[0] = key1.c_str(); - keys[1] = key2.c_str(); - keys[2] = key3.c_str(); - - result.clear(); - redis.clear(); - if (redis.mget(keys, 3, &result) == false) - { - printf("mset error: %s\r\n", redis.result_error()); - return false; - } - else if (i >= 10) - continue; - - size_t size = redis.result_size(); - printf("size: %lu\r\n", (unsigned long) size); - - size_t j; - for (j = 0; j < size; j++) - { - const char* val = redis.result_value(j); - printf("mget ok, %s=%s\r\n", - keys[j], val ? val : "null"); - } - - std::vector::const_iterator it= result.begin(); - for (j = 0; it != result.end(); ++it, j++) - printf("mget %s=%s\r\n", keys[j], (*it).c_str()); - } - - return true; -} - -static bool test_msetnx(acl::redis_string& redis, int n) -{ - acl::string key1, key2, key3; - acl::string val1, val2, val3; - std::map objs; - int ret; - - for (int i = 0; i < n; i++) - { - key1.format("key1_%s_%d", __keypre.c_str(), i); - key2.format("key2_%s_%d", __keypre.c_str(), i); - key3.format("key3_%s_%d", __keypre.c_str(), i); - - val1.format("val1_%s", key1.c_str()); - val2.format("val2_%s", key2.c_str()); - val3.format("val3_%s", key3.c_str()); - - objs[key1] = val1; - objs[key2] = val2; - objs[key3] = val3; - - redis.clear(); - ret = redis.msetnx(objs); - if (ret < 0) - { - printf("mset error: %s\r\n", redis.result_error()); - return false; - } - else if (i < 10) - { - printf("msetnx ret: %d, %s=%s, %s=%s, %s=%s\r\n", ret, - key1.c_str(), val1.c_str(), - key2.c_str(), val2.c_str(), - key3.c_str(), val3.c_str()); - } - objs.clear(); - } - - return true; -} - -static bool test_setrange(acl::redis_string& redis, int n) -{ - acl::string key, value; - unsigned int off = 5; - int ret; - - for (int i = 0; i < n; i++) - { - key.format("%s_%d", __keypre.c_str(), i); - value.format("range_value_%s", key.c_str()); - - redis.clear(); - ret = redis.setrange(key.c_str(), off, value.c_str()); - if (ret < 0) - { - printf("setrange error: %s, key: %s, off: %u, value: %s\r\n", - redis.result_error(), key.c_str(), off, value.c_str()); - return false; - } - else if (i < 10) - printf("setrange ok, key: %s, off: %u, value: %s\r\n", - key.c_str(), off, value.c_str()); - } - - return true; -} - -static bool test_getrange(acl::redis_string& redis, int n) -{ - acl::string key, value; - int start = 5, end = 10; - - for (int i = 0; i < n; i++) - { - key.format("%s_%d", __keypre.c_str(), i); - value.clear(); - - redis.clear(); - if (redis.getrange(key, start, end, value) == false) - { - printf("getrange error: %s, key: %s, start: %d, end: %d\r\n", - redis.result_error(), key.c_str(), start, end); - return false; - } - else if (i >= 10) - continue; - - printf("getrange ok, key: %s, start: %d, end: %d, value: %s\r\n", - key.c_str(), start, end, value.c_str()); - } - - return true; -} - -static bool test_setbit(acl::redis_string& redis, int n) -{ - acl::string key; - unsigned off = 5; - - for (int i = 0; i < n; i++) - { - key.format("bit_%s_%d", __keypre.c_str(), i); - - redis.clear(); - if (redis.setbit_(key.c_str(), off, 1) == false) - { - printf("setbit error: %s, key: %s, off: %u\r\n", - redis.result_error(), key.c_str(), off); - return false; - } - else if (i >= 10) - continue; - - printf("setbit ok, key: %s, off: %d\r\n", key.c_str(), off); - } - - return true; -} - -static bool test_getbit(acl::redis_string& redis, int n) -{ - acl::string key; - unsigned off = 5; - int bit; - - for (int i = 0; i < n; i++) - { - key.format("bit_%s_%d", __keypre.c_str(), i); - - redis.clear(); - if (redis.getbit(key.c_str(), off, bit) == false) - { - printf("getbit error: %s, key: %s, off: %u\r\n", - redis.result_error(), key.c_str(), off); - return false; - } - else if (i >= 10) - continue; - - printf("getbit ok, key: %s, off: %d, bit: %d\r\n", - key.c_str(), off, bit); - } - - return true; -} - -static bool test_bitcount(acl::redis_string& redis, int n) -{ - acl::string key; - int ret; - - for (int i = 0; i < n; i++) - { - key.format("bit_%s_%d", __keypre.c_str(), i); - - redis.clear(); - ret = redis.bitcount(key.c_str()); - if (ret < 0) - { - printf("bitcount error: %s, key: %s\r\n", - redis.result_error(), key.c_str()); - return false; - } - else if (i < 10) - printf("bitcount ok, key: %s, ret: %d\r\n", - key.c_str(), ret); - } - - return true; -} - -static bool test_bitop_and(acl::redis_string& redis, int n) -{ - const char* keys[3]; - acl::string key, key1, key2, key3; - int ret; - - for (int i = 0; i < n; i++) - { - key.format("bit_%s_%d", __keypre.c_str(), i); - key1.format("bit_%s_%d", __keypre.c_str(), i % 1); - key2.format("bit_%s_%d", __keypre.c_str(), i % 2); - key3.format("bit_%s_%d", __keypre.c_str(), i % 3); - keys[0] = key1.c_str(); - keys[1] = key2.c_str(); - keys[2] = key3.c_str(); - - redis.clear(); - ret = redis.bitop_and(key.c_str(), keys, 3); - if (ret < 0) - { - printf("bitop_and error: %s, key: %s\r\n", - redis.result_error(), key.c_str()); - return false; - } - else if (i < 10) - printf("bitop_and ok, key: %s, bits: %u\n", - key.c_str(), ret); - } - - return true; -} - -static bool test_bitop_or(acl::redis_string& redis, int n) -{ - const char* keys[3]; - acl::string key, key1, key2, key3; - int ret; - - for (int i = 0; i < n; i++) - { - key.format("bit_%s_%d", __keypre.c_str(), i); - key1.format("bit_%s_%d", __keypre.c_str(), i % 1); - key2.format("bit_%s_%d", __keypre.c_str(), i % 2); - key3.format("bit_%s_%d", __keypre.c_str(), i % 3); - keys[0] = key1.c_str(); - keys[1] = key2.c_str(); - keys[2] = key3.c_str(); - - redis.clear(); - ret = redis.bitop_or(key.c_str(), keys, 3); - if (ret < 0) - { - printf("bitop_or error: %s, key: %s\r\n", - redis.result_error(), key.c_str()); - return false; - } - else if (i < 10) - printf("bitop_or ok, key: %s, bits: %u\n", - key.c_str(), ret); - } - - return true; -} - -static bool test_bitop_xor(acl::redis_string& redis, int n) -{ - const char* keys[3]; - acl::string key, key1, key2, key3; - int ret; - - for (int i = 0; i < n; i++) - { - key.format("bit_%s_%d", __keypre.c_str(), i); - key1.format("bit_%s_%d", __keypre.c_str(), i % 1); - key2.format("bit_%s_%d", __keypre.c_str(), i % 2); - key3.format("bit_%s_%d", __keypre.c_str(), i % 3); - keys[0] = key1.c_str(); - keys[1] = key2.c_str(); - keys[2] = key3.c_str(); - - redis.clear(); - ret = redis.bitop_xor(key.c_str(), keys, 3); - if (ret < 0) - { - printf("bitop_xor error: %s, key: %s\r\n", - redis.result_error(), key.c_str()); - return false; - } - else if (i < 10) - printf("bitop_xor ok, key: %s, bits: %u\n", - key.c_str(), ret); - } - - - return true; -} - -static bool test_incr(acl::redis_string& redis, int n) -{ - acl::string key; - long long int result; - - for (int i = 0; i < n; i++) - { - key.format("incr_%s_%d", __keypre.c_str(), i); - - redis.clear(); - if (redis.incr(key.c_str(), &result) == false) - { - printf("incr error: %s, key: %s\r\n", - redis.result_error(), key.c_str()); - return false; - } - else if (i < 10) - printf("incr ok, key: %s, result: %lld\r\n", - key.c_str(), result); - } - - return true; -} - -static bool test_incrby(acl::redis_string& redis, int n) -{ - acl::string key; - long long int result; - - for (int i = 0; i < n; i++) - { - key.format("incr_%s_%d", __keypre.c_str(), i); - - redis.clear(); - if (redis.incrby(key.c_str(), 10, &result) == false) - { - printf("incrby error: %s, key: %s\r\n", - redis.result_error(), key.c_str()); - return false; - } - else if (i < 10) - printf("incrby ok, key: %s, result: %lld\r\n", - key.c_str(), result); - } - - return true; -} - -static bool test_incrbyfloat(acl::redis_string& redis, int n) -{ - acl::string key; - double result; - - for (int i = 0; i < n; i++) - { - key.format("incrbyfloat_%s_%d", __keypre.c_str(), i); - - redis.clear(); - if (redis.incrbyfloat(key.c_str(), 8.8, &result) == false) - { - printf("incrbyfloat error: %s, key: %s\r\n", - redis.result_error(), key.c_str()); - return false; - } - else if (i < 10) - printf("incrbyfloat ok, key: %s, result: %.2f\r\n", - key.c_str(), result); - } - - return true; -} - -static bool test_decr(acl::redis_string& redis, int n) -{ - acl::string key; - long long int result; - - for (int i = 0; i < n; i++) - { - key.format("incr_%s_%d", __keypre.c_str(), i); - - redis.clear(); - if (redis.decr(key.c_str(), &result) == false) - { - printf("decr error: %s, key: %s\r\n", - redis.result_error(), key.c_str()); - return false; - } - else if (i < 10) - printf("decr ok, key: %s, result: %lld\r\n", - key.c_str(), result); - } - - return true; -} - -static bool test_decrby(acl::redis_string& redis, int n) -{ - acl::string key; - long long int result; - - for (int i = 0; i < n; i++) - { - key.format("incr_%s_%d", __keypre.c_str(), i); - - redis.clear(); - if (redis.decrby(key.c_str(), 10, &result) == false) - { - printf("decrby error: %s, key: %s\r\n", - redis.result_error(), key.c_str()); - return false; - } - else if (i < 10) - printf("decrby ok, key: %s, result: %lld\r\n", - key.c_str(), result); - } - - return true; -} - -static void usage(const char* procname) -{ - printf("usage: %s -h[help]\r\n" - "-s redis_addr[127.0.0.1:6379]\r\n" - "-n count[default: 1]\r\n" - "-C connect_timeout[default: 10]\r\n" - "-I rw_timeout[default: 10]\r\n" - "-t object timeout[default: 10]\r\n" - "-c [use cluster mode]\r\n" - "-M [if check connection addr first]\r\n" - "-a cmd[set|setex|setnx|append|get|getset|strlen|mset|mget|msetnx|setrange|getrange|setbit|getbit|bitcount|bitop_and|bitop_or|bitop_xor|incr|incrby|incrbyfloat|decr|decrby]\r\n", - procname); -} - -int main(int argc, char* argv[]) -{ - int ch, n = 1, conn_timeout = 10, rw_timeout = 10, ttl = 10; - acl::string addr("127.0.0.1:6379"), cmd; - bool cluster_mode = false; - - while ((ch = getopt(argc, argv, "hs:n:C:I:a:t:cM")) > 0) - { - switch (ch) - { - case 'h': - usage(argv[0]); - return 0; - case 's': - addr = optarg; - break; - case 'n': - n = atoi(optarg); - break; - case 'C': - conn_timeout = atoi(optarg); - break; - case 'I': - rw_timeout = atoi(optarg); - break; - case 'a': - cmd = optarg; - break; - case 't': - ttl = atoi(optarg); - break; - case 'c': - cluster_mode = true; - break; - case 'M': - __check_addr = true; - break; - default: - break; - } - } - - acl::acl_cpp_init(); - acl::log::stdout_open(true); - - acl::redis_client_cluster cluster; - cluster.set(addr.c_str(), 100, conn_timeout, rw_timeout); - - acl::redis_client client(addr.c_str(), conn_timeout, rw_timeout); - - acl::redis_string redis; - - if (cluster_mode) - redis.set_cluster(&cluster, 100); - else - redis.set_client(&client); - - bool ret; - - if (cmd == "set") - ret = test_set(redis, n); - else if (cmd == "setex") - ret = test_setex(redis, n, ttl); - else if (cmd == "setnx") - ret = test_setnx(redis, n); - else if (cmd == "append") - ret = test_append(redis, n); - else if (cmd == "get") - ret = test_get(redis, n); - else if (cmd == "getset") - ret = test_getset(redis, n); - else if (cmd == "strlen") - ret = test_strlen(redis, n); - else if (cmd == "mset") - ret = test_mset(redis, n); - else if (cmd == "mget") - ret = test_mget(redis, n); - else if (cmd == "msetnx") - ret = test_msetnx(redis, n); - else if (cmd == "setrange") - ret = test_setrange(redis, n); - else if (cmd == "getrange") - ret = test_getrange(redis, n); - else if (cmd == "setbit") - ret = test_setbit(redis, n); - else if (cmd == "getbit") - ret = test_getbit(redis, n); - else if (cmd == "bitcount") - ret = test_bitcount(redis, n); - else if (cmd == "bitop_and") - ret = test_bitop_and(redis, n); - else if (cmd == "bitop_or") - ret = test_bitop_or(redis, n); - else if (cmd == "bitop_xor") - ret = test_bitop_xor(redis, n); - else if (cmd == "incr") - ret = test_incr(redis, n); - else if (cmd == "incrby") - ret = test_incrby(redis, n); - else if (cmd == "incrbyfloat") - ret = test_incrbyfloat(redis, n); - else if (cmd == "decr") - ret = test_decr(redis, n); - else if (cmd == "decrby") - ret = test_decrby(redis, n); - else if (cmd == "all") - { - ret = test_set(redis, n) - && test_setex(redis, n, ttl) - && test_setnx(redis, n) - && test_append(redis, n) - && test_get(redis, n) - && test_getset(redis, n) - && test_strlen(redis, n) - && test_mset(redis, n) - && test_mget(redis, n) - && test_msetnx(redis, n) - && test_setrange(redis, n) - && test_getrange(redis, n) - && test_setbit(redis, n) - && test_getbit(redis, n) - && test_bitcount(redis, n) - && test_bitop_and(redis, n) - && test_bitop_or(redis, n) - && test_bitop_xor(redis, n) - && test_incr(redis, n) - && test_incrby(redis, n) - && test_incrbyfloat(redis, n) - && test_decr(redis, n) - && test_decrby(redis, n); - } - else - { - ret = false; - printf("unknown cmd: %s\r\n", cmd.c_str()); - } - - if (ret == true) - printf("test OK!\r\n"); - else - printf("test failed!\r\n"); - -#ifdef WIN32 - printf("enter any key to exit\r\n"); - getchar(); -#endif - return 0; -} +#include "stdafx.h" + +static bool __check_addr = false; +static acl::string __keypre("test_key"); + +static bool test_set(acl::redis_string& redis, int n) +{ + acl::string key; + acl::string value; + + for (int i = 0; i < n; i++) + { + key.format("%s_%d", __keypre.c_str(), i); + value.format("value_%s", key.c_str()); + + redis.clear(); + redis.set_check_addr(__check_addr); + if (redis.set(key.c_str(), value.c_str(), 100, SETFLAG_EX | SETFLAG_NX) == false) + { + printf("set key: %s error: %s\r\n", + key.c_str(), redis.result_error()); + return false; + } + else if (i < 10) + printf("set key: %s ok\r\n", key.c_str()); + } + + return true; +} + +static bool test_setex(acl::redis_string& redis, int n, int ttl) +{ + acl::string key, value; + + for (int i = 0; i < n; i++) + { + key.format("%s_%d", __keypre.c_str(), i); + value.format("value_%s", key.c_str()); + + redis.clear(); + if (redis.setex(key.c_str(), value.c_str(), ttl) == false) + { + printf("setex key: %s error: %s\r\n", + key.c_str(), redis.result_error()); + return false; + } + else if (i < 10) + printf("setex key: %s, ttl: %d\r\n", key.c_str(), ttl); + } + + return true; +} + +static bool test_setnx(acl::redis_string& redis, int n) +{ + acl::string key; + acl::string value; + + for (int i = 0; i < n; i++) + { + key.format("%s_%d", __keypre.c_str(), i); + value.format("_setnx_%s", key.c_str()); + + redis.clear(); + int ret = redis.setnx(key.c_str(), value.c_str()); + if (ret < 0) + { + printf("setnx key: %s error: %s\r\n", + key.c_str(), redis.result_error()); + return false; + } + printf("%s: ret: %d, key: %s\r\n", __FUNCTION__, ret, + key.c_str()); + } + + return true; +} + +static bool test_append(acl::redis_string& redis, int n) +{ + acl::string key; + acl::string value; + + for (int i = 0; i < n; i++) + { + key.format("%s_%d", __keypre.c_str(), i); + value.format("_append_%d", i); + + redis.clear(); + if (redis.append(key.c_str(), value.c_str()) < 0) + { + printf("append key: %s\r\n", key.c_str()); + return false; + } + } + + return true; +} + +static bool test_get(acl::redis_string& redis, int n) +{ + acl::string key; + acl::string value; + + for (int i = 0; i < n; i++) + { + key.format("%s_%d", __keypre.c_str(), i); + //key.format("key1_%s_%d", __keypre.c_str(), i); + value.clear(); + + redis.clear(); + if (redis.get(key.c_str(), value) == false) + { + printf("get key: %s\r\n", key.c_str()); + return false; + } + else if (i < 10) + printf("key: %s, value: %s, len: %d\r\n", + key.c_str(), value.c_str(), + (int) value.length()); + } + + return true; +} + +static bool test_getset(acl::redis_string& redis, int n) +{ + acl::string key; + acl::string value; + acl::string result; + + for (int i = 0; i < n; i++) + { + key.format("%s_%d", __keypre.c_str(), i); + value.format("getset_%s", key.c_str()); + result.clear(); + + redis.clear(); + if (redis.getset(key.c_str(), value.c_str(), result) == false) + { + printf("getset error: %s, key: %s\r\n", + redis.result_error(), key.c_str()); + return false; + } + else if (i < 10) + printf("getset: key: %s, old value: %s\r\n", + key.c_str(), result.c_str()); + } + + return true; +} + +static bool test_strlen(acl::redis_string& redis, int n) +{ + acl::string key; + + for (int i = 0; i < n; i++) + { + key.format("%s_%d", __keypre.c_str(), i); + + redis.clear(); + int ret = redis.get_strlen(key.c_str()); + if (ret < 0) + { + printf("str_len error: %s, key: %s\r\n", + redis.result_error(), key.c_str()); + return false; + } + else if (i < 10) + printf("key: %s's value's length: %d\r\n", + key.c_str(), ret); + } + + return true; +} + +static bool test_mset(acl::redis_string& redis, int n) +{ + acl::string key1, key2, key3; + acl::string val1, val2, val3; + std::map objs; + + for (int i = 0; i < n; i++) + { + key1.format("key1_%s_%d", __keypre.c_str(), i); + key2.format("key2_%s_%d", __keypre.c_str(), i); + key3.format("key3_%s_%d", __keypre.c_str(), i); + + val1.format("val1_%s", key1.c_str()); + val2.format("val2_%s", key2.c_str()); + val3.format("val3_%s", key3.c_str()); + + objs[key1] = val1; + objs[key2] = val2; + objs[key3] = val3; + + redis.clear(); + if (redis.mset(objs) == false) + { + printf("mset error: %s\r\n", redis.result_error()); + return false; + } + else if (i < 10) + { + printf("mset ok, %s=%s, %s=%s, %s=%s\r\n", + key1.c_str(), val1.c_str(), + key2.c_str(), val2.c_str(), + key3.c_str(), val3.c_str()); + } + objs.clear(); + } + + return true; +} + +static bool test_mget(acl::redis_string& redis, int n) +{ + acl::string key1, key2, key3; + std::vector result; + const char* keys[3]; + + for (int i = 0; i < n; i++) + { + key1.format("key1_%s_%d", __keypre.c_str(), i); + key2.format("key2_%s_%d", __keypre.c_str(), i); + key3.format("key3_%s_%d", __keypre.c_str(), i); + keys[0] = key1.c_str(); + keys[1] = key2.c_str(); + keys[2] = key3.c_str(); + + result.clear(); + redis.clear(); + if (redis.mget(keys, 3, &result) == false) + { + printf("mset error: %s\r\n", redis.result_error()); + return false; + } + else if (i >= 10) + continue; + + size_t size = redis.result_size(); + printf("size: %lu\r\n", (unsigned long) size); + + size_t j; + for (j = 0; j < size; j++) + { + const char* val = redis.result_value(j); + printf("mget ok, %s=%s\r\n", + keys[j], val ? val : "null"); + } + + std::vector::const_iterator it= result.begin(); + for (j = 0; it != result.end(); ++it, j++) + printf("mget %s=%s\r\n", keys[j], (*it).c_str()); + } + + return true; +} + +static bool test_msetnx(acl::redis_string& redis, int n) +{ + acl::string key1, key2, key3; + acl::string val1, val2, val3; + std::map objs; + int ret; + + for (int i = 0; i < n; i++) + { + key1.format("key1_%s_%d", __keypre.c_str(), i); + key2.format("key2_%s_%d", __keypre.c_str(), i); + key3.format("key3_%s_%d", __keypre.c_str(), i); + + val1.format("val1_%s", key1.c_str()); + val2.format("val2_%s", key2.c_str()); + val3.format("val3_%s", key3.c_str()); + + objs[key1] = val1; + objs[key2] = val2; + objs[key3] = val3; + + redis.clear(); + ret = redis.msetnx(objs); + if (ret < 0) + { + printf("mset error: %s\r\n", redis.result_error()); + return false; + } + else if (i < 10) + { + printf("msetnx ret: %d, %s=%s, %s=%s, %s=%s\r\n", ret, + key1.c_str(), val1.c_str(), + key2.c_str(), val2.c_str(), + key3.c_str(), val3.c_str()); + } + objs.clear(); + } + + return true; +} + +static bool test_setrange(acl::redis_string& redis, int n) +{ + acl::string key, value; + unsigned int off = 5; + int ret; + + for (int i = 0; i < n; i++) + { + key.format("%s_%d", __keypre.c_str(), i); + value.format("range_value_%s", key.c_str()); + + redis.clear(); + ret = redis.setrange(key.c_str(), off, value.c_str()); + if (ret < 0) + { + printf("setrange error: %s, key: %s, off: %u, value: %s\r\n", + redis.result_error(), key.c_str(), off, value.c_str()); + return false; + } + else if (i < 10) + printf("setrange ok, key: %s, off: %u, value: %s\r\n", + key.c_str(), off, value.c_str()); + } + + return true; +} + +static bool test_getrange(acl::redis_string& redis, int n) +{ + acl::string key, value; + int start = 5, end = 10; + + for (int i = 0; i < n; i++) + { + key.format("%s_%d", __keypre.c_str(), i); + value.clear(); + + redis.clear(); + if (redis.getrange(key, start, end, value) == false) + { + printf("getrange error: %s, key: %s, start: %d, end: %d\r\n", + redis.result_error(), key.c_str(), start, end); + return false; + } + else if (i >= 10) + continue; + + printf("getrange ok, key: %s, start: %d, end: %d, value: %s\r\n", + key.c_str(), start, end, value.c_str()); + } + + return true; +} + +static bool test_setbit(acl::redis_string& redis, int n) +{ + acl::string key; + unsigned off = 5; + + for (int i = 0; i < n; i++) + { + key.format("bit_%s_%d", __keypre.c_str(), i); + + redis.clear(); + if (redis.setbit_(key.c_str(), off, 1) == false) + { + printf("setbit error: %s, key: %s, off: %u\r\n", + redis.result_error(), key.c_str(), off); + return false; + } + else if (i >= 10) + continue; + + printf("setbit ok, key: %s, off: %d\r\n", key.c_str(), off); + } + + return true; +} + +static bool test_getbit(acl::redis_string& redis, int n) +{ + acl::string key; + unsigned off = 5; + int bit; + + for (int i = 0; i < n; i++) + { + key.format("bit_%s_%d", __keypre.c_str(), i); + + redis.clear(); + if (redis.getbit(key.c_str(), off, bit) == false) + { + printf("getbit error: %s, key: %s, off: %u\r\n", + redis.result_error(), key.c_str(), off); + return false; + } + else if (i >= 10) + continue; + + printf("getbit ok, key: %s, off: %d, bit: %d\r\n", + key.c_str(), off, bit); + } + + return true; +} + +static bool test_bitcount(acl::redis_string& redis, int n) +{ + acl::string key; + int ret; + + for (int i = 0; i < n; i++) + { + key.format("bit_%s_%d", __keypre.c_str(), i); + + redis.clear(); + ret = redis.bitcount(key.c_str()); + if (ret < 0) + { + printf("bitcount error: %s, key: %s\r\n", + redis.result_error(), key.c_str()); + return false; + } + else if (i < 10) + printf("bitcount ok, key: %s, ret: %d\r\n", + key.c_str(), ret); + } + + return true; +} + +static bool test_bitop_and(acl::redis_string& redis, int n) +{ + const char* keys[3]; + acl::string key, key1, key2, key3; + int ret; + + for (int i = 0; i < n; i++) + { + key.format("bit_%s_%d", __keypre.c_str(), i); + key1.format("bit_%s_%d", __keypre.c_str(), i % 1); + key2.format("bit_%s_%d", __keypre.c_str(), i % 2); + key3.format("bit_%s_%d", __keypre.c_str(), i % 3); + keys[0] = key1.c_str(); + keys[1] = key2.c_str(); + keys[2] = key3.c_str(); + + redis.clear(); + ret = redis.bitop_and(key.c_str(), keys, 3); + if (ret < 0) + { + printf("bitop_and error: %s, key: %s\r\n", + redis.result_error(), key.c_str()); + return false; + } + else if (i < 10) + printf("bitop_and ok, key: %s, bits: %u\n", + key.c_str(), ret); + } + + return true; +} + +static bool test_bitop_or(acl::redis_string& redis, int n) +{ + const char* keys[3]; + acl::string key, key1, key2, key3; + int ret; + + for (int i = 0; i < n; i++) + { + key.format("bit_%s_%d", __keypre.c_str(), i); + key1.format("bit_%s_%d", __keypre.c_str(), i % 1); + key2.format("bit_%s_%d", __keypre.c_str(), i % 2); + key3.format("bit_%s_%d", __keypre.c_str(), i % 3); + keys[0] = key1.c_str(); + keys[1] = key2.c_str(); + keys[2] = key3.c_str(); + + redis.clear(); + ret = redis.bitop_or(key.c_str(), keys, 3); + if (ret < 0) + { + printf("bitop_or error: %s, key: %s\r\n", + redis.result_error(), key.c_str()); + return false; + } + else if (i < 10) + printf("bitop_or ok, key: %s, bits: %u\n", + key.c_str(), ret); + } + + return true; +} + +static bool test_bitop_xor(acl::redis_string& redis, int n) +{ + const char* keys[3]; + acl::string key, key1, key2, key3; + int ret; + + for (int i = 0; i < n; i++) + { + key.format("bit_%s_%d", __keypre.c_str(), i); + key1.format("bit_%s_%d", __keypre.c_str(), i % 1); + key2.format("bit_%s_%d", __keypre.c_str(), i % 2); + key3.format("bit_%s_%d", __keypre.c_str(), i % 3); + keys[0] = key1.c_str(); + keys[1] = key2.c_str(); + keys[2] = key3.c_str(); + + redis.clear(); + ret = redis.bitop_xor(key.c_str(), keys, 3); + if (ret < 0) + { + printf("bitop_xor error: %s, key: %s\r\n", + redis.result_error(), key.c_str()); + return false; + } + else if (i < 10) + printf("bitop_xor ok, key: %s, bits: %u\n", + key.c_str(), ret); + } + + + return true; +} + +static bool test_incr(acl::redis_string& redis, int n) +{ + acl::string key; + long long int result; + + for (int i = 0; i < n; i++) + { + key.format("incr_%s_%d", __keypre.c_str(), i); + + redis.clear(); + if (redis.incr(key.c_str(), &result) == false) + { + printf("incr error: %s, key: %s\r\n", + redis.result_error(), key.c_str()); + return false; + } + else if (i < 10) + printf("incr ok, key: %s, result: %lld\r\n", + key.c_str(), result); + } + + return true; +} + +static bool test_incrby(acl::redis_string& redis, int n) +{ + acl::string key; + long long int result; + + for (int i = 0; i < n; i++) + { + key.format("incr_%s_%d", __keypre.c_str(), i); + + redis.clear(); + if (redis.incrby(key.c_str(), 10, &result) == false) + { + printf("incrby error: %s, key: %s\r\n", + redis.result_error(), key.c_str()); + return false; + } + else if (i < 10) + printf("incrby ok, key: %s, result: %lld\r\n", + key.c_str(), result); + } + + return true; +} + +static bool test_incrbyfloat(acl::redis_string& redis, int n) +{ + acl::string key; + double result; + + for (int i = 0; i < n; i++) + { + key.format("incrbyfloat_%s_%d", __keypre.c_str(), i); + + redis.clear(); + if (redis.incrbyfloat(key.c_str(), 8.8, &result) == false) + { + printf("incrbyfloat error: %s, key: %s\r\n", + redis.result_error(), key.c_str()); + return false; + } + else if (i < 10) + printf("incrbyfloat ok, key: %s, result: %.2f\r\n", + key.c_str(), result); + } + + return true; +} + +static bool test_decr(acl::redis_string& redis, int n) +{ + acl::string key; + long long int result; + + for (int i = 0; i < n; i++) + { + key.format("incr_%s_%d", __keypre.c_str(), i); + + redis.clear(); + if (redis.decr(key.c_str(), &result) == false) + { + printf("decr error: %s, key: %s\r\n", + redis.result_error(), key.c_str()); + return false; + } + else if (i < 10) + printf("decr ok, key: %s, result: %lld\r\n", + key.c_str(), result); + } + + return true; +} + +static bool test_decrby(acl::redis_string& redis, int n) +{ + acl::string key; + long long int result; + + for (int i = 0; i < n; i++) + { + key.format("incr_%s_%d", __keypre.c_str(), i); + + redis.clear(); + if (redis.decrby(key.c_str(), 10, &result) == false) + { + printf("decrby error: %s, key: %s\r\n", + redis.result_error(), key.c_str()); + return false; + } + else if (i < 10) + printf("decrby ok, key: %s, result: %lld\r\n", + key.c_str(), result); + } + + return true; +} + +static void usage(const char* procname) +{ + printf("usage: %s -h[help]\r\n" + "-s redis_addr[127.0.0.1:6379]\r\n" + "-n count[default: 1]\r\n" + "-C connect_timeout[default: 10]\r\n" + "-I rw_timeout[default: 10]\r\n" + "-t object timeout[default: 10]\r\n" + "-c [use cluster mode]\r\n" + "-M [if check connection addr first]\r\n" + "-a cmd[set|setex|setnx|append|get|getset|strlen|mset|mget|msetnx|setrange|getrange|setbit|getbit|bitcount|bitop_and|bitop_or|bitop_xor|incr|incrby|incrbyfloat|decr|decrby]\r\n", + procname); +} + +int main(int argc, char* argv[]) +{ + int ch, n = 1, conn_timeout = 10, rw_timeout = 10, ttl = 10; + acl::string addr("127.0.0.1:6379"), cmd; + bool cluster_mode = false; + + while ((ch = getopt(argc, argv, "hs:n:C:I:a:t:cM")) > 0) + { + switch (ch) + { + case 'h': + usage(argv[0]); + return 0; + case 's': + addr = optarg; + break; + case 'n': + n = atoi(optarg); + break; + case 'C': + conn_timeout = atoi(optarg); + break; + case 'I': + rw_timeout = atoi(optarg); + break; + case 'a': + cmd = optarg; + break; + case 't': + ttl = atoi(optarg); + break; + case 'c': + cluster_mode = true; + break; + case 'M': + __check_addr = true; + break; + default: + break; + } + } + + acl::acl_cpp_init(); + acl::log::stdout_open(true); + + acl::redis_client_cluster cluster; + cluster.set(addr.c_str(), 100, conn_timeout, rw_timeout); + + acl::redis_client client(addr.c_str(), conn_timeout, rw_timeout); + + acl::redis_string redis; + + if (cluster_mode) + redis.set_cluster(&cluster, 100); + else + redis.set_client(&client); + + bool ret; + + if (cmd == "set") + ret = test_set(redis, n); + else if (cmd == "setex") + ret = test_setex(redis, n, ttl); + else if (cmd == "setnx") + ret = test_setnx(redis, n); + else if (cmd == "append") + ret = test_append(redis, n); + else if (cmd == "get") + ret = test_get(redis, n); + else if (cmd == "getset") + ret = test_getset(redis, n); + else if (cmd == "strlen") + ret = test_strlen(redis, n); + else if (cmd == "mset") + ret = test_mset(redis, n); + else if (cmd == "mget") + ret = test_mget(redis, n); + else if (cmd == "msetnx") + ret = test_msetnx(redis, n); + else if (cmd == "setrange") + ret = test_setrange(redis, n); + else if (cmd == "getrange") + ret = test_getrange(redis, n); + else if (cmd == "setbit") + ret = test_setbit(redis, n); + else if (cmd == "getbit") + ret = test_getbit(redis, n); + else if (cmd == "bitcount") + ret = test_bitcount(redis, n); + else if (cmd == "bitop_and") + ret = test_bitop_and(redis, n); + else if (cmd == "bitop_or") + ret = test_bitop_or(redis, n); + else if (cmd == "bitop_xor") + ret = test_bitop_xor(redis, n); + else if (cmd == "incr") + ret = test_incr(redis, n); + else if (cmd == "incrby") + ret = test_incrby(redis, n); + else if (cmd == "incrbyfloat") + ret = test_incrbyfloat(redis, n); + else if (cmd == "decr") + ret = test_decr(redis, n); + else if (cmd == "decrby") + ret = test_decrby(redis, n); + else if (cmd == "all") + { + ret = test_set(redis, n) + && test_setex(redis, n, ttl) + && test_setnx(redis, n) + && test_append(redis, n) + && test_get(redis, n) + && test_getset(redis, n) + && test_strlen(redis, n) + && test_mset(redis, n) + && test_mget(redis, n) + && test_msetnx(redis, n) + && test_setrange(redis, n) + && test_getrange(redis, n) + && test_setbit(redis, n) + && test_getbit(redis, n) + && test_bitcount(redis, n) + && test_bitop_and(redis, n) + && test_bitop_or(redis, n) + && test_bitop_xor(redis, n) + && test_incr(redis, n) + && test_incrby(redis, n) + && test_incrbyfloat(redis, n) + && test_decr(redis, n) + && test_decrby(redis, n); + } + else + { + ret = false; + printf("unknown cmd: %s\r\n", cmd.c_str()); + } + + if (ret == true) + printf("test OK!\r\n"); + else + printf("test failed!\r\n"); + +#ifdef WIN32 + printf("enter any key to exit\r\n"); + getchar(); +#endif + return 0; +} diff --git a/lib_acl_cpp/src/redis/redis_string.cpp b/lib_acl_cpp/src/redis/redis_string.cpp index 452bd1b59bc179bb9d545ec798b86fe621349ea2..8f952a34ec3ad2f982431535548a4d01141cea66 100644 --- a/lib_acl_cpp/src/redis/redis_string.cpp +++ b/lib_acl_cpp/src/redis/redis_string.cpp @@ -1,797 +1,860 @@ -#include "acl_stdafx.hpp" -#ifndef ACL_PREPARE_COMPILE -#include "acl_cpp/stdlib/snprintf.hpp" -#include "acl_cpp/stdlib/dbuf_pool.hpp" -#include "acl_cpp/stdlib/string.hpp" -#include "acl_cpp/redis/redis_client.hpp" -#include "acl_cpp/redis/redis_result.hpp" -#include "acl_cpp/redis/redis_string.hpp" -#endif - -#if !defined(ACL_CLIENT_ONLY) && !defined(ACL_REDIS_DISABLE) - -namespace acl -{ - -#define INT64_LEN 21 -#define INT_LEN 11 -#define FLOAT_LEN 32 - -redis_string::redis_string() -: redis_command(NULL) -{ -} - -redis_string::redis_string(redis_client* conn) -: redis_command(conn) -{ -} - -redis_string::redis_string(redis_client_cluster* cluster, size_t max_conns) -: redis_command(cluster, max_conns) -{ -} - -redis_string::~redis_string() -{ -} - -bool redis_string::set(const char* key, const char* value) -{ - return set(key, strlen(key), value, strlen(value)); -} - -bool redis_string::set(const char* key, size_t key_len, - const char* value, size_t value_len) -{ - const char* argv[3]; - size_t lens[3]; - - argv[0] = "SET"; - lens[0] = sizeof("SET") - 1; - - argv[1] = key; - lens[1] = key_len; - - argv[2] = value; - lens[2] = value_len; - - hash_slot(key, key_len); - build_request(3, argv, lens); - return check_status(); -} - -bool redis_string::setex(const char* key, const char* value, int timeout) -{ - return setex(key, strlen(key), value, strlen(value), timeout); -} - -bool redis_string::setex(const char* key, size_t key_len, const char* value, - size_t value_len, int timeout) -{ - const char* argv[4]; - size_t lens[4]; - - argv[0] = "SETEX"; - lens[0] = sizeof("SETEX") - 1; - - argv[1] = key; - lens[1] = key_len; - - char buf[INT_LEN]; - (void) safe_snprintf(buf, sizeof(buf), "%d", timeout); - argv[2] = buf; - lens[2] = strlen(buf); - - argv[3] = value; - lens[3] = value_len; - - hash_slot(key, key_len); - build_request(4, argv, lens); - return check_status(); -} - -bool redis_string::psetex(const char* key, const char* value, int timeout) -{ - return psetex(key, strlen(key), value, strlen(value), timeout); -} - -bool redis_string::psetex(const char* key, size_t key_len, const char* value, - size_t value_len, int timeout) -{ - const char* argv[4]; - size_t lens[4]; - - argv[0] = "PSETEX"; - lens[0] = sizeof("PSETEX") - 1; - - argv[1] = key; - lens[1] = key_len; - - char buf[INT_LEN]; - (void) safe_snprintf(buf, sizeof(buf), "%d", timeout); - argv[2] = buf; - lens[2] = strlen(buf); - - argv[3] = value; - lens[3] = value_len; - - hash_slot(key, key_len); - build_request(4, argv, lens); - return check_status(); -} - -int redis_string::setnx(const char* key, const char* value) -{ - return setnx(key, strlen(key), value, strlen(value)); -} - -int redis_string::setnx(const char* key, size_t key_len, - const char* value, size_t value_len) -{ - const char* argv[3]; - size_t lens[3]; - - argv[0] = "SETNX"; - lens[0] = sizeof("SETNX") - 1; - - argv[1] = key; - lens[1] = key_len; - - argv[2] = value; - lens[2] = value_len; - - hash_slot(key, key_len); - build_request(3, argv, lens); - return get_number(); -} - -int redis_string::append(const char* key, const char* value) -{ - return append(key, value, strlen(value)); -} - -int redis_string::append(const char* key, const char* value, size_t size) -{ - const char* argv[3]; - size_t lens[3]; - - argv[0] = "APPEND"; - lens[0] = sizeof("APPEND") - 1; - - argv[1] = key; - lens[1] = strlen(key); - - argv[2] = value; - lens[2] = size; - - hash_slot(key); - build_request(3, argv, lens); - return get_number(); -} - -bool redis_string::get(const char* key, string& buf) -{ - return get(key, strlen(key), buf); -} - -bool redis_string::get(const char* key, size_t len, string& buf) -{ - const char* argv[2]; - size_t lens[2]; - - argv[0] = "GET"; - lens[0] = sizeof("GET") - 1; - - argv[1] = key; - lens[1] = len; - - hash_slot(key, len); - build_request(2, argv, lens); - return get_string(buf) >= 0 ? true : false; -} - -const redis_result* redis_string::get(const char* key) -{ - return get(key, strlen(key)); -} - -const redis_result* redis_string::get(const char* key, size_t len) -{ - const char* argv[2]; - size_t lens[2]; - - argv[0] = "GET"; - lens[0] = sizeof("GET") - 1; - - argv[1] = key; - lens[1] = len; - - hash_slot(key, len); - build_request(2, argv, lens); - const redis_result* result = run(); - if (result == NULL) - return NULL; - if (result->get_type() != REDIS_RESULT_STRING) - return NULL; - return result; -} - -bool redis_string::getset(const char* key, const char* value, string& buf) -{ - return getset(key, strlen(key), value, strlen(value), buf); -} - -bool redis_string::getset(const char* key, size_t key_len, - const char* value, size_t value_len, string& buf) -{ - const char* argv[3]; - size_t lens[3]; - - argv[0] = "GETSET"; - lens[0] = sizeof("GETSET") - 1; - - argv[1] = key; - lens[1] = key_len; - - argv[2] = value; - lens[2] = value_len; - - hash_slot(key, key_len); - build_request(3, argv, lens); - return get_string(buf) >= 0 ? true : false; -} - -///////////////////////////////////////////////////////////////////////////// - -int redis_string::get_strlen(const char* key) -{ - return get_strlen(key, strlen(key)); -} - -int redis_string::get_strlen(const char* key, size_t len) -{ - const char* argv[2]; - size_t lens[2]; - - argv[0] = "STRLEN"; - lens[0] = sizeof("STRLEN") - 1; - - argv[1] = key; - lens[1] = len; - - hash_slot(key, len); - build_request(2, argv, lens); - return get_number(); -} - -int redis_string::setrange(const char* key, unsigned offset, const char* value) -{ - return setrange(key, strlen(key), offset, value, strlen(value)); -} - -int redis_string::setrange(const char* key, size_t key_len, unsigned offset, - const char* value, size_t value_len) -{ - const char* argv[4]; - size_t lens[4]; - - argv[0] = "SETRANGE"; - lens[0] = sizeof("SETRANGE") - 1; - - argv[1] = key; - lens[1] = key_len; - - char buf[INT64_LEN]; - (void) acl_i64toa(offset, buf, sizeof(buf)); - argv[2] = buf; - lens[2] = strlen(buf); - - argv[3] = value; - lens[3] = value_len; - - hash_slot(key, key_len); - build_request(4, argv, lens); - return get_number(); -} - -bool redis_string::getrange(const char* key, int start, int end, string& buf) -{ - return getrange(key, strlen(key), start, end, buf); -} - -bool redis_string::getrange(const char* key, size_t key_len, - int start, int end, string& buf) -{ - const char* argv[4]; - size_t lens[4]; - - argv[0] = "GETRANGE"; - lens[0] = sizeof("GETRANGE") - 1; - - argv[1] = key; - lens[1] = key_len; - - char start_buf[INT_LEN], end_buf[INT_LEN]; - (void) safe_snprintf(start_buf, sizeof(start_buf), "%d", start); - argv[2] = start_buf; - lens[2] = strlen(start_buf); - - (void) safe_snprintf(end_buf, sizeof(end_buf), "%d", end); - argv[3] = end_buf; - lens[3] = strlen(end_buf); - - hash_slot(key, key_len); - build_request(4, argv, lens); - return get_string(buf) >= 0 ? true : false; -} - -///////////////////////////////////////////////////////////////////////////// - -bool redis_string::setbit_(const char* key, unsigned offset, bool bit) -{ - return setbit_(key, strlen(key), offset, bit); -} - -bool redis_string::setbit_(const char* key, size_t len, - unsigned offset, bool bit) -{ - const char* argv[4]; - size_t lens[4]; - - argv[0] = "SETBIT"; - lens[0] = sizeof("SETBIT") - 1; - - argv[1] = key; - lens[1] = len; - - char buf4off[INT_LEN]; - (void) safe_snprintf(buf4off, sizeof(buf4off), "%d", offset); - argv[2] = buf4off; - lens[2] = strlen(buf4off); - - argv[3] = bit ? "1" : "0"; - lens[3] = 1; - - hash_slot(key, len); - build_request(4, argv, lens); - return get_number() >= 0 ? true : false; -} - -bool redis_string::getbit(const char* key, unsigned offset, int& bit) -{ - return getbit(key, strlen(key), offset, bit); -} - -bool redis_string::getbit(const char* key, size_t len, - unsigned offset, int& bit) -{ - const char* argv[3]; - size_t lens[3]; - - argv[0] = "GETBIT"; - lens[0] = sizeof("GETBIT") - 1; - - argv[1] = key; - lens[1] = len; - - char buf4off[INT_LEN]; - (void) safe_snprintf(buf4off, sizeof(buf4off), "%d", offset); - argv[2] = buf4off; - lens[2] = strlen(buf4off); - - hash_slot(key, len); - build_request(3, argv, lens); - int ret = get_number(); - if (ret < 0) - return false; - bit = ret == 0 ? 0 : 1; - return true; -} - -int redis_string::bitcount(const char* key) -{ - return bitcount(key, strlen(key)); -} - -int redis_string::bitcount(const char* key, size_t len) -{ - const char* argv[2]; - size_t lens[2]; - - argv[0] = "BITCOUNT"; - lens[0] = sizeof("BITCOUNT") - 1; - - argv[1] = key; - lens[1] = len; - - hash_slot(key, len); - build_request(2, argv, lens); - return get_number(); -} - -int redis_string::bitcount(const char* key, int start, int end) -{ - return bitcount(key, strlen(key), start, end); -} - -int redis_string::bitcount(const char* key, size_t len, int start, int end) -{ - const char* argv[4]; - size_t lens[4]; - - argv[0] = "BITCOUNT"; - lens[0] = sizeof("BITCOUNT") - 1; - - argv[1] = key; - lens[1] = len; - - char buf4start[INT_LEN]; - (void) safe_snprintf(buf4start, sizeof(buf4start), "%d", start); - argv[2] = buf4start; - lens[2] = strlen(buf4start); - - char buf4end[INT_LEN]; - (void) safe_snprintf(buf4end, sizeof(buf4end), "%d", end); - argv[3] = buf4end; - lens[3] = strlen(buf4end); - - hash_slot(key, len); - build_request(4, argv, lens); - return get_number(); -} - -int redis_string::bitop_and(const char* destkey, const std::vector& keys) -{ - return bitop("AND", destkey, keys); -} - -int redis_string::bitop_or(const char* destkey, const std::vector& keys) -{ - return bitop("OR", destkey, keys); -} - -int redis_string::bitop_xor(const char* destkey, const std::vector& keys) -{ - return bitop("XOR", destkey, keys); -} - -int redis_string::bitop_and(const char* destkey, const std::vector& keys) -{ - return bitop("AND", destkey, keys); -} - -int redis_string::bitop_or(const char* destkey, const std::vector& keys) -{ - return bitop("OR", destkey, keys); -} - -int redis_string::bitop_xor(const char* destkey, const std::vector& keys) -{ - return bitop("XOR", destkey, keys); -} - -int redis_string::bitop_and(const char* destkey, const char* keys[], size_t size) -{ - return bitop("AND", destkey, keys, size); -} - -int redis_string::bitop_or(const char* destkey, const char* keys[], size_t size) -{ - return bitop("OR", destkey, keys, size); -} - -int redis_string::bitop_xor(const char* destkey, const char* keys[], size_t size) -{ - return bitop("XOR", destkey, keys, size); -} - -int redis_string::bitop_and(const char* destkey, const char* key, ...) -{ - std::vector keys; - keys.push_back(key); - - va_list ap; - va_start(ap, key); - const char* ptr; - while ((ptr = va_arg(ap, const char*)) != NULL) - keys.push_back(ptr); - va_end(ap); - return bitop("AND", destkey, keys); -} - -int redis_string::bitop_or(const char* destkey, const char* key, ...) -{ - std::vector keys; - keys.push_back(key); - - va_list ap; - va_start(ap, key); - const char* ptr; - while ((ptr = va_arg(ap, const char*)) != NULL) - keys.push_back(ptr); - va_end(ap); - return bitop("OR", destkey, keys); -} - -int redis_string::bitop_xor(const char* destkey, const char* key, ...) -{ - std::vector keys; - keys.push_back(key); - - va_list ap; - va_start(ap, key); - const char* ptr; - while ((ptr = va_arg(ap, const char*)) != NULL) - keys.push_back(ptr); - va_end(ap); - return bitop("XOR", destkey, keys); -} - -int redis_string::bitop(const char* op, const char* destkey, - const std::vector& keys) -{ - size_t argc = 3 + keys.size(); - const char** argv = (const char**) dbuf_->dbuf_alloc(argc * sizeof(char*)); - size_t* lens = (size_t*) dbuf_->dbuf_alloc(argc * sizeof(size_t)); - - argv[0] = "BITOP"; - lens[0] = sizeof("BITOP") - 1; - - argv[1] = op; - lens[1] = strlen(op); - - argv[2] = destkey; - lens[2] = strlen(destkey); - - std::vector::const_iterator cit = keys.begin(); - for (size_t i = 3; cit != keys.end(); ++cit, i++) { - argv[i] = (*cit).c_str(); - lens[i] = strlen(argv[i]); - } - - build_request(argc, argv, lens); - return get_number(); -} - -int redis_string::bitop(const char* op, const char* destkey, - const std::vector& keys) -{ - size_t argc = 3 + keys.size(); - const char** argv = (const char**) dbuf_->dbuf_alloc(argc * sizeof(char*)); - size_t* lens = (size_t*) dbuf_->dbuf_alloc(argc * sizeof(size_t)); - - argv[0] = "BITOP"; - lens[0] = sizeof("BITOP") - 1; - - argv[1] = op; - lens[1] = strlen(op); - - argv[2] = destkey; - lens[2] = strlen(destkey); - - std::vector::const_iterator cit = keys.begin(); - for (size_t i = 3; cit != keys.end(); ++cit, i++) { - argv[i] = *cit; - lens[i] = strlen(argv[i]); - } - - build_request(argc, argv, lens); - return get_number(); -} - -int redis_string::bitop(const char* op, const char* destkey, - const char* keys[], size_t size) -{ - size_t argc = 3 + size; - const char** argv = (const char**) dbuf_->dbuf_alloc(argc * sizeof(char*)); - size_t* lens = (size_t*) dbuf_->dbuf_alloc(argc * sizeof(size_t)); - - argv[0] = "BITOP"; - lens[0] = sizeof("BITOP") - 1; - - argv[1] = op; - lens[1] = strlen(op); - - argv[2] = destkey; - lens[2] = strlen(destkey); - - for (size_t i = 3, j = 0; j < size; i++, j++) { - argv[i] = keys[j]; - lens[i] = strlen(argv[i]); - } - - build_request(argc, argv, lens); - return get_number(); -} - -///////////////////////////////////////////////////////////////////////////// - -bool redis_string::mset(const std::map& objs) -{ - build("MSET", NULL, objs); - return check_status(); -} - -bool redis_string::mset(const std::vector& keys, - const std::vector& values) -{ - build("MSET", NULL, keys, values); - return check_status(); -} - -bool redis_string::mset(const char* keys[], const char* values[], size_t argc) -{ - build("MSET", NULL, keys, values, argc); - return check_status(); -} - -bool redis_string::mset(const char* keys[], const size_t keys_len[], - const char* values[], const size_t values_len[], size_t argc) -{ - build("MSET", NULL, keys, keys_len, values, values_len, argc); - return check_status(); -} - -///////////////////////////////////////////////////////////////////////////// - -int redis_string::msetnx(const std::map& objs) -{ - build("MSETNX", NULL, objs); - return get_number(); -} - -int redis_string::msetnx(const std::vector& keys, - const std::vector& values) -{ - build("MSETNX", NULL, keys, values); - return get_number(); -} - -int redis_string::msetnx(const char* keys[], const char* values[], size_t argc) -{ - build("MSETNX", NULL, keys, values, argc); - return get_number(); -} - -int redis_string::msetnx(const char* keys[], const size_t keys_len[], - const char* values[], const size_t values_len[], size_t argc) -{ - build("MSETNX", NULL, keys, keys_len, values, values_len, argc); - return get_number(); -} - -///////////////////////////////////////////////////////////////////////////// - -bool redis_string::mget(const std::vector& keys, - std::vector* out /* = NULL */) -{ - build("MGET", NULL, keys); - return get_strings(out) >= 0 ? true : false; -} - -bool redis_string::mget(const std::vector& keys, - std::vector* out /* = NULL */) -{ - build("MGET", NULL, keys); - return get_strings(out) >= 0 ? true : false; -} - -bool redis_string::mget(std::vector* out, const char* first_key, ...) -{ - std::vector keys; - keys.push_back(first_key); - - va_list ap; - va_start(ap, first_key); - const char* key; - while ((key = va_arg(ap, const char*)) != NULL) - keys.push_back(key); - va_end(ap); - - build("MGET", NULL, keys); - return get_strings(out) >= 0 ? true : false; -} - -bool redis_string::mget(const char* keys[], size_t argc, - std::vector* out /* = NULL */) -{ - build("MGET", NULL, keys, argc); - return get_strings(out) >= 0 ? true : false; -} - -bool redis_string::mget(const char* keys[], const size_t keys_len[], - size_t argc, std::vector* out /* = NULL */) -{ - build("MGET", NULL, keys, keys_len, argc); - return get_strings(out) >= 0 ? true : false; -} - -///////////////////////////////////////////////////////////////////////////// - -bool redis_string::incr(const char* key, long long int* result /* = NULL */) -{ - hash_slot(key); - return incoper("INCR", key, NULL, result); -} - -bool redis_string::incrby(const char* key, long long int inc, - long long int* result /* = NULL */) -{ - hash_slot(key); - return incoper("INCRBY", key, &inc, result); -} - -bool redis_string::incrbyfloat(const char* key, double inc, - double* result /* = NULL */) -{ - const char* argv[3]; - size_t lens[3]; - - argv[0] = "INCRBYFLOAT"; - lens[0] = sizeof("INCRBYFLOAT") - 1; - - argv[1] = key; - lens[1] = strlen(key); - - char buf[FLOAT_LEN]; - (void) safe_snprintf(buf, sizeof(buf), "%f", inc); - argv[2] = buf; - lens[2] = strlen(buf); - - hash_slot(key); - build_request(3, argv, lens); - if (get_string(buf, sizeof(buf)) <= 0) - return false; - - if (result != NULL) - *result = atof(buf); - return true; -} - -bool redis_string::decr(const char* key, long long int* result /* = NULL */) -{ - return incoper("DECR", key, NULL, result); -} - -bool redis_string::decrby(const char* key, long long int dec, - long long int* result /* = NULL */) -{ - return incoper("DECRBY", key, &dec, result); -} - -bool redis_string::incoper(const char* cmd, const char* key, long long int* n, - long long int* result) -{ - size_t argc = 2; - const char* argv[3]; - size_t lens[3]; - - argv[0] = cmd; - lens[0] = strlen(cmd); - - argv[1] = key; - lens[1] = strlen(key); - - char buf[INT64_LEN]; - if (n != NULL) { - (void) acl_i64toa(*n, buf, sizeof(buf)); - argv[2] = buf; - lens[2] = strlen(buf); - argc++; - } - - hash_slot(key); - build_request(argc, argv, lens); - - bool success; - if (result != NULL) - *result = get_number64(&success); - else - (void) get_number64(&success); - return success; -} - -} // namespace acl - -#endif // ACL_CLIENT_ONLY +#include "acl_stdafx.hpp" +#ifndef ACL_PREPARE_COMPILE +#include "acl_cpp/stdlib/snprintf.hpp" +#include "acl_cpp/stdlib/dbuf_pool.hpp" +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/redis/redis_client.hpp" +#include "acl_cpp/redis/redis_result.hpp" +#include "acl_cpp/redis/redis_string.hpp" +#endif + +#if !defined(ACL_CLIENT_ONLY) && !defined(ACL_REDIS_DISABLE) + +namespace acl +{ + +#define INT64_LEN 21 +#define INT_LEN 11 +#define FLOAT_LEN 32 + +redis_string::redis_string() +: redis_command(NULL) +{ +} + +redis_string::redis_string(redis_client* conn) +: redis_command(conn) +{ +} + +redis_string::redis_string(redis_client_cluster* cluster, size_t max_conns) +: redis_command(cluster, max_conns) +{ +} + +redis_string::~redis_string() +{ +} + +bool redis_string::set(const char* key, const char* value) +{ + return set(key, strlen(key), value, strlen(value)); +} + +bool redis_string::set(const char* key, size_t key_len, + const char* value, size_t value_len) +{ + const char* argv[3]; + size_t lens[3]; + + argv[0] = "SET"; + lens[0] = sizeof("SET") - 1; + + argv[1] = key; + lens[1] = key_len; + + argv[2] = value; + lens[2] = value_len; + + hash_slot(key, key_len); + build_request(3, argv, lens); + return check_status(); +} + +bool redis_string::set(const char* key, const char* value, int timeout, int flag) +{ + return set(key, strlen(key), value, strlen(value), timeout, flag); +} + +bool redis_string::set(const char* key, size_t key_len, const char* value, size_t value_len, int timeout, int flag) +{ + const char* argv[6]; + size_t lens[6]; + int n = 3; + + argv[0] = "SET"; + lens[0] = sizeof("SET") - 1; + + argv[1] = key; + lens[1] = key_len; + + argv[2] = value; + lens[2] = value_len; + + if ( timeout > 0) + { + if (SETFLAG_EX == ( flag & 0x03)) + { + argv[n] = "EX"; + lens[n] = sizeof("EX") - 1; + n++; + } + else if ( SETFLAG_PX == (flag & 0x03)) + { + argv[n] = "PX"; + lens[n] = sizeof("PX") - 1; + n++; + } + else + goto NEXT_X; + + char buf[INT_LEN]; + (void) safe_snprintf(buf, sizeof(buf), "%d", timeout); + argv[n] = buf; + lens[n] = strlen(buf); + n++; + } + +NEXT_X: + if (SETFLAG_NX == ( flag & 0x0c)) + { + argv[n] = "NX"; + lens[n] = sizeof("NX") - 1; + n++; + } + else if (SETFLAG_XX == ( flag & 0x0c)) + { + argv[n] = "XX"; + lens[n] = sizeof("XX") - 1; + n++; + } + + hash_slot(key, key_len); + build_request(n, argv, lens); + return check_status(); +} + +bool redis_string::setex(const char* key, const char* value, int timeout) +{ + return setex(key, strlen(key), value, strlen(value), timeout); +} + +bool redis_string::setex(const char* key, size_t key_len, const char* value, + size_t value_len, int timeout) +{ + const char* argv[4]; + size_t lens[4]; + + argv[0] = "SETEX"; + lens[0] = sizeof("SETEX") - 1; + + argv[1] = key; + lens[1] = key_len; + + char buf[INT_LEN]; + (void) safe_snprintf(buf, sizeof(buf), "%d", timeout); + argv[2] = buf; + lens[2] = strlen(buf); + + argv[3] = value; + lens[3] = value_len; + + hash_slot(key, key_len); + build_request(4, argv, lens); + return check_status(); +} + +bool redis_string::psetex(const char* key, const char* value, int timeout) +{ + return psetex(key, strlen(key), value, strlen(value), timeout); +} + +bool redis_string::psetex(const char* key, size_t key_len, const char* value, + size_t value_len, int timeout) +{ + const char* argv[4]; + size_t lens[4]; + + argv[0] = "PSETEX"; + lens[0] = sizeof("PSETEX") - 1; + + argv[1] = key; + lens[1] = key_len; + + char buf[INT_LEN]; + (void) safe_snprintf(buf, sizeof(buf), "%d", timeout); + argv[2] = buf; + lens[2] = strlen(buf); + + argv[3] = value; + lens[3] = value_len; + + hash_slot(key, key_len); + build_request(4, argv, lens); + return check_status(); +} + +int redis_string::setnx(const char* key, const char* value) +{ + return setnx(key, strlen(key), value, strlen(value)); +} + +int redis_string::setnx(const char* key, size_t key_len, + const char* value, size_t value_len) +{ + const char* argv[3]; + size_t lens[3]; + + argv[0] = "SETNX"; + lens[0] = sizeof("SETNX") - 1; + + argv[1] = key; + lens[1] = key_len; + + argv[2] = value; + lens[2] = value_len; + + hash_slot(key, key_len); + build_request(3, argv, lens); + return get_number(); +} + +int redis_string::append(const char* key, const char* value) +{ + return append(key, value, strlen(value)); +} + +int redis_string::append(const char* key, const char* value, size_t size) +{ + const char* argv[3]; + size_t lens[3]; + + argv[0] = "APPEND"; + lens[0] = sizeof("APPEND") - 1; + + argv[1] = key; + lens[1] = strlen(key); + + argv[2] = value; + lens[2] = size; + + hash_slot(key); + build_request(3, argv, lens); + return get_number(); +} + +bool redis_string::get(const char* key, string& buf) +{ + return get(key, strlen(key), buf); +} + +bool redis_string::get(const char* key, size_t len, string& buf) +{ + const char* argv[2]; + size_t lens[2]; + + argv[0] = "GET"; + lens[0] = sizeof("GET") - 1; + + argv[1] = key; + lens[1] = len; + + hash_slot(key, len); + build_request(2, argv, lens); + return get_string(buf) >= 0 ? true : false; +} + +const redis_result* redis_string::get(const char* key) +{ + return get(key, strlen(key)); +} + +const redis_result* redis_string::get(const char* key, size_t len) +{ + const char* argv[2]; + size_t lens[2]; + + argv[0] = "GET"; + lens[0] = sizeof("GET") - 1; + + argv[1] = key; + lens[1] = len; + + hash_slot(key, len); + build_request(2, argv, lens); + const redis_result* result = run(); + if (result == NULL) + return NULL; + if (result->get_type() != REDIS_RESULT_STRING) + return NULL; + return result; +} + +bool redis_string::getset(const char* key, const char* value, string& buf) +{ + return getset(key, strlen(key), value, strlen(value), buf); +} + +bool redis_string::getset(const char* key, size_t key_len, + const char* value, size_t value_len, string& buf) +{ + const char* argv[3]; + size_t lens[3]; + + argv[0] = "GETSET"; + lens[0] = sizeof("GETSET") - 1; + + argv[1] = key; + lens[1] = key_len; + + argv[2] = value; + lens[2] = value_len; + + hash_slot(key, key_len); + build_request(3, argv, lens); + return get_string(buf) >= 0 ? true : false; +} + +///////////////////////////////////////////////////////////////////////////// + +int redis_string::get_strlen(const char* key) +{ + return get_strlen(key, strlen(key)); +} + +int redis_string::get_strlen(const char* key, size_t len) +{ + const char* argv[2]; + size_t lens[2]; + + argv[0] = "STRLEN"; + lens[0] = sizeof("STRLEN") - 1; + + argv[1] = key; + lens[1] = len; + + hash_slot(key, len); + build_request(2, argv, lens); + return get_number(); +} + +int redis_string::setrange(const char* key, unsigned offset, const char* value) +{ + return setrange(key, strlen(key), offset, value, strlen(value)); +} + +int redis_string::setrange(const char* key, size_t key_len, unsigned offset, + const char* value, size_t value_len) +{ + const char* argv[4]; + size_t lens[4]; + + argv[0] = "SETRANGE"; + lens[0] = sizeof("SETRANGE") - 1; + + argv[1] = key; + lens[1] = key_len; + + char buf[INT64_LEN]; + (void) acl_i64toa(offset, buf, sizeof(buf)); + argv[2] = buf; + lens[2] = strlen(buf); + + argv[3] = value; + lens[3] = value_len; + + hash_slot(key, key_len); + build_request(4, argv, lens); + return get_number(); +} + +bool redis_string::getrange(const char* key, int start, int end, string& buf) +{ + return getrange(key, strlen(key), start, end, buf); +} + +bool redis_string::getrange(const char* key, size_t key_len, + int start, int end, string& buf) +{ + const char* argv[4]; + size_t lens[4]; + + argv[0] = "GETRANGE"; + lens[0] = sizeof("GETRANGE") - 1; + + argv[1] = key; + lens[1] = key_len; + + char start_buf[INT_LEN], end_buf[INT_LEN]; + (void) safe_snprintf(start_buf, sizeof(start_buf), "%d", start); + argv[2] = start_buf; + lens[2] = strlen(start_buf); + + (void) safe_snprintf(end_buf, sizeof(end_buf), "%d", end); + argv[3] = end_buf; + lens[3] = strlen(end_buf); + + hash_slot(key, key_len); + build_request(4, argv, lens); + return get_string(buf) >= 0 ? true : false; +} + +///////////////////////////////////////////////////////////////////////////// + +bool redis_string::setbit_(const char* key, unsigned offset, bool bit) +{ + return setbit_(key, strlen(key), offset, bit); +} + +bool redis_string::setbit_(const char* key, size_t len, + unsigned offset, bool bit) +{ + const char* argv[4]; + size_t lens[4]; + + argv[0] = "SETBIT"; + lens[0] = sizeof("SETBIT") - 1; + + argv[1] = key; + lens[1] = len; + + char buf4off[INT_LEN]; + (void) safe_snprintf(buf4off, sizeof(buf4off), "%d", offset); + argv[2] = buf4off; + lens[2] = strlen(buf4off); + + argv[3] = bit ? "1" : "0"; + lens[3] = 1; + + hash_slot(key, len); + build_request(4, argv, lens); + return get_number() >= 0 ? true : false; +} + +bool redis_string::getbit(const char* key, unsigned offset, int& bit) +{ + return getbit(key, strlen(key), offset, bit); +} + +bool redis_string::getbit(const char* key, size_t len, + unsigned offset, int& bit) +{ + const char* argv[3]; + size_t lens[3]; + + argv[0] = "GETBIT"; + lens[0] = sizeof("GETBIT") - 1; + + argv[1] = key; + lens[1] = len; + + char buf4off[INT_LEN]; + (void) safe_snprintf(buf4off, sizeof(buf4off), "%d", offset); + argv[2] = buf4off; + lens[2] = strlen(buf4off); + + hash_slot(key, len); + build_request(3, argv, lens); + int ret = get_number(); + if (ret < 0) + return false; + bit = ret == 0 ? 0 : 1; + return true; +} + +int redis_string::bitcount(const char* key) +{ + return bitcount(key, strlen(key)); +} + +int redis_string::bitcount(const char* key, size_t len) +{ + const char* argv[2]; + size_t lens[2]; + + argv[0] = "BITCOUNT"; + lens[0] = sizeof("BITCOUNT") - 1; + + argv[1] = key; + lens[1] = len; + + hash_slot(key, len); + build_request(2, argv, lens); + return get_number(); +} + +int redis_string::bitcount(const char* key, int start, int end) +{ + return bitcount(key, strlen(key), start, end); +} + +int redis_string::bitcount(const char* key, size_t len, int start, int end) +{ + const char* argv[4]; + size_t lens[4]; + + argv[0] = "BITCOUNT"; + lens[0] = sizeof("BITCOUNT") - 1; + + argv[1] = key; + lens[1] = len; + + char buf4start[INT_LEN]; + (void) safe_snprintf(buf4start, sizeof(buf4start), "%d", start); + argv[2] = buf4start; + lens[2] = strlen(buf4start); + + char buf4end[INT_LEN]; + (void) safe_snprintf(buf4end, sizeof(buf4end), "%d", end); + argv[3] = buf4end; + lens[3] = strlen(buf4end); + + hash_slot(key, len); + build_request(4, argv, lens); + return get_number(); +} + +int redis_string::bitop_and(const char* destkey, const std::vector& keys) +{ + return bitop("AND", destkey, keys); +} + +int redis_string::bitop_or(const char* destkey, const std::vector& keys) +{ + return bitop("OR", destkey, keys); +} + +int redis_string::bitop_xor(const char* destkey, const std::vector& keys) +{ + return bitop("XOR", destkey, keys); +} + +int redis_string::bitop_and(const char* destkey, const std::vector& keys) +{ + return bitop("AND", destkey, keys); +} + +int redis_string::bitop_or(const char* destkey, const std::vector& keys) +{ + return bitop("OR", destkey, keys); +} + +int redis_string::bitop_xor(const char* destkey, const std::vector& keys) +{ + return bitop("XOR", destkey, keys); +} + +int redis_string::bitop_and(const char* destkey, const char* keys[], size_t size) +{ + return bitop("AND", destkey, keys, size); +} + +int redis_string::bitop_or(const char* destkey, const char* keys[], size_t size) +{ + return bitop("OR", destkey, keys, size); +} + +int redis_string::bitop_xor(const char* destkey, const char* keys[], size_t size) +{ + return bitop("XOR", destkey, keys, size); +} + +int redis_string::bitop_and(const char* destkey, const char* key, ...) +{ + std::vector keys; + keys.push_back(key); + + va_list ap; + va_start(ap, key); + const char* ptr; + while ((ptr = va_arg(ap, const char*)) != NULL) + keys.push_back(ptr); + va_end(ap); + return bitop("AND", destkey, keys); +} + +int redis_string::bitop_or(const char* destkey, const char* key, ...) +{ + std::vector keys; + keys.push_back(key); + + va_list ap; + va_start(ap, key); + const char* ptr; + while ((ptr = va_arg(ap, const char*)) != NULL) + keys.push_back(ptr); + va_end(ap); + return bitop("OR", destkey, keys); +} + +int redis_string::bitop_xor(const char* destkey, const char* key, ...) +{ + std::vector keys; + keys.push_back(key); + + va_list ap; + va_start(ap, key); + const char* ptr; + while ((ptr = va_arg(ap, const char*)) != NULL) + keys.push_back(ptr); + va_end(ap); + return bitop("XOR", destkey, keys); +} + +int redis_string::bitop(const char* op, const char* destkey, + const std::vector& keys) +{ + size_t argc = 3 + keys.size(); + const char** argv = (const char**) dbuf_->dbuf_alloc(argc * sizeof(char*)); + size_t* lens = (size_t*) dbuf_->dbuf_alloc(argc * sizeof(size_t)); + + argv[0] = "BITOP"; + lens[0] = sizeof("BITOP") - 1; + + argv[1] = op; + lens[1] = strlen(op); + + argv[2] = destkey; + lens[2] = strlen(destkey); + + std::vector::const_iterator cit = keys.begin(); + for (size_t i = 3; cit != keys.end(); ++cit, i++) { + argv[i] = (*cit).c_str(); + lens[i] = strlen(argv[i]); + } + + build_request(argc, argv, lens); + return get_number(); +} + +int redis_string::bitop(const char* op, const char* destkey, + const std::vector& keys) +{ + size_t argc = 3 + keys.size(); + const char** argv = (const char**) dbuf_->dbuf_alloc(argc * sizeof(char*)); + size_t* lens = (size_t*) dbuf_->dbuf_alloc(argc * sizeof(size_t)); + + argv[0] = "BITOP"; + lens[0] = sizeof("BITOP") - 1; + + argv[1] = op; + lens[1] = strlen(op); + + argv[2] = destkey; + lens[2] = strlen(destkey); + + std::vector::const_iterator cit = keys.begin(); + for (size_t i = 3; cit != keys.end(); ++cit, i++) { + argv[i] = *cit; + lens[i] = strlen(argv[i]); + } + + build_request(argc, argv, lens); + return get_number(); +} + +int redis_string::bitop(const char* op, const char* destkey, + const char* keys[], size_t size) +{ + size_t argc = 3 + size; + const char** argv = (const char**) dbuf_->dbuf_alloc(argc * sizeof(char*)); + size_t* lens = (size_t*) dbuf_->dbuf_alloc(argc * sizeof(size_t)); + + argv[0] = "BITOP"; + lens[0] = sizeof("BITOP") - 1; + + argv[1] = op; + lens[1] = strlen(op); + + argv[2] = destkey; + lens[2] = strlen(destkey); + + for (size_t i = 3, j = 0; j < size; i++, j++) { + argv[i] = keys[j]; + lens[i] = strlen(argv[i]); + } + + build_request(argc, argv, lens); + return get_number(); +} + +///////////////////////////////////////////////////////////////////////////// + +bool redis_string::mset(const std::map& objs) +{ + build("MSET", NULL, objs); + return check_status(); +} + +bool redis_string::mset(const std::vector& keys, + const std::vector& values) +{ + build("MSET", NULL, keys, values); + return check_status(); +} + +bool redis_string::mset(const char* keys[], const char* values[], size_t argc) +{ + build("MSET", NULL, keys, values, argc); + return check_status(); +} + +bool redis_string::mset(const char* keys[], const size_t keys_len[], + const char* values[], const size_t values_len[], size_t argc) +{ + build("MSET", NULL, keys, keys_len, values, values_len, argc); + return check_status(); +} + +///////////////////////////////////////////////////////////////////////////// + +int redis_string::msetnx(const std::map& objs) +{ + build("MSETNX", NULL, objs); + return get_number(); +} + +int redis_string::msetnx(const std::vector& keys, + const std::vector& values) +{ + build("MSETNX", NULL, keys, values); + return get_number(); +} + +int redis_string::msetnx(const char* keys[], const char* values[], size_t argc) +{ + build("MSETNX", NULL, keys, values, argc); + return get_number(); +} + +int redis_string::msetnx(const char* keys[], const size_t keys_len[], + const char* values[], const size_t values_len[], size_t argc) +{ + build("MSETNX", NULL, keys, keys_len, values, values_len, argc); + return get_number(); +} + +///////////////////////////////////////////////////////////////////////////// + +bool redis_string::mget(const std::vector& keys, + std::vector* out /* = NULL */) +{ + build("MGET", NULL, keys); + return get_strings(out) >= 0 ? true : false; +} + +bool redis_string::mget(const std::vector& keys, + std::vector* out /* = NULL */) +{ + build("MGET", NULL, keys); + return get_strings(out) >= 0 ? true : false; +} + +bool redis_string::mget(std::vector* out, const char* first_key, ...) +{ + std::vector keys; + keys.push_back(first_key); + + va_list ap; + va_start(ap, first_key); + const char* key; + while ((key = va_arg(ap, const char*)) != NULL) + keys.push_back(key); + va_end(ap); + + build("MGET", NULL, keys); + return get_strings(out) >= 0 ? true : false; +} + +bool redis_string::mget(const char* keys[], size_t argc, + std::vector* out /* = NULL */) +{ + build("MGET", NULL, keys, argc); + return get_strings(out) >= 0 ? true : false; +} + +bool redis_string::mget(const char* keys[], const size_t keys_len[], + size_t argc, std::vector* out /* = NULL */) +{ + build("MGET", NULL, keys, keys_len, argc); + return get_strings(out) >= 0 ? true : false; +} + +///////////////////////////////////////////////////////////////////////////// + +bool redis_string::incr(const char* key, long long int* result /* = NULL */) +{ + hash_slot(key); + return incoper("INCR", key, NULL, result); +} + +bool redis_string::incrby(const char* key, long long int inc, + long long int* result /* = NULL */) +{ + hash_slot(key); + return incoper("INCRBY", key, &inc, result); +} + +bool redis_string::incrbyfloat(const char* key, double inc, + double* result /* = NULL */) +{ + const char* argv[3]; + size_t lens[3]; + + argv[0] = "INCRBYFLOAT"; + lens[0] = sizeof("INCRBYFLOAT") - 1; + + argv[1] = key; + lens[1] = strlen(key); + + char buf[FLOAT_LEN]; + (void) safe_snprintf(buf, sizeof(buf), "%f", inc); + argv[2] = buf; + lens[2] = strlen(buf); + + hash_slot(key); + build_request(3, argv, lens); + if (get_string(buf, sizeof(buf)) <= 0) + return false; + + if (result != NULL) + *result = atof(buf); + return true; +} + +bool redis_string::decr(const char* key, long long int* result /* = NULL */) +{ + return incoper("DECR", key, NULL, result); +} + +bool redis_string::decrby(const char* key, long long int dec, + long long int* result /* = NULL */) +{ + return incoper("DECRBY", key, &dec, result); +} + +bool redis_string::incoper(const char* cmd, const char* key, long long int* n, + long long int* result) +{ + size_t argc = 2; + const char* argv[3]; + size_t lens[3]; + + argv[0] = cmd; + lens[0] = strlen(cmd); + + argv[1] = key; + lens[1] = strlen(key); + + char buf[INT64_LEN]; + if (n != NULL) { + (void) acl_i64toa(*n, buf, sizeof(buf)); + argv[2] = buf; + lens[2] = strlen(buf); + argc++; + } + + hash_slot(key); + build_request(argc, argv, lens); + + bool success; + if (result != NULL) + *result = get_number64(&success); + else + (void) get_number64(&success); + return success; +} + +} // namespace acl + +#endif // ACL_CLIENT_ONLY