PageRenderTime 71ms 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
  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 recv_int_reply_(socket);
  1487. }
  1488. int_type zinterstore(const string_type & dstkey, const string_vector & keys, const std::vector<double> & weights = std::vector<double>(), aggregate_type aggragate = aggregate_sum )
  1489. {
  1490. int dst_socket = get_socket(dstkey);
  1491. int socket = get_socket(keys);
  1492. if(socket != dst_socket)
  1493. throw std::runtime_error("feature is not available in cluster mode");
  1494. makecmd m("ZINTERSTORE");
  1495. m << dstkey << keys.size() << keys;
  1496. if( weights.size() > 0 )
  1497. {
  1498. assert(keys.size() == weights.size());
  1499. m << "WEIGHTS" << weights;
  1500. }
  1501. m << "AGGREGATE";
  1502. switch(aggragate)
  1503. {
  1504. case aggregate_sum:
  1505. m << "SUM";
  1506. break;
  1507. case aggregate_min:
  1508. m << "MIN";
  1509. break;
  1510. case aggregate_max:
  1511. m << "MAX";
  1512. break;
  1513. default:
  1514. assert(false);
  1515. }
  1516. send_(socket, m);
  1517. return recv_int_reply_(socket);
  1518. }
  1519. bool hset( const string_type & key, const string_type & field, const string_type & value )
  1520. {
  1521. int socket = get_socket(key);
  1522. send_(socket, makecmd("HSET") << key << field << value);
  1523. return recv_int_reply_(socket) == 1;
  1524. }
  1525. string_type hget( const string_type & key, const string_type & field )
  1526. {
  1527. int socket = get_socket(key);
  1528. send_(socket, makecmd("HGET") << key << field);
  1529. return recv_bulk_reply_(socket);
  1530. }
  1531. bool hsetnx( const string_type & key, const string_type & field, const string_type & value )
  1532. {
  1533. int socket = get_socket(key);
  1534. send_(socket, makecmd("HSETNX") << key << field << value);
  1535. return recv_int_reply_(socket) == 1;
  1536. }
  1537. void hmset( const string_type & key, const string_vector & fields, const string_vector& values )
  1538. {
  1539. int socket = get_socket(key);
  1540. makecmd m("HMSET");
  1541. m << key;
  1542. assert( fields.size() == values.size() );
  1543. for(size_t i=0; i < fields.size(); i++)
  1544. m << fields[i] << values[i];
  1545. send_(socket, m);
  1546. recv_ok_reply_(socket);
  1547. }
  1548. void hmset( const string_type & key, const string_pair_vector & field_value_pairs )
  1549. {
  1550. int socket = get_socket(key);
  1551. makecmd m("HMSET");
  1552. m << key;
  1553. for(size_t i=0; i < field_value_pairs.size(); i++)
  1554. m << field_value_pairs[i].first << field_value_pairs[i].second;
  1555. send_(socket, m);
  1556. recv_ok_reply_(socket);
  1557. }
  1558. void hmget( const string_type & key, const string_vector & fields, string_vector & out)
  1559. {
  1560. int socket = get_socket(key);
  1561. makecmd m("HMGET");
  1562. m << key;
  1563. for(size_t i=0; i < fields.size(); i++)
  1564. m << fields[i];
  1565. send_(socket, m);
  1566. recv_multi_bulk_reply_(socket, out);
  1567. }
  1568. int_type hincrby( const string_type & key, const string_type & field, int_type by )
  1569. {
  1570. int socket = get_socket(key);
  1571. send_(socket, makecmd("HINCRBY") << key << field << by);
  1572. return recv_int_reply_(socket);
  1573. }
  1574. bool hexists( const string_type & key, const string_type & field )
  1575. {
  1576. int socket = get_socket(key);
  1577. send_(socket, makecmd("HEXISTS") << key << field);
  1578. return recv_int_reply_(socket) == 1;
  1579. }
  1580. bool hdel( const string_type& key, const string_type& field )
  1581. {
  1582. int socket = get_socket(key);
  1583. send_(socket, makecmd("HDEL") << key << field);
  1584. return recv_int_reply_(socket) == 1;
  1585. }
  1586. int_type hlen( const string_type & key )
  1587. {
  1588. int socket = get_socket(key);
  1589. send_(socket, makecmd("HLEN") << key);
  1590. return recv_int_reply_(socket);
  1591. }
  1592. void hkeys( const string_type & key, string_vector & out )
  1593. {
  1594. int socket = get_socket(key);
  1595. send_(socket, makecmd("HKEYS") << key);
  1596. recv_multi_bulk_reply_(socket, out);
  1597. }
  1598. void hvals( const string_type & key, string_vector & out )
  1599. {
  1600. int socket = get_socket(key);
  1601. send_(socket, makecmd("HVALS") << key);
  1602. recv_multi_bulk_reply_(socket, out);
  1603. }
  1604. void hgetall( const string_type & key, string_pair_vector & out )
  1605. {
  1606. int socket = get_socket(key);
  1607. send_(socket, makecmd("HGETALL") << key);
  1608. string_vector s;
  1609. recv_multi_bulk_reply_(socket, s);
  1610. for(size_t i = 0; i < s.size(); i+=2)
  1611. out.push_back( make_pair(s[i], s[i+1]) );
  1612. }
  1613. void select(int_type dbindex)
  1614. {
  1615. BOOST_FOREACH(const connection_data & con, connections_)
  1616. {
  1617. send_(con.socket, makecmd("SELECT") << dbindex);
  1618. }
  1619. BOOST_FOREACH(connection_data & con, connections_)
  1620. {
  1621. recv_ok_reply_(con.socket);
  1622. con.dbindex = dbindex;
  1623. }
  1624. }
  1625. void select(int_type dbindex, const connection_data & con)
  1626. {
  1627. int socket = con.socket;
  1628. send_(socket, makecmd("SELECT") << dbindex);
  1629. recv_ok_reply_(socket);
  1630. BOOST_FOREACH(connection_data & cur_con, connections_)
  1631. {
  1632. if( cur_con == con )
  1633. cur_con.dbindex = dbindex;
  1634. }
  1635. }
  1636. void move(const string_type & key,
  1637. int_type dbindex)
  1638. {
  1639. int socket = get_socket(key);
  1640. send_(socket, makecmd("MOVE") << key << dbindex);
  1641. recv_int_ok_reply_(socket);
  1642. }
  1643. void flushdb()
  1644. {
  1645. BOOST_FOREACH(const connection_data & con, connections_)
  1646. {
  1647. send_(con.socket, makecmd("FLUSHDB"));
  1648. }
  1649. BOOST_FOREACH(const connection_data & con, connections_)
  1650. {
  1651. recv_ok_reply_(con.socket);
  1652. }
  1653. }
  1654. void flushdb(const connection_data & con)
  1655. {
  1656. int socket = con.socket;
  1657. send_(socket, makecmd("FLUSHDB"));
  1658. recv_ok_reply_(socket);
  1659. }
  1660. void flushall()
  1661. {
  1662. if( connections_.size() > 1 )
  1663. throw std::runtime_error("feature is not available in cluster mode");
  1664. int socket = connections_[0].socket;
  1665. send_(socket, makecmd("FLUSHALL"));
  1666. recv_ok_reply_(socket);
  1667. }
  1668. void flushall(const connection_data & con)
  1669. {
  1670. int socket = con.socket;
  1671. send_(socket, makecmd("FLUSHALL"));
  1672. recv_ok_reply_(socket);
  1673. }
  1674. int_type sort(const string_type & key,
  1675. string_vector & out,
  1676. sort_order order = sort_order_ascending,
  1677. bool lexicographically = false)
  1678. {
  1679. int socket = get_socket(key);
  1680. makecmd m("SORT");
  1681. m << key << (order == sort_order_ascending ? "ASC" : "DESC");
  1682. if(lexicographically)
  1683. m << "ALPHA";
  1684. send_(socket, m);
  1685. return recv_multi_bulk_reply_(socket, out);
  1686. }
  1687. int_type sort(const string_type & key,
  1688. string_vector & out,
  1689. int_type limit_start,
  1690. int_type limit_end,
  1691. sort_order order = sort_order_ascending,
  1692. bool lexicographically = false)
  1693. {
  1694. makecmd m("SORT");
  1695. m << key
  1696. << "LIMIT"
  1697. << limit_start
  1698. << limit_end
  1699. << (order == sort_order_ascending ? "ASC" : "DESC");
  1700. if(lexicographically)
  1701. m << "ALPHA";
  1702. send_(m);
  1703. return recv_multi_bulk_reply_(out);
  1704. }
  1705. int_type sort(const string_type & key,
  1706. string_vector & out,
  1707. const string_type & by_pattern,
  1708. int_type limit_start,
  1709. int_type limit_end,
  1710. const string_vector & get_patterns,
  1711. sort_order order = sort_order_ascending,
  1712. bool lexicographically = false)
  1713. {
  1714. int socket = get_socket(key);
  1715. makecmd m("SORT");
  1716. m << key
  1717. << "BY" << by_pattern
  1718. << "LIMIT" << limit_start << limit_end;
  1719. string_vector::const_iterator it = get_patterns.begin();
  1720. for ( ; it != get_patterns.end(); ++it)
  1721. m << "GET" << *it;
  1722. m << (order == sort_order_ascending ? "ASC" : "DESC");
  1723. if(lexicographically)
  1724. m << "ALPHA";
  1725. send_(socket, m);
  1726. return recv_multi_bulk_reply_(socket, out);
  1727. }
  1728. void save()
  1729. {
  1730. BOOST_FOREACH(const connection_data & con, connections_)
  1731. {
  1732. send_(con.socket, makecmd("SAVE"));
  1733. }
  1734. BOOST_FOREACH(const connection_data & con, connections_)
  1735. {
  1736. recv_ok_reply_(con.socket);
  1737. }
  1738. }
  1739. void save(const connection_data & con)
  1740. {
  1741. send_(con.socket, makecmd("SAVE"));
  1742. recv_ok_reply_(con.socket);
  1743. }
  1744. void bgsave()
  1745. {
  1746. BOOST_FOREACH(const connection_data & con, connections_)
  1747. {
  1748. send_(con.socket, makecmd("BGSAVE"));
  1749. }
  1750. BOOST_FOREACH(const connection_data & con, connections_)
  1751. {
  1752. std::string reply = recv_single_line_reply_(con.socket);
  1753. if(reply != REDIS_STATUS_REPLY_OK && reply != "Background saving started")
  1754. throw protocol_error("Unexpected response on bgsave: '" + reply + "'");
  1755. }
  1756. }
  1757. void bgsave(const connection_data & con)
  1758. {
  1759. send_(con.socket, makecmd("BGSAVE"));
  1760. std::string reply = recv_single_line_reply_(con.socket);
  1761. if(reply != REDIS_STATUS_REPLY_OK && reply != "Background saving started")
  1762. throw protocol_error("Unexpected response on bgsave: '" + reply + "'");
  1763. }
  1764. time_t lastsave()
  1765. {
  1766. time_t res = 0;
  1767. BOOST_FOREACH(const connection_data & con, connections_)
  1768. {
  1769. int socket = con.socket;
  1770. send_(socket, makecmd("LASTSAVE"));
  1771. time_t cur = recv_int_reply_(socket);
  1772. if(res > 0)
  1773. res = std::min(cur, res);
  1774. else
  1775. res = cur;
  1776. }
  1777. return res;
  1778. }
  1779. time_t lastsave(const connection_data & con)
  1780. {
  1781. send_(con.socket, makecmd("LASTSAVE"));
  1782. return recv_int_reply_(con.socket);
  1783. }
  1784. void shutdown()
  1785. {
  1786. BOOST_FOREACH(const connection_data & con, connections_)
  1787. {
  1788. int socket = con.socket;
  1789. send_(socket, makecmd("SHUTDOWN"));
  1790. // we expected to get a connection_error as redis closes the connection on shutdown command.
  1791. try
  1792. {
  1793. recv_ok_reply_(socket);
  1794. }
  1795. catch (connection_error & e)
  1796. {
  1797. }
  1798. }
  1799. }
  1800. void shutdown(const connection_data & con)
  1801. {
  1802. send_(con.socket, makecmd("SHUTDOWN"));
  1803. // we expected to get a connection_error as redis closes the connection on shutdown command.
  1804. try
  1805. {
  1806. recv_ok_reply_(con.socket);
  1807. }
  1808. catch (connection_error & e)
  1809. {
  1810. }
  1811. }
  1812. void info(const connection_data & con, server_info & out)
  1813. {
  1814. int socket = con.socket;
  1815. send_(socket, makecmd("INFO"));
  1816. std::string response = recv_bulk_reply_(socket);
  1817. if (response.empty())
  1818. throw protocol_error("empty");
  1819. string_vector lines;
  1820. split_lines(response, lines);
  1821. if (lines.empty())
  1822. throw protocol_error("empty line for info");
  1823. for(string_vector::const_iterator it = lines.begin(); it != lines.end(); ++it)
  1824. {
  1825. const std::string & line = *it;
  1826. if( line.empty() || line[0] == '#' ) // Don't throw protocol_error on empty and comment lines
  1827. continue;
  1828. string_vector line_parts;
  1829. split(line, ':', line_parts);
  1830. if (line_parts.size() != 2)
  1831. throw protocol_error("unexpected line format for info");
  1832. const std::string & key = line_parts[0];
  1833. const std::string & val = line_parts[1];
  1834. out.param_map[key] = val;
  1835. if (key == "redis_version")
  1836. out.version = val;
  1837. else if (key == "bgsave_in_progress")
  1838. out.bgsave_in_progress = boost::lexical_cast<unsigned long>(val) == 1;
  1839. else if (key == "connected_clients")
  1840. out.connected_clients = boost::lexical_cast<unsigned long>(val);
  1841. else if (key == "connected_slaves")
  1842. out.connected_slaves = boost::lexical_cast<unsigned long>(val);
  1843. else if (key == "used_memory")
  1844. out.used_memory = boost::lexical_cast<unsigned long>(val);
  1845. else if (key == "changes_since_last_save")
  1846. out.changes_since_last_save = boost::lexical_cast<unsigned long>(val);
  1847. else if (key == "last_save_time")
  1848. out.last_save_time = boost::lexical_cast<unsigned long>(val);
  1849. else if (key == "total_connections_received")
  1850. out.total_connections_received = boost::lexical_cast<unsigned long>(val);
  1851. else if (key == "total_commands_processed")
  1852. out.total_commands_processed = boost::lexical_cast<unsigned long>(val);
  1853. else if (key == "uptime_in_seconds")
  1854. out.uptime_in_seconds = boost::lexical_cast<unsigned long>(val);
  1855. else if (key == "uptime_in_days")
  1856. out.uptime_in_days = boost::lexical_cast<unsigned long>(val);
  1857. else if (key == "role")
  1858. out.role = val == "master" ? role_master : role_slave;
  1859. else if (key == "arch_bits")
  1860. out.arch_bits = boost::lexical_cast<unsigned short>(val);
  1861. else if (key == "multiplexing_api")
  1862. out.multiplexing_api = val;
  1863. #ifndef NDEBUG // Ignore new/unknown keys in release mode
  1864. else
  1865. std::cerr << "Found unknown info key '" << key << "'" << std::endl;
  1866. #endif // NDEBUG
  1867. }
  1868. }
  1869. void info(server_info & out)
  1870. {
  1871. info(connections_[0], out);
  1872. }
  1873. int_type publish(const string_type & channel, const string_type & message)
  1874. {
  1875. int socket = get_socket(channel);
  1876. send_(socket, makecmd("PUBLISH") << channel << message);
  1877. return recv_int_reply_(socket);
  1878. }
  1879. #if 0 // currently unuseable
  1880. struct subscription_t
  1881. {
  1882. string_type channel;
  1883. boost::function<void (const string_type &)> callback;
  1884. };
  1885. void subscribe(const string_type & channel)
  1886. {
  1887. int socket = get_socket(channel);
  1888. }
  1889. #endif // 0 // currently unuseable
  1890. private:
  1891. base_client(const base_client &);
  1892. base_client & operator=(const base_client &);
  1893. void send_(int socket, const std::string & msg)
  1894. {
  1895. #ifndef NDEBUG
  1896. //output_proto_debug(msg, false);
  1897. #endif
  1898. if (anetWrite(socket, const_cast<char *>(msg.data()), msg.size()) == -1)
  1899. throw connection_error(strerror(errno));
  1900. }
  1901. std::string recv_single_line_reply_(int socket)
  1902. {
  1903. std::string line = read_line(socket);
  1904. #ifndef NDEBUG
  1905. //output_proto_debug(line);
  1906. #endif
  1907. if (line.empty())
  1908. throw protocol_error("empty single line reply");
  1909. if (line.find(REDIS_PREFIX_STATUS_REPLY_ERROR) == 0)
  1910. {
  1911. std::string error_msg = line.substr( strlen(REDIS_PREFIX_STATUS_REPLY_ERROR) );
  1912. if (error_msg.empty())
  1913. error_msg = "unknown error";
  1914. throw protocol_error(error_msg);
  1915. }
  1916. if (line[0] != REDIS_PREFIX_STATUS_REPLY_VALUE)
  1917. throw protocol_error("unexpected prefix for status reply");
  1918. return line.substr(1);
  1919. }
  1920. void recv_ok_reply_(int socket)
  1921. {
  1922. if (recv_single_line_reply_(socket) != REDIS_STATUS_REPLY_OK)
  1923. throw protocol_error("expected OK response");
  1924. }
  1925. int_type recv_bulk_reply_(int socket, char prefix)
  1926. {
  1927. std::string line = read_line(socket);
  1928. #ifndef NDEBUG
  1929. //output_proto_debug(line);
  1930. #endif
  1931. if (line[0] != prefix)
  1932. {
  1933. #ifndef NDEBUG
  1934. std::cerr << "unexpected prefix for bulk reply (expected '" << prefix << "' but got '" << line[0] << "')" << std::endl;
  1935. #endif // NDEBUG
  1936. throw protocol_error("unexpected prefix for bulk reply");
  1937. }
  1938. return boost::lexical_cast<int_type>(line.substr(1));
  1939. }
  1940. std::string recv_bulk_reply_(int socket)
  1941. {
  1942. int_type length = recv_bulk_reply_(socket, REDIS_PREFIX_SINGLE_BULK_REPLY );
  1943. if (length == -1)
  1944. return missing_value();
  1945. int_type real_length = length + 2; // CRLF
  1946. std::string data = read_n(socket, real_length);
  1947. #ifndef NDEBUG
  1948. //output_proto_debug(data.substr(0, data.length()-2));
  1949. #endif
  1950. if (data.empty())
  1951. throw protocol_error("invalid bulk reply data; empty");
  1952. if (data.length() != static_cast<std::string::size_type>(real_length))
  1953. throw protocol_error("invalid bulk reply data; data of unexpected length");
  1954. data.erase(data.size() - 2);
  1955. return data;
  1956. }
  1957. int_type recv_multi_bulk_reply_(int socket, string_vector & out)
  1958. {
  1959. int_type length = recv_bulk_reply_(socket, REDIS_PREFIX_MULTI_BULK_REPLY);
  1960. if (length == -1)
  1961. throw key_error("no such key");
  1962. out.reserve( out.size()+length );
  1963. for (int_type i = 0; i < length; ++i)
  1964. out.push_back(recv_bulk_reply_(socket));
  1965. return length;
  1966. }
  1967. int_type recv_multi_bulk_reply_(int socket, string_set & out)
  1968. {
  1969. int_type length = recv_bulk_reply_(socket, REDIS_PREFIX_MULTI_BULK_REPLY);
  1970. if (length == -1)
  1971. throw key_error("no such key");
  1972. for (int_type i = 0; i < length; ++i)
  1973. out.insert(recv_bulk_reply_(socket));
  1974. return length;
  1975. }
  1976. template<typename INT_TYPE>
  1977. INT_TYPE recv_int_reply_(int socket)
  1978. {
  1979. std::string line = read_line(socket);
  1980. #ifndef NDEBUG
  1981. //output_proto_debug(line);
  1982. #endif
  1983. if (line.empty())
  1984. throw protocol_error("invalid integer reply; empty");
  1985. if (line[0] != REDIS_PREFIX_INT_REPLY)
  1986. throw protocol_error("unexpected prefix for integer reply");
  1987. return boost::lexical_cast<INT_TYPE>(line.substr(1));
  1988. }
  1989. int_type recv_int_reply_(int socket)
  1990. {
  1991. std::string line = read_line(socket);
  1992. #ifndef NDEBUG
  1993. //output_proto_debug(line);
  1994. #endif
  1995. if (line.empty())
  1996. throw protocol_error("invalid integer reply; empty");
  1997. if (line[0] != REDIS_PREFIX_INT_REPLY)
  1998. throw protocol_error("unexpected prefix for integer reply");
  1999. return boost::lexical_cast<int_type>(line.substr(1));
  2000. }
  2001. void recv_int_ok_reply_(int socket)
  2002. {
  2003. if (recv_int_reply_(socket) != 1)
  2004. throw protocol_error("expecting int reply of 1");
  2005. }
  2006. inline int get_socket(const string_type & key)
  2007. {
  2008. size_t con_count = connections_.size();
  2009. if(con_count == 1)
  2010. return connections_[0].socket;
  2011. size_t idx = hasher_( key, static_cast<const std::vector<connection_data> &>(connections_) );
  2012. return connections_[idx].socket;
  2013. }
  2014. int get_socket(const string_vector & keys)
  2015. {
  2016. assert( !keys.empty() );
  2017. if( connections_.size() == 1 )
  2018. return connections_[0].socket;
  2019. int socket = -1;
  2020. for(size_t i=0; i < keys.size(); i++)
  2021. {
  2022. int cur_socket = get_socket(keys[i]);
  2023. if(i > 0 && socket != cur_socket)
  2024. return -1;
  2025. //throw std::runtime_error("not possible in cluster mode");
  2026. socket = cur_socket;
  2027. }
  2028. return socket;
  2029. }
  2030. #ifndef NDEBUG
  2031. void output_proto_debug(const std::string & data, bool is_received = true)
  2032. {
  2033. std::string escaped_data(data);
  2034. size_t pos;
  2035. while ((pos = escaped_data.find("\n")) != std::string::npos)
  2036. escaped_data.replace(pos, 1, "\\n");
  2037. while ((pos = escaped_data.find("\r")) != std::string::npos)
  2038. escaped_data.replace(pos, 1, "\\r");
  2039. std::cerr << time(NULL) << ": "
  2040. << (is_received ? "RECV '" : "SEND '")
  2041. << escaped_data
  2042. << "'"
  2043. << std::endl;
  2044. }
  2045. #endif
  2046. std::vector<std::string>::size_type split(const std::string & str, char delim, std::vector<std::string> & elems)
  2047. {
  2048. std::stringstream ss(str);
  2049. std::string item;
  2050. std::vector<std::string>::size_type n = 0;
  2051. while (getline(ss, item, delim))
  2052. {
  2053. elems.push_back(item);
  2054. ++n;
  2055. }
  2056. return n;
  2057. }
  2058. inline std::string & rtrim(std::string & str, const std::string & ws = REDIS_WHITESPACE)
  2059. {
  2060. std::string::size_type pos = str.find_last_not_of(ws);
  2061. str.erase(pos + 1);
  2062. return str;
  2063. }
  2064. inline void split_lines(const std::string & str, std::vector<std::string> & elems)
  2065. {
  2066. split(str, '\n', elems);
  2067. for (std::vector<std::string>::iterator it = elems.begin(); it != elems.end(); ++it)
  2068. rtrim(*it);
  2069. }
  2070. // Reads N bytes from given blocking socket.
  2071. std::string read_n(int socket, ssize_t n)
  2072. {
  2073. // changed char* to vector<char> buffer to don't leak memory on exceptions (and also because I hate this delete stuff)
  2074. // C++0x TODO: use a std::string here and it's non-const data() member instead of the vector<char> indirection
  2075. std::vector<char> buffer(n);
  2076. char* buf_start = &buffer[0];
  2077. char* bp = buf_start;
  2078. ssize_t bytes_read = 0;
  2079. while (bytes_read != n)
  2080. {
  2081. ssize_t bytes_received = recv_or_throw(socket, bp, n - (bp - buf_start), 0);
  2082. bytes_read += bytes_received;
  2083. bp += bytes_received;
  2084. }
  2085. return std::string( buf_start, n );
  2086. }
  2087. reply_t next_reply_type(int socket)
  2088. {
  2089. char reply_prefix[1];
  2090. recv_or_throw(socket, reply_prefix, 1, MSG_PEEK);
  2091. switch( reply_prefix[0] )
  2092. {
  2093. case REDIS_PREFIX_STATUS_REPLY_VALUE:
  2094. return status_code_reply;
  2095. case REDIS_PREFIX_STATUS_REPLY_ERR_C:
  2096. return error_reply;
  2097. case REDIS_PREFIX_INT_REPLY:
  2098. return int_reply;
  2099. case REDIS_PREFIX_SINGLE_BULK_REPLY:
  2100. return bulk_reply;
  2101. case REDIS_PREFIX_MULTI_BULK_REPLY:
  2102. return multi_bulk_reply;
  2103. }
  2104. throw std::runtime_error("invalid/unknown rely type from redis server");
  2105. }
  2106. reply_data_t recv_generic_reply_(int socket)
  2107. {
  2108. reply_data_t res;
  2109. res.first = next_reply_type(socket);
  2110. switch( res.first )
  2111. {
  2112. case status_code_reply:
  2113. res.second = read_line(socket).substr(1);
  2114. break;
  2115. case error_reply:
  2116. res.second = read_line(socket).substr(strlen(REDIS_PREFIX_STATUS_REPLY_ERROR));
  2117. break;
  2118. case int_reply:
  2119. res.second = recv_int_reply_(socket);
  2120. break;
  2121. case bulk_reply:
  2122. res.second = recv_bulk_reply_(socket);
  2123. break;
  2124. case multi_bulk_reply:
  2125. {
  2126. string_vector v;
  2127. recv_multi_bulk_reply_( socket, v );
  2128. res.second = v;
  2129. break;
  2130. }
  2131. case no_reply:
  2132. assert(false);
  2133. }
  2134. return res;
  2135. }
  2136. // Reads a single line of character data from the given blocking socket.
  2137. // Returns the line that was read, not including EOL delimiter(s). Both LF
  2138. // ('\n') and CRLF ("\r\n") delimiters are supported. If there was an I/O
  2139. // error reading from the socket, connection_error is raised. If max_size
  2140. // bytes are read before finding an EOL delimiter, a blank string is
  2141. // returned.
  2142. std::string read_line(int socket, ssize_t max_size = 2048)
  2143. {
  2144. assert(socket > 0);
  2145. assert(max_size > 0);
  2146. std::ostringstream oss;
  2147. enum { buffer_size = 64 };
  2148. char buffer[buffer_size];
  2149. memset(buffer, 0, buffer_size);
  2150. ssize_t total_bytes_read = 0;
  2151. bool found_delimiter = false;
  2152. while (total_bytes_read < max_size && !found_delimiter)
  2153. {
  2154. // Peek at what's available.
  2155. ssize_t bytes_received = recv_or_throw(socket, buffer, buffer_size, MSG_PEEK);
  2156. // Some data is available; Length might be < buffer_size.
  2157. // Look for newline in whatever was read though.
  2158. char * eol = static_cast<char *>(memchr(buffer, '\n', bytes_received));
  2159. // If found, write data from the buffer to the output string.
  2160. // Else, write the entire buffer and continue reading more data.
  2161. ssize_t to_read = bytes_received;
  2162. if (eol)
  2163. {
  2164. to_read = eol - buffer + 1;
  2165. oss.write(buffer, to_read);
  2166. found_delimiter = true;
  2167. }
  2168. else
  2169. oss.write(buffer, bytes_received);
  2170. // Now read from the socket to remove the peeked data from the socket's
  2171. // read buffer. This will not block since we've peeked already and know
  2172. // there's data waiting. It might fail if we were interrupted however.
  2173. bytes_received = recv_or_throw(socket, buffer, to_read, 0);
  2174. }
  2175. // Construct final line string. Remove trailing CRLF-based whitespace.
  2176. std::string line = oss.str();
  2177. return rtrim(line, REDIS_LBR);
  2178. }
  2179. private:
  2180. std::vector<connection_data> connections_;
  2181. //int socket_;
  2182. CONSISTENT_HASHER hasher_;
  2183. };
  2184. struct default_hasher
  2185. {
  2186. inline size_t operator()(const std::string & key, const std::vector<connection_data> & connections)
  2187. {
  2188. return boost::hash<std::string>()(key) % connections.size();
  2189. }
  2190. };
  2191. typedef base_client<default_hasher> client;
  2192. class distributed_value
  2193. {
  2194. protected:
  2195. explicit distributed_value(const client::string_type & key, client & client_conn)
  2196. : client_conn_(&client_conn),
  2197. key_(key)
  2198. {
  2199. }
  2200. public:
  2201. virtual ~distributed_value()
  2202. {
  2203. }
  2204. inline const client::string_type & key() const
  2205. {
  2206. return key_;
  2207. }
  2208. bool exists() const
  2209. {
  2210. return client_conn_->exists(key_);
  2211. }
  2212. void del()
  2213. {
  2214. client_conn_->del(key_);
  2215. }
  2216. void rename(const client::string_type & new_name)
  2217. {
  2218. client_conn_->rename(key_, new_name);
  2219. key_ = new_name;
  2220. }
  2221. bool renamenx(const client::string_type & new_name)
  2222. {
  2223. if( client_conn_->renamenx(key_, new_name) )
  2224. {
  2225. key_ = new_name;
  2226. return true;
  2227. }
  2228. return false;
  2229. }
  2230. void expire(unsigned int secs)
  2231. {
  2232. client_conn_->expire(key_, secs);
  2233. }
  2234. int ttl() const
  2235. {
  2236. return client_conn_->ttl(key_);
  2237. }
  2238. void move(client::int_type dbindex)
  2239. {
  2240. client_conn_->move(key_, dbindex);
  2241. }
  2242. client::datatype type() const
  2243. {
  2244. return client_conn_->type(key_);
  2245. }
  2246. protected:
  2247. redis::client* client_conn_;
  2248. private:
  2249. distributed_value & operator=(const distributed_value &)
  2250. {
  2251. return *this;
  2252. }
  2253. client::string_type key_;
  2254. };
  2255. class distributed_string : public distributed_value
  2256. {
  2257. public:
  2258. explicit distributed_string(const client::string_type & key, client & client_conn)
  2259. : distributed_value(key, client_conn)
  2260. {
  2261. }
  2262. distributed_string(const client::string_type & key, const client::string_type & default_value, redis::client & client_conn)
  2263. : distributed_value(key, client_conn)
  2264. {
  2265. setnx(default_value);
  2266. }
  2267. operator client::string_type() const
  2268. {
  2269. return client_conn_->get(key());
  2270. }
  2271. inline client::string_type str() const
  2272. {
  2273. return *this;
  2274. }
  2275. distributed_string & operator=(const client::string_type & value)
  2276. {
  2277. client_conn_->set(key(), value);
  2278. return *this;
  2279. }
  2280. distributed_string & operator=(const distributed_string & other_str)
  2281. {
  2282. if( key() != other_str.key() )
  2283. *this = other_str.str();
  2284. return *this;
  2285. }
  2286. client::string_type getset(const client::string_type & new_value)
  2287. {
  2288. return client_conn_->getset(key(), new_value);
  2289. }
  2290. bool setnx(const client::string_type & value)
  2291. {
  2292. return client_conn_->setnx(key(), value);
  2293. }
  2294. void setex(const client::string_type & value, unsigned int secs)
  2295. {
  2296. client_conn_->setex(key(), value, secs);
  2297. }
  2298. size_t append(const client::string_type & value)
  2299. {
  2300. return client_conn_->append(key(), value);
  2301. }
  2302. distributed_string & operator+=(const client::string_type & value)
  2303. {
  2304. append(value);
  2305. return *this;
  2306. }
  2307. client::string_type substr(int start, int end) const
  2308. {
  2309. return client_conn_->substr(key(), start, end);
  2310. }
  2311. };
  2312. template<typename INT_TYPE>
  2313. class distributed_base_int : public distributed_value
  2314. {
  2315. private:
  2316. BOOST_STATIC_ASSERT( std::numeric_limits<INT_TYPE>::is_integer );
  2317. public:
  2318. typedef INT_TYPE int_type;
  2319. explicit distributed_base_int(const client::string_type & key, client & client_conn)
  2320. : distributed_value(key, client_conn)
  2321. {
  2322. }
  2323. distributed_base_int(const client::string_type & key, int_type default_value, client & client_conn)
  2324. : distributed_value(key, client_conn)
  2325. {
  2326. setnx(default_value);
  2327. }
  2328. distributed_base_int & operator=(int_type val)
  2329. {
  2330. client_conn_->set(key(), boost::lexical_cast<client::string_type>(val));
  2331. return *this;
  2332. }
  2333. distributed_base_int & operator=(const distributed_base_int & other)
  2334. {
  2335. if(key() != other.key())
  2336. client_conn_->set(key(), boost::lexical_cast<client::string_type>(other.to_int()));
  2337. return *this;
  2338. }
  2339. operator int_type() const
  2340. {
  2341. return to_int_type( client_conn_->get(key()) );
  2342. }
  2343. int_type to_int() const
  2344. {
  2345. return *this;
  2346. }
  2347. bool setnx(const int_type & value)
  2348. {
  2349. return client_conn_->setnx(key(), boost::lexical_cast<client::string_type>(value) );
  2350. }
  2351. void setex(const int_type & value, unsigned int secs)
  2352. {
  2353. client_conn_->setex(key(), boost::lexical_cast<client::string_type>(value), secs);
  2354. }
  2355. int_type operator++()
  2356. {
  2357. return client_conn_->incr<int_type>(key());
  2358. }
  2359. int_type operator++(int)
  2360. {
  2361. return client_conn_->incr<int_type>(key()) - 1;
  2362. }
  2363. int_type operator--()
  2364. {
  2365. return client_conn_->decr<int_type>(key());
  2366. }
  2367. int_type operator--(int)
  2368. {
  2369. return client_conn_->decr<int_type>(key()) + 1;
  2370. }
  2371. int_type operator+=(int_type val)
  2372. {
  2373. return client_conn_->incrby<int_type>(key(), val);
  2374. }
  2375. int_type operator-=(int_type val)
  2376. {
  2377. return client_conn_->decrby<int_type>(key(), val);
  2378. }
  2379. private:
  2380. static int_type to_int_type(const client::string_type & val)
  2381. {
  2382. try
  2383. {
  2384. return boost::lexical_cast<int_type>( val );
  2385. }
  2386. catch(boost::bad_lexical_cast & e)
  2387. {
  2388. throw value_error("value is not of integer type");
  2389. }
  2390. }
  2391. };
  2392. typedef distributed_base_int<short> distributed_short;
  2393. typedef distributed_base_int<ushort> distributed_ushort;
  2394. typedef distributed_base_int<int> distributed_int;
  2395. typedef distributed_base_int<uint> distributed_uint;
  2396. typedef distributed_base_int<long> distributed_long;
  2397. typedef distributed_base_int<ulong> distributed_ulong;
  2398. // TODO: lexical_cast treats int8_t/uint8_t as char/uchar
  2399. //typedef distributed_base_int<boost::int8_t> distributed_int8;
  2400. //typedef distributed_base_int<boost::uint8_t> distributed_uint8;
  2401. typedef distributed_base_int<boost::int16_t> distributed_int16;
  2402. typedef distributed_base_int<boost::uint16_t> distributed_uint16;
  2403. typedef distributed_base_int<boost::int32_t> distributed_int32;
  2404. typedef distributed_base_int<boost::uint32_t> distributed_uint32;
  2405. #ifndef BOOST_NO_INT64_T
  2406. typedef distributed_base_int<boost::int64_t> distributed_longlong;
  2407. typedef distributed_base_int<boost::uint64_t> distributed_ulonglong;
  2408. typedef distributed_base_int<boost::int64_t> distributed_int64;
  2409. typedef distributed_base_int<boost::uint64_t> distributed_uint64;
  2410. #endif // BOOST_NO_INT64_T
  2411. #if 0
  2412. // not yet working correctly!
  2413. /**
  2414. * This class provides a subset of the functionality that is provided by distributed_int.
  2415. * As it provides only atomic features and is limited to the things that are required to work without
  2416. * a sequence in redis it is harder to missuse the distributed sequence than it is to missuse shared_int.
  2417. */
  2418. template<typename INT_TYPE>
  2419. class distributed_base_sequence
  2420. {
  2421. public:
  2422. distributed_base_sequence(const client::string_type & name, client & con)
  2423. : shr_int_(name, con)
  2424. {
  2425. }
  2426. distributed_base_sequence(const client::string_type & name, INT_TYPE initial_value, client & con)
  2427. : shr_int_(name, initial_value, con)
  2428. {
  2429. }
  2430. /**
  2431. * Gets the next free value from the sequence. If no initial_value is given, this starts with 0.
  2432. */
  2433. INT_TYPE get_next_value()
  2434. {
  2435. return cur_val_ = shr_int_++;
  2436. }
  2437. INT_TYPE get_global_max_value() const
  2438. {
  2439. return shr_int_-1; // -1 because we work with post increment
  2440. }
  2441. inline INT_TYPE get_current_local_value() const
  2442. {
  2443. assert(cur_val_); // You can not call get_current_local_value if you have not called get_next_value
  2444. return *cur_val_;
  2445. }
  2446. /**
  2447. * Lets the sequence skip the given count of values.
  2448. */
  2449. void seek(INT_TYPE by)
  2450. {
  2451. INT_TYPE res = (shr_int_ += by);
  2452. return res-1; // -1 because we work with post increment
  2453. }
  2454. private:
  2455. distributed_base_int<INT_TYPE> shr_int_;
  2456. boost::optional<INT_TYPE> cur_val_;
  2457. };
  2458. typedef distributed_base_sequence<boost::intmax_t> distributed_sequence;
  2459. #ifndef TIMEOUT_SEC
  2460. #define TIMEOUT_SEC 60
  2461. #endif
  2462. /**
  2463. * Supports the Lockable and TimedLockable concepts from Boost.Thread/C++0x.
  2464. */
  2465. class distributed_mutex
  2466. {
  2467. private:
  2468. boost::int32_t tstamp_val( const boost::posix_time::time_duration & in_future = boost::posix_time::time_duration() )
  2469. {
  2470. boost::posix_time::ptime t = boost::posix_time::second_clock::universal_time();
  2471. boost::posix_time::ptime time_t_epoch( boost::gregorian::date(1970, 1, 1) );
  2472. t += in_future;
  2473. boost::posix_time::time_duration timeout_tstamp = t - time_t_epoch;
  2474. return timeout_tstamp.total_seconds();
  2475. }
  2476. public:
  2477. distributed_mutex(const client::string_type & name, client & con)
  2478. : con_(&con), name_(name)
  2479. {
  2480. std::string timeout_str = boost::lexical_cast<std::string>( tstamp_val( boost::posix_time::seconds(TIMEOUT_SEC) ) );
  2481. if( con_->setnx(name_, timeout_str) )
  2482. con_->rpush(name_ + ":list", timeout_str);
  2483. }
  2484. ~distributed_mutex()
  2485. {
  2486. }
  2487. void lock()
  2488. {
  2489. std::string timeout_tstamp_str;
  2490. while(true)
  2491. {
  2492. timeout_tstamp_str = con_->get(name_);
  2493. boost::int32_t timeout_tstamp = boost::lexical_cast<boost::int32_t>(timeout_tstamp_str);
  2494. boost::int32_t diff = tstamp_val( boost::posix_time::seconds(TIMEOUT_SEC) ) - timeout_tstamp;
  2495. if( diff < 1 )
  2496. diff = 1;
  2497. std::string token = con_->blpop(name_ + ":list", diff);
  2498. if( token == client::missing_value() )
  2499. {
  2500. if( timeout_tstamp_str == con_->get(name_) )
  2501. {
  2502. timeout_tstamp_str = boost::lexical_cast<std::string>( tstamp_val( boost::posix_time::seconds(TIMEOUT_SEC) ) );
  2503. con_->set(name_, timeout_tstamp_str);
  2504. con_->rpush(name_ + ":list", timeout_tstamp_str);
  2505. }
  2506. continue;
  2507. }
  2508. timeout_tstamp_str = con_->get(name_);
  2509. if( token == timeout_tstamp_str )
  2510. break;
  2511. }
  2512. std::string new_timeout_tstamp_str = boost::lexical_cast<std::string>( tstamp_val( boost::posix_time::seconds(TIMEOUT_SEC) ) );
  2513. std::string val = con_->getset(name_, timeout_tstamp_str);
  2514. if( timeout_tstamp_str != val )
  2515. lock();
  2516. token_ = new_timeout_tstamp_str;
  2517. }
  2518. void unlock()
  2519. {
  2520. con_->rpush(name_ + ":list", token_);
  2521. token_.clear();
  2522. }
  2523. bool try_lock()
  2524. {
  2525. if( con_->lpop(name_ + ":list") != client::missing_value() )
  2526. return true;
  2527. return false;
  2528. }
  2529. bool timed_lock(boost::system_time const& abs_time)
  2530. {
  2531. boost::posix_time::time_duration dur = abs_time - boost::get_system_time();
  2532. client::int_type timeout = std::max( dur.total_seconds(), 1 );
  2533. std::string res = con_->blpop(name_ + ":list", timeout);
  2534. if( res == client::missing_value() )
  2535. return false;
  2536. return false;
  2537. }
  2538. template<typename DurationType>
  2539. bool timed_lock(DurationType const& rel_time)
  2540. {
  2541. boost::posix_time::time_duration dur( rel_time );
  2542. client::int_type timeout = std::max( dur.total_seconds(), 1 );
  2543. std::string res = con_->blpop(name_ + ":list", timeout);
  2544. if( res == client::missing_value() )
  2545. return false;
  2546. return false;
  2547. }
  2548. typedef boost::unique_lock<distributed_mutex> scoped_timed_lock;
  2549. typedef boost::detail::try_lock_wrapper<distributed_mutex> scoped_try_lock;
  2550. typedef scoped_timed_lock scoped_lock;
  2551. private:
  2552. client* con_;
  2553. client::string_type name_;
  2554. std::string token_;
  2555. };
  2556. #endif // 0
  2557. class distributed_list : public distributed_value
  2558. {
  2559. public:
  2560. distributed_list(client & client_conn, const client::string_type & key)
  2561. : distributed_value(key, client_conn)
  2562. {
  2563. }
  2564. void push_back(const client::string_type & value)
  2565. {
  2566. client_conn_->rpush(key(), value);
  2567. }
  2568. void push_front(const client::string_type & value)
  2569. {
  2570. client_conn_->lpush(key(), value);
  2571. }
  2572. client::string_type pop_back()
  2573. {
  2574. return client_conn_->rpop(key());
  2575. }
  2576. client::string_type blocking_pop_back(client::int_type timeout = 0)
  2577. {
  2578. return client_conn_->brpop(key(), timeout);
  2579. }
  2580. client::string_type pop_front()
  2581. {
  2582. return client_conn_->lpop(key());
  2583. }
  2584. client::string_type blocking_pop_front(client::int_type timeout = 0)
  2585. {
  2586. return client_conn_->blpop(key(), timeout);
  2587. }
  2588. size_t size() const
  2589. {
  2590. return client_conn_->llen(key());
  2591. }
  2592. client::string_vector range(client::int_type begin = 0, client::int_type end = -1) const
  2593. {
  2594. client::string_vector res;
  2595. client_conn_->lrange(key(), begin, end, res);
  2596. return res;
  2597. }
  2598. inline client::string_vector to_vector() const
  2599. {
  2600. return range();
  2601. }
  2602. void trim(client::int_type begin, client::int_type end = -1)
  2603. {
  2604. client_conn_->ltrim(key(), begin, end);
  2605. }
  2606. client::string_type operator[](client::int_type index)
  2607. {
  2608. return client_conn_->lindex(key(), index);
  2609. }
  2610. void set(client::int_type index, const client::string_type & value)
  2611. {
  2612. client_conn_->lset(key(), index, value);
  2613. }
  2614. };
  2615. /**
  2616. * This class works on 'redis sets'. For best matching the stl/boost naming conventions it is called
  2617. * distributed_unordered_set and not distributed_set.
  2618. */
  2619. class distributed_unordered_set : public distributed_value
  2620. {
  2621. public:
  2622. distributed_unordered_set(const client::string_type & key, client & client_conn)
  2623. : distributed_value(key, client_conn)
  2624. {
  2625. }
  2626. void insert(const client::string_type & value)
  2627. {
  2628. client_conn_->sadd(key(), value);
  2629. }
  2630. void erase(const client::string_type & value)
  2631. {
  2632. client_conn_->srem(key(), value);
  2633. }
  2634. void clear()
  2635. {
  2636. del();
  2637. }
  2638. client::int_type count() const
  2639. {
  2640. return client_conn_->scard(key());
  2641. }
  2642. client::string_type pop_random()
  2643. {
  2644. return client_conn_->spop(key());
  2645. }
  2646. client::string_type get_random() const
  2647. {
  2648. return client_conn_->srandmember(key());
  2649. }
  2650. bool contains(const client::string_type & value) const
  2651. {
  2652. return client_conn_->sismember(key(), value);
  2653. }
  2654. };
  2655. /**
  2656. * This class works on 'redis sorted sets'. For best matching the stl/boost naming conventions it is called
  2657. * distributed_set.
  2658. */
  2659. class distributed_set : public distributed_value
  2660. {
  2661. public:
  2662. distributed_set(const client::string_type & key, client & client_conn)
  2663. : distributed_value(key, client_conn)
  2664. {
  2665. }
  2666. };
  2667. }
  2668. inline bool operator==(const redis::distributed_string & sh_str, const redis::client::string_type & str)
  2669. {
  2670. return sh_str.str() == str;
  2671. }
  2672. inline bool operator!=(const redis::distributed_string & sh_str, const redis::client::string_type & str)
  2673. {
  2674. return sh_str.str() != str;
  2675. }
  2676. template <typename ch, typename char_traits>
  2677. std::basic_ostream<ch, char_traits>& operator<<(std::basic_ostream<ch, char_traits> & os, const redis::distributed_string & sh_str)
  2678. {
  2679. return os << sh_str.str();
  2680. }
  2681. template <typename ch, typename char_traits>
  2682. std::basic_istream<ch, char_traits>& operator>>(std::basic_istream<ch, char_traits> & is, redis::distributed_string & sh_str)
  2683. {
  2684. redis::client::string_type s_val;
  2685. is >> s_val;
  2686. sh_str = s_val;
  2687. return is;
  2688. }
  2689. #endif // REDISCLIENT_H
  2690. #endif