PageRenderTime 66ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 1ms

/Server/GameServer/redis/redisclient.h

https://github.com/lovemychobits/c2p_server
C Header | 3197 lines | 2552 code | 507 blank | 138 comment | 286 complexity | b3b6e186a284494de02e206ffc45274b MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. /* redisclient.h -- a C++ client library for redis.
  2. *
  3. * Copyright (c) 2009, Brian Hammond <brian at fictorial dot com>
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions are met:
  8. *
  9. * * Redistributions of source code must retain the above copyright notice,
  10. * this list of conditions and the following disclaimer.
  11. * * Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * * Neither the name of Redis nor the names of its contributors may be used
  15. * to endorse or promote products derived from this software without
  16. * specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  19. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  20. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  21. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  22. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  23. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  24. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  25. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  26. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  27. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  28. * POSSIBILITY OF SUCH DAMAGE.
  29. */
  30. #ifndef REDISCLIENT_H
  31. #define REDISCLIENT_H
  32. #ifndef _MSC_VER
  33. #include <errno.h>
  34. #include <sys/socket.h>
  35. #include <string>
  36. #include <vector>
  37. #include <map>
  38. #include <set>
  39. #include <stdexcept>
  40. #include <ctime>
  41. #include <sstream>
  42. #include <boost/concept_check.hpp>
  43. #include <boost/lexical_cast.hpp>
  44. #include <boost/functional/hash.hpp>
  45. #include <boost/foreach.hpp>
  46. #include <boost/thread/mutex.hpp>
  47. #include <boost/thread/condition_variable.hpp>
  48. #include <boost/random.hpp>
  49. #include <boost/cstdint.hpp>
  50. #include <boost/date_time/posix_time/ptime.hpp>
  51. #include <boost/date_time/posix_time/posix_time_types.hpp>
  52. #include <boost/optional.hpp>
  53. #include <boost/variant.hpp>
  54. #include "anet.h"
  55. #define REDIS_LBR "\r\n"
  56. #define REDIS_STATUS_REPLY_OK "OK"
  57. #define REDIS_PREFIX_STATUS_REPLY_ERROR "-ERR "
  58. #define REDIS_PREFIX_STATUS_REPLY_ERR_C '-'
  59. #define REDIS_PREFIX_STATUS_REPLY_VALUE '+'
  60. #define REDIS_PREFIX_SINGLE_BULK_REPLY '$'
  61. #define REDIS_PREFIX_MULTI_BULK_REPLY '*'
  62. #define REDIS_PREFIX_INT_REPLY ':'
  63. #define REDIS_WHITESPACE " \f\n\r\t\v"
  64. template<class Object >
  65. struct make;
  66. namespace redis
  67. {
  68. template<typename CONSISTENT_HASHER>
  69. class base_client;
  70. enum reply_t
  71. {
  72. no_reply,
  73. status_code_reply,
  74. error_reply,
  75. int_reply,
  76. bulk_reply,
  77. multi_bulk_reply
  78. };
  79. struct connection_data
  80. {
  81. connection_data(const std::string & host = "localhost", uint16_t port = 6379, int dbindex = 0)
  82. : host(host), port(port), dbindex(dbindex), socket(ANET_ERR)
  83. {
  84. }
  85. bool operator==(const connection_data & other) const
  86. {
  87. if(host != other.host)
  88. return false;
  89. if(port != other.port)
  90. return false;
  91. if(dbindex != other.dbindex)
  92. return false;
  93. return true;
  94. }
  95. std::string host;
  96. boost::uint16_t port;
  97. int dbindex;
  98. private:
  99. int socket;
  100. template<typename CONSISTENT_HASHER>
  101. friend class base_client;
  102. };
  103. enum server_role
  104. {
  105. role_master,
  106. role_slave
  107. };
  108. // Generic error that is thrown when communicating with the redis server.
  109. class redis_error : public std::exception
  110. {
  111. public:
  112. redis_error(const std::string & err) : err_(err) {}
  113. virtual ~redis_error() throw () {}
  114. operator const std::string () const { return err_; }
  115. virtual const char* what() const throw ()
  116. {
  117. return err_.c_str();
  118. }
  119. private:
  120. std::string err_;
  121. };
  122. // Some socket-level I/O or general connection error.
  123. class connection_error : public redis_error
  124. {
  125. public:
  126. connection_error(const std::string & err) : redis_error(err) {}
  127. };
  128. // Redis gave us a reply we were not expecting.
  129. // Possibly an internal error (here or in redis, probably here).
  130. class protocol_error : public redis_error
  131. {
  132. public:
  133. protocol_error(const std::string & err) : redis_error(err) {};
  134. };
  135. // A key that you expected to exist does not in fact exist.
  136. class key_error : public redis_error
  137. {
  138. public:
  139. key_error(const std::string & err) : redis_error(err) {};
  140. };
  141. // A operation with time limit does not deliver an result early enough.
  142. class timeout_error : public redis_error
  143. {
  144. public:
  145. timeout_error(const std::string & err) : redis_error(err) {};
  146. };
  147. // A value of an expected type or other semantics was found to be invalid.
  148. class value_error : public redis_error
  149. {
  150. public:
  151. value_error(const std::string & err) : redis_error(err) {};
  152. };
  153. struct key
  154. {
  155. explicit key(const std::string & name)
  156. : name(name)
  157. {
  158. }
  159. std::string name;
  160. };
  161. class makecmd
  162. {
  163. public:
  164. explicit makecmd(const std::string & cmd_name)
  165. {
  166. append(cmd_name);
  167. //if (!finalize)
  168. // buffer_ << " ";
  169. }
  170. const std::string & key_name() const
  171. {
  172. if(!key_name_)
  173. throw std::runtime_error("No key defined!");
  174. return *key_name_;
  175. }
  176. inline makecmd & operator<<(const key & datum)
  177. {
  178. if(key_name_)
  179. throw std::runtime_error("You could not add a second key");
  180. else
  181. key_name_ = datum.name;
  182. append(datum.name);
  183. return *this;
  184. }
  185. inline makecmd & operator<<(const std::string & datum)
  186. {
  187. append(datum);
  188. return *this;
  189. }
  190. template <typename T>
  191. makecmd & operator<<(T const & datum)
  192. {
  193. append( boost::lexical_cast<std::string>(datum) );
  194. return *this;
  195. }
  196. makecmd & operator<<(const std::vector<std::string> & data)
  197. {
  198. lines_.insert( lines_.end(), data.begin(), data.end() );
  199. return *this;
  200. }
  201. template <typename T>
  202. makecmd & operator<<(const std::vector<T> & data)
  203. {
  204. size_t n = data.size();
  205. for (size_t i = 0; i < n; ++i)
  206. {
  207. append( boost::lexical_cast<std::string>( data[i] ) );
  208. //if (i < n - 1)
  209. // buffer_ << " ";
  210. }
  211. return *this;
  212. }
  213. operator std::string () const
  214. {
  215. std::ostringstream oss;
  216. size_t n = lines_.size();
  217. oss << REDIS_PREFIX_MULTI_BULK_REPLY << n << REDIS_LBR;
  218. for (size_t i = 0; i < n; ++i)
  219. {
  220. const std::string & param = lines_[i];
  221. oss << REDIS_PREFIX_SINGLE_BULK_REPLY << param.size() << REDIS_LBR;
  222. oss << param << REDIS_LBR;
  223. }
  224. return oss.str();
  225. }
  226. private:
  227. void append(const std::string & param)
  228. {
  229. lines_.push_back(param);
  230. }
  231. std::vector<std::string> lines_;
  232. boost::optional<std::string> key_name_;
  233. };
  234. template<typename CONSISTENT_HASHER>
  235. class base_client;
  236. typedef boost::variant< std::string, int, std::vector<std::string> > reply_val_t;
  237. typedef std::pair<reply_t, reply_val_t> reply_data_t;
  238. class command
  239. {
  240. private:
  241. std::string request_;
  242. std::string hash_key_;
  243. reply_data_t reply_;
  244. void check_reply_t(reply_t reply_type) const
  245. {
  246. if( reply_.first != reply_type )
  247. throw std::runtime_error("invalid reply type");
  248. }
  249. void set_reply(const reply_data_t & reply)
  250. {
  251. reply_ = reply;
  252. }
  253. template<typename CONSISTENT_HASHER>
  254. friend class base_client;
  255. public:
  256. command( const makecmd & cmd_input )
  257. : request_(cmd_input), hash_key_(cmd_input.key_name())
  258. {
  259. reply_.first = no_reply;
  260. }
  261. reply_t reply_type() const
  262. {
  263. return reply_.first;
  264. }
  265. const std::string & get_status_code_reply() const
  266. {
  267. check_reply_t(status_code_reply);
  268. return boost::get<std::string>(reply_.second);
  269. }
  270. const std::string & get_error_reply() const
  271. {
  272. check_reply_t(error_reply);
  273. return boost::get<std::string>(reply_.second);
  274. }
  275. int get_int_reply() const
  276. {
  277. check_reply_t(int_reply);
  278. return boost::get<int>(reply_.second);
  279. }
  280. const std::string & get_bulk_reply() const
  281. {
  282. check_reply_t(bulk_reply);
  283. return boost::get<std::string>(reply_.second);
  284. }
  285. const std::vector<std::string> & get_multi_bulk_reply() const
  286. {
  287. check_reply_t(multi_bulk_reply);
  288. return boost::get< std::vector<std::string> >(reply_.second);
  289. }
  290. };
  291. struct server_info
  292. {
  293. std::string version;
  294. bool bgsave_in_progress;
  295. unsigned long connected_clients;
  296. unsigned long connected_slaves;
  297. unsigned long used_memory;
  298. unsigned long changes_since_last_save;
  299. unsigned long last_save_time;
  300. unsigned long total_connections_received;
  301. unsigned long total_commands_processed;
  302. unsigned long uptime_in_seconds;
  303. unsigned long uptime_in_days;
  304. server_role role;
  305. unsigned short arch_bits;
  306. std::string multiplexing_api;
  307. std::map<std::string, std::string> param_map;
  308. };
  309. inline ssize_t recv_or_throw(int fd, void* buf, size_t n, int flags)
  310. {
  311. ssize_t bytes_received;
  312. do
  313. bytes_received = ::recv(fd, buf, n, flags);
  314. while(bytes_received < static_cast<ssize_t>(0) && errno == EINTR);
  315. if( bytes_received == static_cast<ssize_t>(0) )
  316. throw connection_error("connection was closed");
  317. // Handle receive errors. I overlooked it totally, thanks mkx!
  318. if( bytes_received == static_cast<ssize_t>(-1) )
  319. throw connection_error(std::string("recv error: ") + strerror(errno));
  320. return bytes_received;
  321. }
  322. // You should construct a 'client' object per connection to a redis-server.
  323. //
  324. // Please read the online redis command reference:
  325. // http://code.google.com/p/redis/wiki/CommandReference
  326. //
  327. // No provisions for customizing the allocator on the string/bulk value type
  328. // (std::string) are provided. If needed, you can always change the
  329. // string_type typedef in your local version.
  330. template<typename CONSISTENT_HASHER>
  331. class base_client
  332. {
  333. private:
  334. void init(connection_data & con)
  335. {
  336. char err[ANET_ERR_LEN];
  337. con.socket = anetTcpConnect(err, const_cast<char*>(con.host.c_str()), con.port);
  338. if (con.socket == ANET_ERR)
  339. {
  340. std::ostringstream os;
  341. os << err << " (redis://" << con.host << ':' << con.port << ")";
  342. throw connection_error( os.str() );
  343. }
  344. anetTcpNoDelay(NULL, con.socket);
  345. select(con.dbindex, con);
  346. }
  347. public:
  348. typedef std::string string_type;
  349. typedef std::vector<string_type> string_vector;
  350. typedef std::pair<string_type, string_type> string_pair;
  351. typedef std::vector<string_pair> string_pair_vector;
  352. typedef std::pair<string_type, double> string_score_pair;
  353. typedef std::vector<string_score_pair> string_score_vector;
  354. typedef std::set<string_type> string_set;
  355. typedef long int_type;
  356. explicit base_client(const string_type & host = "localhost",
  357. uint16_t port = 6379, int_type dbindex = 0)
  358. {
  359. connection_data con;
  360. con.host = host;
  361. con.port = port;
  362. con.dbindex = dbindex;
  363. init(con);
  364. connections_.push_back(con);
  365. }
  366. template<typename CON_ITERATOR>
  367. base_client(CON_ITERATOR begin, CON_ITERATOR end)
  368. {
  369. while(begin != end)
  370. {
  371. connection_data con = *begin;
  372. init(con);
  373. connections_.push_back(con);
  374. begin++;
  375. }
  376. if( connections_.empty() )
  377. throw std::runtime_error("No connections given!");
  378. }
  379. base_client<CONSISTENT_HASHER>* clone() const
  380. {
  381. return new base_client<CONSISTENT_HASHER>(connections_.begin(), connections_.end());
  382. }
  383. inline static string_type missing_value()
  384. {
  385. return "**nonexistent-key**";
  386. }
  387. enum datatype
  388. {
  389. datatype_none, // key doesn't exist
  390. datatype_string,
  391. datatype_list,
  392. datatype_set,
  393. datatype_zset,
  394. datatype_hash,
  395. datatype_unknown
  396. };
  397. int_type get_list(const string_type & key, string_vector & out)
  398. {
  399. return lrange(key, 0, -1, out);
  400. }
  401. void lrem_exact(const string_type & key,
  402. int_type count,
  403. const string_type & value)
  404. {
  405. if (lrem(key, count, value) != count)
  406. throw value_error("failed to remove exactly N elements from list");
  407. }
  408. enum range_specifier
  409. {
  410. exclude_min = 1 << 0,
  411. exclude_max = 1 << 1
  412. };
  413. enum aggregate_type
  414. {
  415. aggregate_sum = 1 << 0,
  416. aggregate_min = 1 << 1,
  417. aggregate_max = 1 << 2
  418. };
  419. enum sort_order
  420. {
  421. sort_order_ascending,
  422. sort_order_descending
  423. };
  424. ~base_client()
  425. {
  426. BOOST_FOREACH(connection_data & con, connections_)
  427. {
  428. if (con.socket != ANET_ERR)
  429. close(con.socket);
  430. }
  431. }
  432. const std::vector<connection_data> & connections() const
  433. {
  434. return connections_;
  435. }
  436. void auth(const string_type & pass)
  437. {
  438. if( connections_.size() > 1 )
  439. throw std::runtime_error("feature is not available in cluster mode");
  440. int socket = connections_[0].socket;
  441. send_(socket, makecmd("AUTH") << pass);
  442. recv_ok_reply_(socket);
  443. }
  444. void set(const string_type & key,
  445. const string_type & value)
  446. {
  447. int socket = get_socket(key);
  448. send_(socket, makecmd("SET") << key << value);
  449. recv_ok_reply_(socket);
  450. }
  451. void mset( const string_vector & keys, const string_vector & values )
  452. {
  453. assert( keys.size() == values.size() );
  454. std::map< int, boost::optional<makecmd> > socket_commands;
  455. for(size_t i=0; i < keys.size(); i++)
  456. {
  457. int socket = get_socket(keys);
  458. boost::optional<makecmd> & cmd = socket_commands[socket];
  459. if(!cmd)
  460. cmd = makecmd("MSET");
  461. *cmd << keys[i] << values[i];
  462. }
  463. typedef std::pair< int, boost::optional<makecmd> > sock_pair;
  464. BOOST_FOREACH(const sock_pair & sp, socket_commands)
  465. {
  466. send_(sp.first, *sp.second);
  467. }
  468. BOOST_FOREACH(const sock_pair & sp, socket_commands)
  469. {
  470. recv_ok_reply_(sp.first);
  471. }
  472. }
  473. void mset( const string_pair_vector & key_value_pairs )
  474. {
  475. std::map< int, boost::optional<makecmd> > socket_commands;
  476. for(size_t i=0; i < key_value_pairs.size(); i++)
  477. {
  478. const string_type & key = key_value_pairs[i].first;
  479. const string_type & value = key_value_pairs[i].second;
  480. int socket = get_socket(key);
  481. boost::optional<makecmd> & cmd = socket_commands[socket];
  482. if(!cmd)
  483. cmd = makecmd("MSET");
  484. *cmd << key << value;
  485. }
  486. typedef std::pair< int, boost::optional<makecmd> > sock_pair;
  487. BOOST_FOREACH(const sock_pair & sp, socket_commands)
  488. {
  489. send_(sp.first, *sp.second);
  490. }
  491. BOOST_FOREACH(const sock_pair & sp, socket_commands)
  492. {
  493. recv_ok_reply_(sp.first);
  494. }
  495. }
  496. private:
  497. struct msetex_data
  498. {
  499. boost::optional<makecmd> mset_cmd;
  500. std::string expire_cmds;
  501. size_t count;
  502. };
  503. public:
  504. void msetex( const string_pair_vector & key_value_pairs, int_type seconds )
  505. {
  506. std::map< int, msetex_data > socket_commands;
  507. for(size_t i=0; i < key_value_pairs.size(); i++)
  508. {
  509. const string_type & key = key_value_pairs[i].first;
  510. const string_type & value = key_value_pairs[i].second;
  511. int socket = get_socket(key);
  512. msetex_data & dat = socket_commands[socket];
  513. boost::optional<makecmd> & cmd = dat.mset_cmd;
  514. if(!cmd)
  515. {
  516. cmd = makecmd("MSET");
  517. dat.count = 0;
  518. }
  519. *cmd << key << value;
  520. std::string & expire_cmds = dat.expire_cmds;
  521. expire_cmds += makecmd("EXPIRE") << key << seconds;
  522. dat.count++;
  523. }
  524. typedef std::pair< int, msetex_data > sock_pair;
  525. BOOST_FOREACH(const sock_pair & sp, socket_commands)
  526. {
  527. std::string cmds = *sp.second.mset_cmd;
  528. cmds += sp.second.expire_cmds;
  529. send_(sp.first, cmds);
  530. }
  531. BOOST_FOREACH(const sock_pair & sp, socket_commands)
  532. {
  533. recv_ok_reply_(sp.first);
  534. for(size_t i= 0; i < sp.second.count; i++)
  535. recv_int_ok_reply_(sp.first);
  536. }
  537. }
  538. string_type get(const string_type & key)
  539. {
  540. int socket = get_socket(key);
  541. send_(socket, makecmd("GET") << key);
  542. return recv_bulk_reply_(socket);
  543. }
  544. string_type getset(const string_type & key, const string_type & value)
  545. {
  546. int socket = get_socket(key);
  547. send_(socket, makecmd("GETSET") << key << value);
  548. return recv_bulk_reply_(socket);
  549. }
  550. private:
  551. struct connection_keys
  552. {
  553. boost::optional<makecmd> cmd;
  554. /// Gives the position of the value in the original array
  555. std::vector<size_t> indices;
  556. };
  557. public:
  558. void exec(command & cmd)
  559. {
  560. int socket = get_socket(cmd.hash_key_);
  561. send_( socket, cmd.request_ );
  562. cmd.set_reply( recv_generic_reply_(socket) );
  563. }
  564. void exec(std::vector<command> & commands)
  565. {
  566. std::map< int, std::string > socket_commands;
  567. for(size_t i=0; i < commands.size(); i++)
  568. {
  569. int socket = get_socket( commands[i].hash_key_ );
  570. socket_commands[socket] += commands[i].request_;
  571. }
  572. typedef std::pair< int, std::string > sock_pair;
  573. BOOST_FOREACH(const sock_pair & sp, socket_commands)
  574. {
  575. send_(sp.first, sp.second);
  576. }
  577. for(size_t i=0; i < commands.size(); i++)
  578. {
  579. int socket = get_socket( commands[i].hash_key_ );
  580. commands[i].set_reply( recv_generic_reply_(socket) );
  581. }
  582. }
  583. void exec_transaction(std::vector<command> & commands)
  584. {
  585. int cmd_socket = -1;
  586. std::string cmd_str = makecmd("MULTI");
  587. for(size_t i=0; i < commands.size(); i++)
  588. {
  589. int socket = get_socket( commands[i].hash_key_ );
  590. if( cmd_socket == -1 )
  591. cmd_socket = socket;
  592. else if( cmd_socket != socket )
  593. throw std::runtime_error("calls in transaction map to different server!");
  594. cmd_str += commands[i].request_;
  595. }
  596. cmd_str += makecmd("EXEC");
  597. send_(cmd_socket, cmd_str);
  598. recv_ok_reply_(cmd_socket); // MULTI => +OK
  599. for(size_t i=0; i < commands.size(); i++)
  600. {
  601. std::string resp = recv_single_line_reply_(cmd_socket);
  602. if( resp != "QUEUED" )
  603. throw std::runtime_error("invalid state (expected 'QUEUED' in transaction but got '" + resp + "')");
  604. }
  605. if( read_line(cmd_socket)[0] != REDIS_PREFIX_MULTI_BULK_REPLY )
  606. throw std::runtime_error("EXEC does not return a multi bulk reply");
  607. for(size_t i=0; i < commands.size(); i++)
  608. {
  609. commands[i].set_reply( recv_generic_reply_(cmd_socket) );
  610. }
  611. }
  612. void mget(const string_vector & keys, string_vector & out)
  613. {
  614. out = string_vector( keys.size() );
  615. std::map< int, connection_keys > socket_commands;
  616. for(size_t i=0; i < keys.size(); i++)
  617. {
  618. int socket = get_socket(keys[i]);
  619. connection_keys & con_keys = socket_commands[socket];
  620. boost::optional<makecmd> & cmd = con_keys.cmd;
  621. if(!cmd)
  622. cmd = makecmd("MGET");
  623. *cmd << keys[i];
  624. con_keys.indices.push_back(i);
  625. }
  626. typedef std::pair< int, connection_keys > sock_pair;
  627. BOOST_FOREACH(const sock_pair & sp, socket_commands)
  628. {
  629. send_(sp.first, *sp.second.cmd);
  630. }
  631. BOOST_FOREACH(const sock_pair & sp, socket_commands)
  632. {
  633. const connection_keys & con_keys = sp.second;
  634. string_vector cur_out;
  635. recv_multi_bulk_reply_(sp.first, cur_out);
  636. for(size_t i=0; i < cur_out.size(); i++)
  637. out[con_keys.indices[i]] = cur_out[i];
  638. }
  639. }
  640. bool setnx(const string_type & key,
  641. const string_type & value)
  642. {
  643. int socket = get_socket(key);
  644. send_(socket, makecmd("SETNX") << key << value);
  645. return recv_int_reply_(socket) == 1;
  646. }
  647. bool msetnx( const string_vector & keys, const string_vector & values )
  648. {
  649. assert( keys.size() == values.size() );
  650. std::map< int, boost::optional<makecmd> > socket_commands;
  651. for(size_t i=0; i < keys.size(); i++)
  652. {
  653. int socket = get_socket(keys);
  654. boost::optional<makecmd> & cmd = socket_commands[socket];
  655. if(!cmd)
  656. cmd = makecmd("MSETNX");
  657. *cmd << keys[i] << values[i];
  658. }
  659. if( socket_commands.size() > 1 )
  660. throw std::runtime_error("feature is not available in cluster mode");
  661. typedef std::pair< int, boost::optional<makecmd> > sock_pair;
  662. BOOST_FOREACH(const sock_pair & sp, socket_commands)
  663. {
  664. send_(sp.first, *sp.second);
  665. recv_ok_reply_(sp.first);
  666. }
  667. }
  668. bool msetnx( const string_pair_vector & key_value_pairs )
  669. {
  670. std::map< int, boost::optional<makecmd> > socket_commands;
  671. for(size_t i=0; i < key_value_pairs.size(); i++)
  672. {
  673. int socket = get_socket(keys);
  674. boost::optional<makecmd> & cmd = socket_commands[socket];
  675. if(!cmd)
  676. cmd = makecmd("MSETNX");
  677. *cmd << key_value_pairs[i].first << key_value_pairs[i].second;
  678. }
  679. if( socket_commands.size() > 1 )
  680. throw std::runtime_error("feature is not available in cluster mode");
  681. typedef std::pair< int, boost::optional<makecmd> > sock_pair;
  682. BOOST_FOREACH(const sock_pair & sp, socket_commands)
  683. {
  684. send_(sp.first, *sp.second);
  685. recv_ok_reply_(sp.first);
  686. }
  687. }
  688. void setex(const string_type & key, const string_type & value, unsigned int secs)
  689. {
  690. int socket = get_socket(key);
  691. send_(socket, makecmd("SETEX") << key << secs << value);
  692. recv_ok_reply_(socket);
  693. }
  694. size_t append(const string_type & key, const string_type & value)
  695. {
  696. int socket = get_socket(key);
  697. send_(socket, makecmd("APPEND") << key << value);
  698. int res = recv_int_reply_(socket);
  699. if(res < 0)
  700. throw protocol_error("expected value size");
  701. assert( static_cast<size_t>(res) >= value.size() );
  702. return static_cast<size_t>(res);
  703. }
  704. string_type substr(const string_type & key, int start, int end)
  705. {
  706. int socket = get_socket(key);
  707. send_(socket, makecmd("SUBSTR") << key << start << end);
  708. return recv_bulk_reply_(socket);
  709. }
  710. int_type incr(const string_type & key)
  711. {
  712. int socket = get_socket(key);
  713. send_(socket, makecmd("INCR") << key);
  714. return recv_int_reply_(socket);
  715. }
  716. template<typename INT_TYPE>
  717. INT_TYPE incr(const string_type & key)
  718. {
  719. int socket = get_socket(key);
  720. send_(socket, makecmd("INCR") << key);
  721. return recv_int_reply_<INT_TYPE>(socket);
  722. }
  723. int_type incrby(const string_type & key, int_type by)
  724. {
  725. int socket = get_socket(key);
  726. send_(socket, makecmd("INCRBY") << key << by);
  727. return recv_int_reply_(socket);
  728. }
  729. template<typename INT_TYPE>
  730. INT_TYPE incrby(const string_type & key, INT_TYPE by)
  731. {
  732. int socket = get_socket(key);
  733. send_(socket, makecmd("INCRBY") << key << by);
  734. return recv_int_reply_<INT_TYPE>(socket);
  735. }
  736. int_type decr(const string_type & key)
  737. {
  738. int socket = get_socket(key);
  739. send_(socket, makecmd("DECR") << key);
  740. return recv_int_reply_(socket);
  741. }
  742. template<typename INT_TYPE>
  743. INT_TYPE decr(const string_type & key)
  744. {
  745. int socket = get_socket(key);
  746. send_(socket, makecmd("DECR") << key);
  747. return recv_int_reply_<INT_TYPE>(socket);
  748. }
  749. int_type decrby(const string_type & key, int_type by)
  750. {
  751. int socket = get_socket(key);
  752. send_(socket, makecmd("DECRBY") << key << by);
  753. return recv_int_reply_(socket);
  754. }
  755. template<typename INT_TYPE>
  756. INT_TYPE decrby(const string_type & key, INT_TYPE by)
  757. {
  758. int socket = get_socket(key);
  759. send_(socket, makecmd("DECRBY") << key << by);
  760. return recv_int_reply_<INT_TYPE>(socket);
  761. }
  762. bool exists(const string_type & key)
  763. {
  764. int socket = get_socket(key);
  765. send_(socket, makecmd("EXISTS") << key);
  766. return recv_int_reply_(socket) == 1;
  767. }
  768. bool del(const string_type & key)
  769. {
  770. int socket = get_socket(key);
  771. send_(socket, makecmd("DEL") << key);
  772. return recv_int_reply_(socket) != 0;
  773. }
  774. template<typename ITERATOR>
  775. bool del(ITERATOR begin, ITERATOR end)
  776. {
  777. std::map<int, string_vector> sock_key_map;
  778. while( begin != end )
  779. {
  780. string_type key = *begin++;
  781. sock_key_map[ get_socket(key) ].push_back(key);
  782. }
  783. typedef std::pair<const int, string_vector> sock_key_pair;
  784. BOOST_FOREACH(const sock_key_pair & p, sock_key_map)
  785. {
  786. send_(p.first, makecmd("DEL") << p.second);
  787. }
  788. int_type res = false;
  789. BOOST_FOREACH(const sock_key_pair & p, sock_key_map)
  790. {
  791. res += recv_int_reply_(p.first);
  792. }
  793. return res;
  794. }
  795. datatype type(const string_type & key)
  796. {
  797. int socket = get_socket(key);
  798. send_(socket, makecmd("TYPE") << key);
  799. std::string response = recv_single_line_reply_(socket);
  800. if(response == "none") return datatype_none;
  801. if(response == "string") return datatype_string;
  802. if(response == "list") return datatype_list;
  803. if(response == "set") return datatype_set;
  804. if(response == "zset") return datatype_zset;
  805. if(response == "hash") return datatype_hash;
  806. #ifndef NDEBUG
  807. std::cerr << "Got unknown datatype name: " << response << std::endl;
  808. #endif // NDEBUG
  809. return datatype_unknown;
  810. }
  811. int_type keys(const string_type & pattern, string_vector & out)
  812. {
  813. BOOST_FOREACH(const connection_data & con, connections_)
  814. {
  815. send_(con.socket, makecmd("KEYS") << pattern);
  816. }
  817. int_type res = 0;
  818. BOOST_FOREACH(const connection_data & con, connections_)
  819. {
  820. res += recv_multi_bulk_reply_(con.socket, out);
  821. }
  822. return res;
  823. }
  824. string_type randomkey()
  825. {
  826. int socket = connections_[0].socket;
  827. if( connections_.size() > 1 )
  828. {
  829. /*
  830. * Select a random server if there are more then one
  831. */
  832. boost::mt19937 gen;
  833. boost::posix_time::ptime now = boost::posix_time::microsec_clock::local_time();
  834. boost::posix_time::ptime epoch( boost::gregorian::date(1970, 1, 1) );
  835. gen.seed( (now-epoch).total_seconds() );
  836. boost::uniform_int<> dist(0, connections_.size()-1);
  837. boost::variate_generator< boost::mt19937&, boost::uniform_int<> > die(gen, dist);
  838. socket = connections_[die()].socket;
  839. }
  840. send_(socket, makecmd("RANDOMKEY") );
  841. return recv_bulk_reply_(socket);
  842. }
  843. /**
  844. * @warning Not cluster save (the old name and the new one must be on the same redis server)
  845. */
  846. void rename(const string_type & old_name, const string_type & new_name)
  847. {
  848. int source_socket = get_socket(old_name);
  849. int destin_socket = get_socket(new_name);
  850. if( source_socket != destin_socket )
  851. {
  852. switch( type(old_name) )
  853. {
  854. case datatype_none: // key doesn't exist
  855. return;
  856. case datatype_string:
  857. set(new_name, get(old_name));
  858. break;
  859. case datatype_list:
  860. {
  861. string_vector content;
  862. lrange(old_name, 0, -1, content);
  863. del(new_name);
  864. BOOST_FOREACH(const string_type & val, content)
  865. {
  866. rpush(new_name, val);
  867. }
  868. break;
  869. }
  870. case datatype_set:
  871. {
  872. string_set content;
  873. smembers(old_name, content);
  874. del(new_name);
  875. BOOST_FOREACH(const string_type & val, content)
  876. {
  877. sadd(new_name, val);
  878. }
  879. break;
  880. }
  881. case datatype_zset:
  882. case datatype_hash:
  883. case datatype_unknown:
  884. default:
  885. throw std::runtime_error("renaming is not supported for this datatype in cluster mode");
  886. }
  887. del(old_name);
  888. return;
  889. }
  890. send_(source_socket, makecmd("RENAME") << old_name << new_name);
  891. recv_ok_reply_(source_socket);
  892. }
  893. /**
  894. * @warning Not cluster save (the old name and the new one must be on the same redis server)
  895. */
  896. bool renamenx(const string_type & old_name, const string_type & new_name)
  897. {
  898. int source_socket = get_socket(old_name);
  899. int destin_socket = get_socket(new_name);
  900. if( source_socket != destin_socket )
  901. {
  902. if( exists(new_name) )
  903. return false;
  904. rename(old_name, new_name);
  905. return true;
  906. }
  907. send_(source_socket, makecmd("RENAMENX") << old_name << new_name);
  908. return recv_int_reply_(source_socket) == 1;
  909. }
  910. /**
  911. * @returns the number of keys in the currently selected database. In cluster mode the number
  912. * of keys in all currently selected databases is returned.
  913. */
  914. int_type dbsize()
  915. {
  916. int_type val = 0;
  917. BOOST_FOREACH(const connection_data & con, connections_)
  918. {
  919. send_(con.socket, makecmd("DBSIZE"));
  920. }
  921. BOOST_FOREACH(const connection_data & con, connections_)
  922. {
  923. val += recv_int_reply_(con.socket);
  924. }
  925. return val;
  926. }
  927. /**
  928. * @returns the number of keys in the currently selected database with the given connection.
  929. */
  930. int_type dbsize(const connection_data & con)
  931. {
  932. send_(con.socket, makecmd("DBSIZE"));
  933. return recv_int_reply_(con.socket);
  934. }
  935. void expire(const string_type & key, unsigned int secs)
  936. {
  937. int socket = get_socket(key);
  938. send_(socket, makecmd("EXPIRE") << key << secs);
  939. recv_int_ok_reply_(socket);
  940. }
  941. int ttl(const string_type & key)
  942. {
  943. int socket = get_socket(key);
  944. send_(socket, makecmd("TTL") << key);
  945. return recv_int_reply_(socket);
  946. }
  947. int_type rpush(const string_type & key,
  948. const string_type & value)
  949. {
  950. int socket = get_socket(key);
  951. send_(socket, makecmd("RPUSH") << key << value);
  952. return recv_int_reply_(socket);
  953. }
  954. int_type lpush(const string_type & key,
  955. const string_type & value)
  956. {
  957. int socket = get_socket(key);
  958. send_(socket, makecmd("LPUSH") << key << value);
  959. return recv_int_reply_(socket);
  960. }
  961. int_type llen(const string_type & key)
  962. {
  963. int socket = get_socket(key);
  964. send_(socket, makecmd("LLEN") << key);
  965. return recv_int_reply_(socket);
  966. }
  967. int_type lrange(const string_type & key,
  968. int_type start,
  969. int_type end,
  970. string_vector & out)
  971. {
  972. int socket = get_socket(key);
  973. send_(socket, makecmd("LRANGE") << key << start << end);
  974. return recv_multi_bulk_reply_(socket, out);
  975. }
  976. void ltrim(const string_type & key,
  977. int_type start,
  978. int_type end)
  979. {
  980. int socket = get_socket(key);
  981. send_(socket, makecmd("LTRIM") << key << start << end);
  982. recv_ok_reply_(socket);
  983. }
  984. string_type lindex(const string_type & key,
  985. int_type index)
  986. {
  987. int socket = get_socket(key);
  988. send_(socket, makecmd("LINDEX") << key << index);
  989. return recv_bulk_reply_(socket);
  990. }
  991. void lset(const string_type & key, int_type index, const string_type & value)
  992. {
  993. int socket = get_socket(key);
  994. send_(socket, makecmd("LSET") << key << index << value);
  995. recv_ok_reply_(socket);
  996. }
  997. int_type lrem(const string_type & key, int_type count, const string_type & value)
  998. {
  999. int socket = get_socket(key);
  1000. send_(socket, makecmd("LREM") << key << count << value);
  1001. return recv_int_reply_(socket);
  1002. }
  1003. string_type lpop(const string_type & key)
  1004. {
  1005. int socket = get_socket(key);
  1006. send_(socket, makecmd("LPOP") << key);
  1007. return recv_bulk_reply_(socket);
  1008. }
  1009. string_type rpop(const string_type & key)
  1010. {
  1011. int socket = get_socket(key);
  1012. send_(socket, makecmd("RPOP") << key);
  1013. return recv_bulk_reply_(socket);
  1014. }
  1015. /**
  1016. * @warning Not cluster save (all keys must be on the same redis server)
  1017. */
  1018. string_pair blpop(const string_vector & keys, int_type timeout_seconds = 0)
  1019. {
  1020. int socket = get_socket(keys);
  1021. if(socket == -1)
  1022. // How to do in cluster mode? Is reinserting of to much poped values a solution?
  1023. throw std::runtime_error("feature is not available in cluster mode");
  1024. send_(socket, makecmd("BLPOP") << keys << timeout_seconds);
  1025. string_vector sv;
  1026. try
  1027. {
  1028. recv_multi_bulk_reply_(socket, sv);
  1029. }
  1030. catch(key_error & e)
  1031. {
  1032. assert(timeout_seconds > 0);
  1033. throw timeout_error("could not pop value in time");
  1034. }
  1035. if(sv.size() == 2)
  1036. return make_pair( sv[0], sv[1] );
  1037. else
  1038. return make_pair( "", missing_value() );
  1039. }
  1040. string_type blpop(const string_type & key, int_type timeout_seconds = 0)
  1041. {
  1042. int socket = get_socket(key);
  1043. if(socket == -1)
  1044. // How to do in cluster mode? Is reinserting of to much poped values a solution?
  1045. throw std::runtime_error("feature is not available in cluster mode");
  1046. send_(socket, makecmd("BLPOP") << key << timeout_seconds);
  1047. string_vector sv;
  1048. try
  1049. {
  1050. recv_multi_bulk_reply_(socket, sv);
  1051. }
  1052. catch(key_error & e)
  1053. {
  1054. assert(timeout_seconds > 0);
  1055. return missing_value(); // should we throw a timeout_error?
  1056. // we set a timeout so we expect that this can happen
  1057. }
  1058. if(sv.size() == 2)
  1059. {
  1060. assert(key == sv[0]);
  1061. return sv[1];
  1062. }
  1063. else
  1064. return missing_value();
  1065. }
  1066. /**
  1067. * @warning Not cluster save (all keys must be on the same redis server)
  1068. */
  1069. string_pair brpop(const string_vector & keys, int_type timeout_seconds)
  1070. {
  1071. int socket = get_socket(keys);
  1072. makecmd m("BRPOP");
  1073. for(size_t i=0; i < keys.size(); i++)
  1074. m << keys[i];
  1075. m << timeout_seconds;
  1076. send_(socket, m);
  1077. string_vector sv;
  1078. try
  1079. {
  1080. recv_multi_bulk_reply_(socket, sv);
  1081. }
  1082. catch(key_error & e)
  1083. {
  1084. assert(timeout_seconds > 0);
  1085. return missing_value(); // should we throw a timeout_error?
  1086. // we set a timeout so we expect that this can happen
  1087. }
  1088. if(sv.size() == 2)
  1089. return make_pair( sv[0], sv[1] );
  1090. else
  1091. return make_pair( "", missing_value );
  1092. }
  1093. string_type brpop(const string_type & key, int_type timeout_seconds)
  1094. {
  1095. int socket = get_socket(key);
  1096. send_(socket, makecmd("BRPOP") << key << timeout_seconds);
  1097. string_vector sv;
  1098. try
  1099. {
  1100. recv_multi_bulk_reply_(socket, sv);
  1101. }
  1102. catch(key_error & e)
  1103. {
  1104. assert(timeout_seconds > 0);
  1105. return missing_value(); // should we throw a timeout_error?
  1106. // we set a timeout so we expect that this can happen
  1107. }
  1108. if(sv.size() == 2)
  1109. {
  1110. assert(key == sv[0]);
  1111. return sv[1];
  1112. }
  1113. else
  1114. return missing_value();
  1115. }
  1116. bool sadd(const string_type & key,
  1117. const string_type & value)
  1118. {
  1119. int socket = get_socket(key);
  1120. send_(socket, makecmd("SADD") << key << value);
  1121. return recv_int_reply_(socket) == 1;
  1122. }
  1123. template<typename ITERATOR>
  1124. int_type sadd(const string_type & key, ITERATOR begin, ITERATOR end)
  1125. {
  1126. int socket = get_socket(key);
  1127. std::string commands;
  1128. size_t count = 0;
  1129. while(begin != end)
  1130. {
  1131. string_type val = *begin++;
  1132. commands += makecmd("SADD") << key << val;
  1133. count++;
  1134. }
  1135. send_(socket, commands);
  1136. int_type res = 0;
  1137. for(size_t i=0; i < count; i++)
  1138. {
  1139. res += recv_int_reply_(socket);
  1140. }
  1141. return res;
  1142. }
  1143. void srem(const string_type & key,
  1144. const string_type & value)
  1145. {
  1146. int socket = get_socket(key);
  1147. send_(socket, makecmd("SREM") << key << value);
  1148. recv_int_ok_reply_(socket);
  1149. }
  1150. string_type spop(const string_type & key)
  1151. {
  1152. int socket = get_socket(key);
  1153. send_(socket, makecmd("SPOP") << key);
  1154. return recv_bulk_reply_(socket);
  1155. }
  1156. void smove(const string_type & srckey, const string_type & dstkey, const string_type & member)
  1157. {
  1158. int src_socket = get_socket(srckey);
  1159. int dst_socket = get_socket(dstkey);
  1160. if(dst_socket != src_socket)
  1161. {
  1162. srem(srckey, member);
  1163. sadd(dstkey, member);
  1164. return;
  1165. }
  1166. send_(src_socket, makecmd("SMOVE") << srckey << dstkey << member);
  1167. recv_int_ok_reply_(src_socket);
  1168. }
  1169. int_type scard(const string_type & key)
  1170. {
  1171. int socket = get_socket(key);
  1172. send_(socket, makecmd("SCARD") << key);
  1173. return recv_int_reply_(socket);
  1174. }
  1175. bool sismember(const string_type & key,
  1176. const string_type & value)
  1177. {
  1178. int socket = get_socket(key);
  1179. send_(socket, makecmd("SISMEMBER") << key << value);
  1180. return recv_int_reply_(socket) == 1;
  1181. }
  1182. /**
  1183. * @returns the intersection between the Sets stored at key1, key2, ..., keyN
  1184. * @warning Not cluster save (all keys must be on the same redis server)
  1185. */
  1186. int_type sinter(const string_vector & keys, string_set & out)
  1187. {
  1188. std::map<int, string_vector> per_server;
  1189. BOOST_FOREACH(const string_type & key, keys)
  1190. {
  1191. per_server[get_socket(key)].push_back(key);
  1192. }
  1193. size_t i = 0;
  1194. typedef std::pair<const int, string_vector> per_server_pair;
  1195. BOOST_FOREACH(const per_server_pair & p, per_server)
  1196. {
  1197. send_(p.first, makecmd("SINTER") << p.second);
  1198. }
  1199. BOOST_FOREACH(const per_server_pair & p, per_server)
  1200. {
  1201. string_set cur;
  1202. recv_multi_bulk_reply_(p.first, cur);
  1203. if(i > 0)
  1204. {
  1205. string_set prev = out;
  1206. out.clear();
  1207. std::set_intersection(prev.begin(), prev.end(), cur.begin(), cur.end(), std::inserter(out, out.end()));
  1208. }
  1209. else
  1210. {
  1211. out = cur;
  1212. }
  1213. i++;
  1214. }
  1215. return out.size();
  1216. }
  1217. /**
  1218. * @warning Not cluster save (all keys must be on the same redis server)
  1219. */
  1220. int_type sinterstore(const string_type & dstkey, const string_vector & keys)
  1221. {
  1222. int socket = get_socket(dstkey);
  1223. int source_sockets = get_socket(keys);
  1224. if(socket != source_sockets)
  1225. {
  1226. std::cerr << 0 << std::endl;
  1227. string_set content;
  1228. std::cerr << 1 << std::endl;
  1229. sinter(keys, content);
  1230. std::cerr << 2 << std::endl;
  1231. del(dstkey);
  1232. std::cerr << 3 << std::endl;
  1233. BOOST_FOREACH(const string_type & val, content)
  1234. {
  1235. std::cerr << 4 << std::endl;
  1236. sadd(dstkey, val);
  1237. }
  1238. std::cerr << 5 << std::endl;
  1239. return content.size();
  1240. }
  1241. send_(socket, makecmd("SINTERSTORE") << dstkey << keys);
  1242. return recv_int_reply_(socket);
  1243. }
  1244. int_type sunion(const string_vector & keys, string_set & out)
  1245. {
  1246. int socket = get_socket(keys);
  1247. if(socket == -1)
  1248. {
  1249. std::map< int, boost::optional<makecmd> > per_socket_keys;
  1250. BOOST_FOREACH(const string_type & key, keys)
  1251. {
  1252. boost::optional<makecmd> & optCmd = per_socket_keys[ get_socket(key) ];
  1253. if( !optCmd )
  1254. optCmd = makecmd("SUNION");
  1255. *optCmd << key;
  1256. }
  1257. typedef std::pair< const int, boost::optional<makecmd> > per_sock_pair;
  1258. BOOST_FOREACH(const per_sock_pair & p, per_socket_keys)
  1259. {
  1260. send_(p.first, *p.second);
  1261. }
  1262. BOOST_FOREACH(const per_sock_pair & p, per_socket_keys)
  1263. {
  1264. recv_multi_bulk_reply_(p.first, out);
  1265. }
  1266. return out.size();
  1267. }
  1268. send_(socket, makecmd("SUNION") << keys);
  1269. return recv_multi_bulk_reply_(socket, out);
  1270. }
  1271. int_type sunionstore(const string_type & dstkey,
  1272. const string_vector & keys)
  1273. {
  1274. int socket = get_socket(dstkey);
  1275. int source_sockets = get_socket(keys);
  1276. if(socket != source_sockets)
  1277. {
  1278. string_set content;
  1279. sunion(keys, content);
  1280. del(dstkey);
  1281. return sadd(dstkey, content.begin(), content.end());
  1282. }
  1283. send_(socket, makecmd("SUNIONSTORE") << dstkey << keys);
  1284. return recv_int_reply_(socket);
  1285. }
  1286. int_type sdiff(const string_vector & keys, string_set & out)
  1287. {
  1288. int socket = get_socket(keys);
  1289. send_(socket, makecmd("SDIFF") << keys);
  1290. return recv_multi_bulk_reply_(socket, out);
  1291. }
  1292. int_type sdiffstore(const string_type & dstkey, const string_vector & keys)
  1293. {
  1294. int socket = get_socket(dstkey);
  1295. int source_sockets = get_socket(keys);
  1296. if(socket != source_sockets)
  1297. throw std::runtime_error("not available in cluster mode");
  1298. send_(socket, makecmd("SDIFFSTORE") << dstkey << keys);
  1299. return recv_int_reply_(socket);
  1300. }
  1301. int_type smembers(const string_type & key, string_set & out)
  1302. {
  1303. int socket = get_socket(key);
  1304. send_(socket, makecmd("SMEMBERS") << key);
  1305. return recv_multi_bulk_reply_(socket, out);
  1306. }
  1307. string_type srandmember(const string_type & key)
  1308. {
  1309. int socket = get_socket(key);
  1310. send_(socket, makecmd("SPOP") << key);
  1311. return recv_bulk_reply_(socket);
  1312. }
  1313. void zadd(const string_type & key, double score, const string_type & member)
  1314. {
  1315. int socket = get_socket(key);
  1316. send_(socket, makecmd("ZADD") << key << score << member);
  1317. recv_int_ok_reply_(socket);
  1318. }
  1319. void zadd(const string_type & key, const string_score_pair & value)
  1320. {
  1321. zadd(key, value.second, value.first);
  1322. }
  1323. void zrem(const string_type & key, const string_type & member)
  1324. {
  1325. int socket = get_socket(key);
  1326. send_(socket, makecmd("ZREM") << key << member);
  1327. recv_int_ok_reply_(socket);
  1328. }
  1329. double zincrby(const string_type & key, const string_type & member, double increment)
  1330. {
  1331. int socket = get_socket(key);
  1332. send_(socket, makecmd("ZINCRBY") << key << increment << member);
  1333. return boost::lexical_cast<double>( recv_bulk_reply_(socket) );
  1334. }
  1335. int_type zrank(const string_type & key, const string_type & member)
  1336. {
  1337. int socket = get_socket(key);
  1338. send_(socket, makecmd("ZRANK") << key << member);
  1339. return recv_int_reply_(socket);
  1340. }
  1341. int_type zrevrank(const string_type & key, const string_type & value)
  1342. {
  1343. int socket = get_socket(key);
  1344. send_(socket, makecmd("ZREVRANK") << key << value);
  1345. return boost::lexical_cast<int_type>( recv_int_reply_(socket) );
  1346. }
  1347. void zrange(const string_type & key, int_type start, int_type end, string_vector & out)
  1348. {
  1349. int socket = get_socket(key);
  1350. send_( socket, makecmd("ZRANGE") << key << start << end );
  1351. recv_multi_bulk_reply_(socket, out);
  1352. }
  1353. private:
  1354. void convert(const string_vector & in, string_score_vector & out)
  1355. {
  1356. assert( in.size() % 2 == 0 );
  1357. for(size_t i=0; i < in.size(); i += 2)
  1358. {
  1359. const std::string & value = in[i];
  1360. const std::string & str_score = in[i+1];
  1361. double score = boost::lexical_cast<double>(str_score);
  1362. out.push_back( make_pair(value, score) );
  1363. }
  1364. }
  1365. public:
  1366. void zrange(const string_type & key, int_type start, int_type end, string_score_vector & out)
  1367. {
  1368. int socket = get_socket(key);
  1369. send_( socket, makecmd("ZRANGE") << key << start << end << "WITHSCORES" );
  1370. string_vector res;
  1371. recv_multi_bulk_reply_(socket, res);
  1372. convert(res, out);
  1373. }
  1374. void zrevrange(const string_type & key, int_type start, int_type end, string_vector & out)
  1375. {
  1376. int socket = get_socket(key);
  1377. send_( socket, makecmd("ZREVRANGE") << key << start << end );
  1378. recv_multi_bulk_reply_(socket, out);
  1379. }
  1380. void zrevrange(const string_type & key, int_type start, int_type end, string_score_vector & out)
  1381. {
  1382. int socket = get_socket(key);
  1383. send_( socket, makecmd("ZREVRANGE") << key << start << end << "WITHSCORES" );
  1384. string_vector res;
  1385. recv_multi_bulk_reply_(socket, res);
  1386. convert(res, out);
  1387. }
  1388. protected:
  1389. void zrangebyscore_base(bool withscores, const string_type & key, double min, double max, string_vector & out, int_type offset, int_type max_count, int range_modification)
  1390. {
  1391. int socket = get_socket(key);
  1392. std::string min_str, max_str;
  1393. if( range_modification & exclude_min )
  1394. min_str = "(";
  1395. if( range_modification & exclude_max )
  1396. max_str = "(";
  1397. min_str += boost::lexical_cast<std::string>(min);
  1398. max_str += boost::lexical_cast<std::string>(max);
  1399. makecmd m("ZRANGEBYSCORE");
  1400. m << key << min_str << max_str;
  1401. if(max_count != -1 || offset > 0)
  1402. {
  1403. std::cerr << "Adding limit: " << offset << " " << max_count << std::endl;
  1404. m << "LIMIT" << offset << max_count;
  1405. }
  1406. send_(socket, m);
  1407. recv_multi_bulk_reply_(socket, out);
  1408. }
  1409. public:
  1410. void zrangebyscore(const string_type & key, double min, double max, string_vector & out, int_type offset = 0, int_type max_count = -1, int range_modification = 0)
  1411. {
  1412. zrangebyscore_base(false, key, min, max, out, offset, max_count, range_modification);
  1413. }
  1414. void zrangebyscore(const string_type & key, double min, double max, string_score_vector & out, int_type offset = 0, int_type max_count = -1, int range_modification = 0)
  1415. {
  1416. string_vector res;
  1417. zrangebyscore_base(true, key, min, max, res, offset, max_count, range_modification);
  1418. convert(res, out);
  1419. }
  1420. int_type zcount(const string_type & key, double min, double max, int range_modification = 0)
  1421. {
  1422. int socket = get_socket(key);
  1423. std::string min_str, max_str;
  1424. if( range_modification & exclude_min )
  1425. min_str = "(";
  1426. if( range_modification & exclude_max )
  1427. max_str = "(";
  1428. min_str += boost::lexical_cast<std::string>(min);
  1429. max_str += boost::lexical_cast<std::string>(max);
  1430. send_(socket, makecmd("ZCOUNT") << key << min_str << max_str);
  1431. return recv_int_reply_(socket);
  1432. }
  1433. int_type zremrangebyrank( const string_type & key, int_type start, int_type end )
  1434. {
  1435. int socket = get_socket(key);
  1436. send_(socket, makecmd("ZREMRANGEBYRANK") << key << start << end);
  1437. return recv_int_reply_(socket);
  1438. }
  1439. int_type zremrangebyscore( const string_type& key, double min, double max )
  1440. {
  1441. int socket = get_socket(key);
  1442. send_(socket, makecmd("ZREMRANGEBYSCORE") << key << min << max);
  1443. return recv_int_reply_(socket);
  1444. }
  1445. int_type zcard( const string_type & key )
  1446. {
  1447. int socket = get_socket(key);
  1448. send_(socket, makecmd("ZCARD") << key);
  1449. return recv_int_reply_(socket);
  1450. }
  1451. double zscore( const string_type& key, const string_type& element )
  1452. {
  1453. int socket = get_socket(key);
  1454. send_(socket, makecmd("ZSCORE") << key << element);
  1455. return boost::lexical_cast<double>( recv_bulk_reply_(socket) );
  1456. }
  1457. int_type zunionstore( const string_type & dstkey, const string_vector & keys, const std::vector<double> & weights = std::vector<double>(), aggregate_type aggragate = aggregate_sum )
  1458. {
  1459. int dst_socket = get_socket(dstkey);
  1460. int socket = get_socket(keys);
  1461. if(socket != dst_socket)
  1462. throw std::runtime_error("feature is not available in cluster mode");
  1463. makecmd m("ZUNIONSTORE");
  1464. m << dstkey << keys.size() << keys;
  1465. if( weights.size() > 0 )
  1466. {
  1467. assert(keys.size() == weights.size());
  1468. m << "WEIGHTS" << weights;
  1469. }
  1470. m << "AGGREGATE";
  1471. switch(aggragate)
  1472. {
  1473. case aggregate_sum:
  1474. m << "SUM";
  1475. break;
  1476. case aggregate_min:
  1477. m << "MIN";
  1478. break;
  1479. case aggregate_max:
  1480. m << "MAX";
  1481. break;
  1482. default:
  1483. assert(false);
  1484. }
  1485. send_(socket, m);
  1486. return re

Large files files are truncated, but you can click here to view the full file