1 /*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
2  *
3  *  Libmemcached library
4  *
5  *  Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
6  *
7  *  Redistribution and use in source and binary forms, with or without
8  *  modification, are permitted provided that the following conditions are
9  *  met:
10  *
11  *      * Redistributions of source code must retain the above copyright
12  *  notice, this list of conditions and the following disclaimer.
13  *
14  *      * Redistributions in binary form must reproduce the above
15  *  copyright notice, this list of conditions and the following disclaimer
16  *  in the documentation and/or other materials provided with the
17  *  distribution.
18  *
19  *      * The names of its contributors may not be used to endorse or
20  *  promote products derived from this software without specific prior
21  *  written permission.
22  *
23  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26  *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27  *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28  *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29  *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30  *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31  *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33  *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34  *
35  */
36 
37 /*
38  * Summary: C++ interface for memcached server
39  *
40  * Copy: See Copyright for the status of this software.
41  *
42  * Authors: Padraig O'Sullivan <osullivan.padraig@gmail.com>
43  *          Patrick Galbraith <patg@patg.net>
44  */
45 
46 /**
47  * @file memcached.hpp
48  * @brief Libmemcached C++ interface
49  */
50 
51 #pragma once
52 
53 #include <libmemcached-1.0/memcached.h>
54 #if 0
55 #include <libmemcached/exception.hpp>
56 #endif
57 
58 #include <string.h>
59 
60 #include <sstream>
61 #include <string>
62 #include <vector>
63 #include <map>
64 
65 namespace memcache
66 {
67 
68 /**
69  * This is the core memcached library (if later, other objects
70  * are needed, they will be created from this class).
71  */
72 class Memcache
73 {
74 public:
75 
Memcache()76   Memcache()
77   {
78     memc_= memcached(NULL, 0);
79   }
80 
Memcache(const std::string & config)81   Memcache(const std::string &config)
82   {
83     memc_= memcached(config.c_str(), config.size());
84   }
85 
Memcache(const std::string & hostname,in_port_t port)86   Memcache(const std::string &hostname, in_port_t port)
87   {
88     memc_= memcached(NULL, 0);
89     if (memc_)
90     {
91       memcached_server_add(memc_, hostname.c_str(), port);
92     }
93   }
94 
Memcache(memcached_st * clone)95   Memcache(memcached_st *clone)
96   {
97     memc_= memcached_clone(NULL, clone);
98   }
99 
Memcache(const Memcache & rhs)100   Memcache(const Memcache &rhs)
101   {
102     memc_= memcached_clone(NULL, rhs.getImpl());
103   }
104 
operator =(const Memcache & rhs)105   Memcache &operator=(const Memcache &rhs)
106   {
107     if (this != &rhs)
108     {
109       memcached_free(memc_);
110       memc_= memcached_clone(NULL, rhs.getImpl());
111     }
112 
113     return *this;
114   }
115 
~Memcache()116   ~Memcache()
117   {
118     memcached_free(memc_);
119   }
120 
121   /**
122    * Get the internal memcached_st *
123    */
getImpl() const124   const memcached_st *getImpl() const
125   {
126     return memc_;
127   }
128 
129   /**
130    * Return an error string for the given return structure.
131    *
132    * @param[in] rc a memcached_return_t structure
133    * @return error string corresponding to given return code in the library.
134    */
getError(memcached_return_t rc) const135   const std::string getError(memcached_return_t rc) const
136   {
137     /* first parameter to strerror is unused */
138     return memcached_strerror(NULL, rc);
139   }
140 
error(std::string & error_message) const141   bool error(std::string& error_message) const
142   {
143     if (memcached_failed(memcached_last_error(memc_)))
144     {
145       error_message+= memcached_last_error_message(memc_);
146       return true;
147     }
148 
149     return false;
150   }
151 
error() const152   bool error() const
153   {
154     if (memcached_failed(memcached_last_error(memc_)))
155     {
156       return true;
157     }
158 
159     return false;
160   }
161 
error(memcached_return_t & arg) const162   bool error(memcached_return_t& arg) const
163   {
164     arg= memcached_last_error(memc_);
165     return memcached_failed(arg);
166   }
167 
setBehavior(memcached_behavior_t flag,uint64_t data)168   bool setBehavior(memcached_behavior_t flag, uint64_t data)
169   {
170     return (memcached_success(memcached_behavior_set(memc_, flag, data)));
171   }
172 
getBehavior(memcached_behavior_t flag)173   uint64_t getBehavior(memcached_behavior_t flag)
174   {
175     return memcached_behavior_get(memc_, flag);
176   }
177 
178   /**
179    * Configure the memcache object
180    *
181    * @param[in] in_config configuration
182    * @return true on success; false otherwise
183    */
configure(const std::string & configuration)184   bool configure(const std::string &configuration)
185   {
186     memcached_st *new_memc= memcached(configuration.c_str(), configuration.size());
187 
188     if (new_memc)
189     {
190       memcached_free(memc_);
191       memc_= new_memc;
192 
193       return true;
194     }
195 
196     return false;
197   }
198 
199   /**
200    * Add a server to the list of memcached servers to use.
201    *
202    * @param[in] server_name name of the server to add
203    * @param[in] port port number of server to add
204    * @return true on success; false otherwise
205    */
addServer(const std::string & server_name,in_port_t port)206   bool addServer(const std::string &server_name, in_port_t port)
207   {
208     return memcached_success(memcached_server_add(memc_, server_name.c_str(), port));
209   }
210 
211   /**
212    * Remove a server from the list of memcached servers to use.
213    *
214    * @param[in] server_name name of the server to remove
215    * @param[in] port port number of server to remove
216    * @return true on success; false otherwise
217    */
removeServer(const std::string & server_name,in_port_t port)218   bool removeServer(const std::string &server_name, in_port_t port)
219   {
220     std::string tmp_str;
221     std::ostringstream strstm;
222     tmp_str.append(",");
223     tmp_str.append(server_name);
224     tmp_str.append(":");
225     strstm << port;
226     tmp_str.append(strstm.str());
227 
228     //memcached_return_t rc= memcached_server_remove(server);
229 
230     return false;
231   }
232 
233   /**
234    * Fetches an individual value from the server. mget() must always
235    * be called before using this method.
236    *
237    * @param[in] key key of object to fetch
238    * @param[out] ret_val store returned object in this vector
239    * @return a memcached return structure
240    */
fetch(std::string & key,std::vector<char> & ret_val,uint32_t & flags,uint64_t & cas_value)241   memcached_return_t fetch(std::string &key,
242                            std::vector<char> &ret_val,
243                            uint32_t &flags,
244                            uint64_t &cas_value)
245   {
246     memcached_return_t rc;
247 
248     memcached_result_st *result;
249     if ((result= memcached_fetch_result(memc_, NULL, &rc)))
250     {
251       // Key
252       key.assign(memcached_result_key_value(result), memcached_result_key_length(result));
253 
254       // Actual value, null terminated
255       ret_val.reserve(memcached_result_length(result) +1);
256       ret_val.assign(memcached_result_value(result),
257                      memcached_result_value(result) +memcached_result_length(result) +1);
258       ret_val.resize(memcached_result_length(result));
259 
260       // Misc
261       flags= memcached_result_flags(result);
262       cas_value= memcached_result_cas(result);
263     }
264     memcached_result_free(result);
265 
266     return rc;
267   }
268 
fetch(std::string & key,std::vector<char> & ret_val)269   memcached_return_t fetch(std::string &key,
270                            std::vector<char> &ret_val)
271   {
272     uint32_t flags= 0;
273     uint64_t cas_value= 0;
274 
275     return fetch(key, ret_val, flags, cas_value);
276   }
277 
278   /**
279    * Fetches an individual value from the server.
280    *
281    * @param[in] key key of object whose value to get
282    * @param[out] ret_val object that is retrieved is stored in
283    *                     this vector
284    * @return true on success; false otherwise
285    */
get(const std::string & key,std::vector<char> & ret_val)286   bool get(const std::string &key, std::vector<char> &ret_val)
287   {
288     uint32_t flags= 0;
289     memcached_return_t rc;
290     size_t value_length= 0;
291 
292     char *value= memcached_get(memc_, key.c_str(), key.length(),
293                                &value_length, &flags, &rc);
294     if (value != NULL && ret_val.empty())
295     {
296       ret_val.reserve(value_length +1); // Always provide null
297       ret_val.assign(value, value +value_length +1);
298       ret_val.resize(value_length);
299       free(value);
300 
301       return true;
302     }
303 
304     return false;
305   }
306 
307   /**
308    * Fetches an individual from a server which is specified by
309    * the master_key parameter that is used for determining which
310    * server an object was stored in if key partitioning was
311    * used for storage.
312    *
313    * @param[in] master_key key that specifies server object is stored on
314    * @param[in] key key of object whose value to get
315    * @param[out] ret_val object that is retrieved is stored in
316    *                     this vector
317    * @return true on success; false otherwise
318    */
getByKey(const std::string & master_key,const std::string & key,std::vector<char> & ret_val)319   bool getByKey(const std::string &master_key,
320                 const std::string &key,
321                 std::vector<char> &ret_val)
322   {
323     uint32_t flags= 0;
324     memcached_return_t rc;
325     size_t value_length= 0;
326 
327     char *value= memcached_get_by_key(memc_,
328                                       master_key.c_str(), master_key.length(),
329                                       key.c_str(), key.length(),
330                                       &value_length, &flags, &rc);
331     if (value)
332     {
333       ret_val.reserve(value_length +1); // Always provide null
334       ret_val.assign(value, value +value_length +1);
335       ret_val.resize(value_length);
336       free(value);
337 
338       return true;
339     }
340     return false;
341   }
342 
343   /**
344    * Selects multiple keys at once. This method always
345    * works asynchronously.
346    *
347    * @param[in] keys vector of keys to select
348    * @return true if all keys are found
349    */
mget(const std::vector<std::string> & keys)350   bool mget(const std::vector<std::string>& keys)
351   {
352     std::vector<const char *> real_keys;
353     std::vector<size_t> key_len;
354     /*
355      * Construct an array which will contain the length
356      * of each of the strings in the input vector. Also, to
357      * interface with the memcached C API, we need to convert
358      * the vector of std::string's to a vector of char *.
359      */
360     real_keys.reserve(keys.size());
361     key_len.reserve(keys.size());
362 
363     std::vector<std::string>::const_iterator it= keys.begin();
364 
365     while (it != keys.end())
366     {
367       real_keys.push_back(const_cast<char *>((*it).c_str()));
368       key_len.push_back((*it).length());
369       ++it;
370     }
371 
372     /*
373      * If the std::vector of keys is empty then we cannot
374      * call memcached_mget as we will get undefined behavior.
375      */
376     if (not real_keys.empty())
377     {
378       return memcached_success(memcached_mget(memc_, &real_keys[0], &key_len[0], real_keys.size()));
379     }
380 
381     return false;
382   }
383 
384   /**
385    * Writes an object to the server. If the object already exists, it will
386    * overwrite the existing object. This method always returns true
387    * when using non-blocking mode unless a network error occurs.
388    *
389    * @param[in] key key of object to write to server
390    * @param[in] value value of object to write to server
391    * @param[in] expiration time to keep the object stored in the server for
392    * @param[in] flags flags to store with the object
393    * @return true on succcess; false otherwise
394    */
set(const std::string & key,const std::vector<char> & value,time_t expiration,uint32_t flags)395   bool set(const std::string &key,
396            const std::vector<char> &value,
397            time_t expiration,
398            uint32_t flags)
399   {
400     memcached_return_t rc= memcached_set(memc_,
401                                          key.c_str(), key.length(),
402                                          &value[0], value.size(),
403                                          expiration, flags);
404     return memcached_success(rc);
405   }
406 
set(const std::string & key,const char * value,const size_t value_length,time_t expiration,uint32_t flags)407   bool set(const std::string &key,
408            const char* value, const size_t value_length,
409            time_t expiration,
410            uint32_t flags)
411   {
412     memcached_return_t rc= memcached_set(memc_,
413                                          key.c_str(), key.length(),
414                                          value, value_length,
415                                          expiration, flags);
416     return memcached_success(rc);
417   }
418 
419   /**
420    * Writes an object to a server specified by the master_key parameter.
421    * If the object already exists, it will overwrite the existing object.
422    *
423    * @param[in] master_key key that specifies server to write to
424    * @param[in] key key of object to write to server
425    * @param[in] value value of object to write to server
426    * @param[in] expiration time to keep the object stored in the server for
427    * @param[in] flags flags to store with the object
428    * @return true on succcess; false otherwise
429    */
setByKey(const std::string & master_key,const std::string & key,const std::vector<char> & value,time_t expiration,uint32_t flags)430   bool setByKey(const std::string& master_key,
431                 const std::string& key,
432                 const std::vector<char> &value,
433                 time_t expiration,
434                 uint32_t flags)
435   {
436     return memcached_success(memcached_set_by_key(memc_, master_key.c_str(),
437                                                   master_key.length(),
438                                                   key.c_str(), key.length(),
439                                                   &value[0], value.size(),
440                                                   expiration,
441                                                   flags));
442   }
443 
444   /**
445    * Writes a list of objects to the server. Objects are specified by
446    * 2 vectors - 1 vector of keys and 1 vector of values.
447    *
448    * @param[in] keys vector of keys of objects to write to server
449    * @param[in] values vector of values of objects to write to server
450    * @param[in] expiration time to keep the objects stored in server for
451    * @param[in] flags flags to store with the objects
452    * @return true on success; false otherwise
453    */
setAll(const std::vector<std::string> & keys,const std::vector<std::vector<char> * > & values,time_t expiration,uint32_t flags)454   bool setAll(const std::vector<std::string>& keys,
455               const std::vector< std::vector<char> *>& values,
456               time_t expiration,
457               uint32_t flags)
458   {
459     bool retval= true;
460     std::vector<std::string>::const_iterator key_it= keys.begin();
461     std::vector< std::vector<char> *>::const_iterator val_it= values.begin();
462     while (key_it != keys.end())
463     {
464       retval= set((*key_it), *(*val_it), expiration, flags);
465       if (retval == false)
466       {
467         return retval;
468       }
469       ++key_it;
470       ++val_it;
471     }
472     return retval;
473   }
474 
475   /**
476    * Writes a list of objects to the server. Objects are specified by
477    * a map of keys to values.
478    *
479    * @param[in] key_value_map map of keys and values to store in server
480    * @param[in] expiration time to keep the objects stored in server for
481    * @param[in] flags flags to store with the objects
482    * @return true on success; false otherwise
483    */
setAll(const std::map<const std::string,std::vector<char>> & key_value_map,time_t expiration,uint32_t flags)484   bool setAll(const std::map<const std::string, std::vector<char> >& key_value_map,
485               time_t expiration,
486               uint32_t flags)
487   {
488     bool retval= true;
489     std::map<const std::string, std::vector<char> >::const_iterator it= key_value_map.begin();
490 
491     while (it != key_value_map.end())
492     {
493       retval= set(it->first, it->second, expiration, flags);
494       if (retval == false)
495       {
496         // We should tell the user what the key that failed was
497         return false;
498       }
499       ++it;
500     }
501 
502     return true;
503   }
504 
505   /**
506    * Increment the value of the object associated with the specified
507    * key by the offset given. The resulting value is saved in the value
508    * parameter.
509    *
510    * @param[in] key key of object in server whose value to increment
511    * @param[in] offset amount to increment object's value by
512    * @param[out] value store the result of the increment here
513    * @return true on success; false otherwise
514    */
increment(const std::string & key,uint32_t offset,uint64_t * value)515   bool increment(const std::string& key, uint32_t offset, uint64_t *value)
516   {
517     return memcached_success(memcached_increment(memc_, key.c_str(), key.length(), offset, value));
518   }
519 
520   /**
521    * Decrement the value of the object associated with the specified
522    * key by the offset given. The resulting value is saved in the value
523    * parameter.
524    *
525    * @param[in] key key of object in server whose value to decrement
526    * @param[in] offset amount to increment object's value by
527    * @param[out] value store the result of the decrement here
528    * @return true on success; false otherwise
529    */
decrement(const std::string & key,uint32_t offset,uint64_t * value)530   bool decrement(const std::string& key, uint32_t offset, uint64_t *value)
531   {
532     return memcached_success(memcached_decrement(memc_, key.c_str(),
533                                                  key.length(),
534                                                  offset, value));
535   }
536 
537 
538   /**
539    * Add an object with the specified key and value to the server. This
540    * function returns false if the object already exists on the server.
541    *
542    * @param[in] key key of object to add
543    * @param[in] value of object to add
544    * @return true on success; false otherwise
545    */
add(const std::string & key,const std::vector<char> & value)546   bool add(const std::string& key, const std::vector<char>& value)
547   {
548     return memcached_success(memcached_add(memc_, key.c_str(), key.length(),
549                                            &value[0], value.size(), 0, 0));
550   }
551 
552   /**
553    * Add an object with the specified key and value to the server. This
554    * function returns false if the object already exists on the server. The
555    * server to add the object to is specified by the master_key parameter.
556    *
557    * @param[in[ master_key key of server to add object to
558    * @param[in] key key of object to add
559    * @param[in] value of object to add
560    * @return true on success; false otherwise
561    */
addByKey(const std::string & master_key,const std::string & key,const std::vector<char> & value)562   bool addByKey(const std::string& master_key,
563                 const std::string& key,
564                 const std::vector<char>& value)
565   {
566     return memcached_success(memcached_add_by_key(memc_,
567                                                   master_key.c_str(),
568                                                   master_key.length(),
569                                                   key.c_str(),
570                                                   key.length(),
571                                                   &value[0],
572                                                   value.size(),
573                                                   0, 0));
574   }
575 
576   /**
577    * Replaces an object on the server. This method only succeeds
578    * if the object is already present on the server.
579    *
580    * @param[in] key key of object to replace
581    * @param[in[ value value to replace object with
582    * @return true on success; false otherwise
583    */
replace(const std::string & key,const std::vector<char> & value)584   bool replace(const std::string& key, const std::vector<char>& value)
585   {
586     return memcached_success(memcached_replace(memc_, key.c_str(), key.length(),
587                                                &value[0], value.size(),
588                                                0, 0));
589   }
590 
591   /**
592    * Replaces an object on the server. This method only succeeds
593    * if the object is already present on the server. The server
594    * to replace the object on is specified by the master_key param.
595    *
596    * @param[in] master_key key of server to replace object on
597    * @param[in] key key of object to replace
598    * @param[in[ value value to replace object with
599    * @return true on success; false otherwise
600    */
replaceByKey(const std::string & master_key,const std::string & key,const std::vector<char> & value)601   bool replaceByKey(const std::string& master_key,
602                     const std::string& key,
603                     const std::vector<char>& value)
604   {
605     return memcached_success(memcached_replace_by_key(memc_,
606                                                       master_key.c_str(),
607                                                       master_key.length(),
608                                                       key.c_str(),
609                                                       key.length(),
610                                                       &value[0],
611                                                       value.size(),
612                                                       0, 0));
613   }
614 
615   /**
616    * Places a segment of data before the last piece of data stored.
617    *
618    * @param[in] key key of object whose value we will prepend data to
619    * @param[in] value data to prepend to object's value
620    * @return true on success; false otherwise
621    */
prepend(const std::string & key,const std::vector<char> & value)622   bool prepend(const std::string& key, const std::vector<char>& value)
623   {
624     return memcached_success(memcached_prepend(memc_, key.c_str(), key.length(),
625                                                &value[0], value.size(), 0, 0));
626   }
627 
628   /**
629    * Places a segment of data before the last piece of data stored. The
630    * server on which the object where we will be prepending data is stored
631    * on is specified by the master_key parameter.
632    *
633    * @param[in] master_key key of server where object is stored
634    * @param[in] key key of object whose value we will prepend data to
635    * @param[in] value data to prepend to object's value
636    * @return true on success; false otherwise
637    */
prependByKey(const std::string & master_key,const std::string & key,const std::vector<char> & value)638   bool prependByKey(const std::string& master_key,
639                     const std::string& key,
640                     const std::vector<char>& value)
641   {
642     return memcached_success(memcached_prepend_by_key(memc_,
643                                                       master_key.c_str(),
644                                                       master_key.length(),
645                                                       key.c_str(),
646                                                       key.length(),
647                                                       &value[0],
648                                                       value.size(),
649                                                       0,
650                                                       0));
651   }
652 
653   /**
654    * Places a segment of data at the end of the last piece of data stored.
655    *
656    * @param[in] key key of object whose value we will append data to
657    * @param[in] value data to append to object's value
658    * @return true on success; false otherwise
659    */
append(const std::string & key,const std::vector<char> & value)660   bool append(const std::string& key, const std::vector<char>& value)
661   {
662     return memcached_success(memcached_append(memc_,
663                                               key.c_str(),
664                                               key.length(),
665                                               &value[0],
666                                               value.size(),
667                                               0, 0));
668   }
669 
670   /**
671    * Places a segment of data at the end of the last piece of data stored. The
672    * server on which the object where we will be appending data is stored
673    * on is specified by the master_key parameter.
674    *
675    * @param[in] master_key key of server where object is stored
676    * @param[in] key key of object whose value we will append data to
677    * @param[in] value data to append to object's value
678    * @return true on success; false otherwise
679    */
appendByKey(const std::string & master_key,const std::string & key,const std::vector<char> & value)680   bool appendByKey(const std::string& master_key,
681                    const std::string& key,
682                    const std::vector<char> &value)
683   {
684     return memcached_success(memcached_append_by_key(memc_,
685                                                      master_key.c_str(),
686                                                      master_key.length(),
687                                                      key.c_str(),
688                                                      key.length(),
689                                                      &value[0],
690                                                      value.size(),
691                                                      0, 0));
692   }
693 
694   /**
695    * Overwrite data in the server as long as the cas_arg value
696    * is still the same in the server.
697    *
698    * @param[in] key key of object in server
699    * @param[in] value value to store for object in server
700    * @param[in] cas_arg "cas" value
701    */
cas(const std::string & key,const std::vector<char> & value,uint64_t cas_arg)702   bool cas(const std::string& key,
703            const std::vector<char>& value,
704            uint64_t cas_arg)
705   {
706     return memcached_success(memcached_cas(memc_, key.c_str(), key.length(),
707                                            &value[0], value.size(),
708                                            0, 0, cas_arg));
709   }
710 
711   /**
712    * Overwrite data in the server as long as the cas_arg value
713    * is still the same in the server. The server to use is
714    * specified by the master_key parameter.
715    *
716    * @param[in] master_key specifies server to operate on
717    * @param[in] key key of object in server
718    * @param[in] value value to store for object in server
719    * @param[in] cas_arg "cas" value
720    */
casByKey(const std::string & master_key,const std::string & key,const std::vector<char> & value,uint64_t cas_arg)721   bool casByKey(const std::string& master_key,
722                 const std::string& key,
723                 const std::vector<char> &value,
724                 uint64_t cas_arg)
725   {
726     return memcached_success(memcached_cas_by_key(memc_,
727                                                   master_key.c_str(),
728                                                   master_key.length(),
729                                                   key.c_str(),
730                                                   key.length(),
731                                                   &value[0],
732                                                   value.size(),
733                                                   0, 0, cas_arg));
734   }
735 
736   /**
737    * Delete an object from the server specified by the key given.
738    *
739    * @param[in] key key of object to delete
740    * @return true on success; false otherwise
741    */
remove(const std::string & key)742   bool remove(const std::string& key)
743   {
744     return memcached_success(memcached_delete(memc_, key.c_str(), key.length(), 0));
745   }
746 
747   /**
748    * Delete an object from the server specified by the key given.
749    *
750    * @param[in] key key of object to delete
751    * @param[in] expiration time to delete the object after
752    * @return true on success; false otherwise
753    */
remove(const std::string & key,time_t expiration)754   bool remove(const std::string& key, time_t expiration)
755   {
756     return memcached_success(memcached_delete(memc_,
757                                               key.c_str(),
758                                               key.length(),
759                                               expiration));
760   }
761 
762   /**
763    * Delete an object from the server specified by the key given.
764    *
765    * @param[in] master_key specifies server to remove object from
766    * @param[in] key key of object to delete
767    * @return true on success; false otherwise
768    */
removeByKey(const std::string & master_key,const std::string & key)769   bool removeByKey(const std::string& master_key,
770                    const std::string& key)
771   {
772     return memcached_success(memcached_delete_by_key(memc_,
773                                                      master_key.c_str(),
774                                                      master_key.length(),
775                                                      key.c_str(),
776                                                      key.length(),
777                                                      0));
778   }
779 
780   /**
781    * Delete an object from the server specified by the key given.
782    *
783    * @param[in] master_key specifies server to remove object from
784    * @param[in] key key of object to delete
785    * @param[in] expiration time to delete the object after
786    * @return true on success; false otherwise
787    */
removeByKey(const std::string & master_key,const std::string & key,time_t expiration)788   bool removeByKey(const std::string& master_key,
789                    const std::string& key,
790                    time_t expiration)
791   {
792     return memcached_success(memcached_delete_by_key(memc_,
793                                                      master_key.c_str(),
794                                                      master_key.length(),
795                                                      key.c_str(),
796                                                      key.length(),
797                                                      expiration));
798   }
799 
800   /**
801    * Wipe the contents of memcached servers.
802    *
803    * @param[in] expiration time to wait until wiping contents of
804    *                       memcached servers
805    * @return true on success; false otherwise
806    */
flush(time_t expiration=0)807   bool flush(time_t expiration= 0)
808   {
809     return memcached_success(memcached_flush(memc_, expiration));
810   }
811 
812   /**
813    * Get the library version string.
814    * @return std::string containing a copy of the library version string.
815    */
libVersion() const816   const std::string libVersion() const
817   {
818     const char *ver= memcached_lib_version();
819     const std::string version(ver);
820     return version;
821   }
822 
823   /**
824    * Retrieve memcached statistics. Populate a std::map with the retrieved
825    * stats. Each server will map to another std::map of the key:value stats.
826    *
827    * @param[out] stats_map a std::map to be populated with the memcached
828    *                       stats
829    * @return true on success; false otherwise
830    */
getStats(std::map<std::string,std::map<std::string,std::string>> & stats_map)831   bool getStats(std::map< std::string, std::map<std::string, std::string> >& stats_map)
832   {
833     memcached_return_t rc;
834     memcached_stat_st *stats= memcached_stat(memc_, NULL, &rc);
835 
836     if (rc != MEMCACHED_SUCCESS &&
837         rc != MEMCACHED_SOME_ERRORS)
838     {
839       return false;
840     }
841 
842     uint32_t server_count= memcached_server_count(memc_);
843 
844     /*
845      * For each memcached server, construct a std::map for its stats and add
846      * it to the std::map of overall stats.
847      */
848     for (uint32_t x= 0; x < server_count; x++)
849     {
850       const memcached_instance_st * instance= memcached_server_instance_by_position(memc_, x);
851       std::ostringstream strstm;
852       std::string server_name(memcached_server_name(instance));
853       server_name.append(":");
854       strstm << memcached_server_port(instance);
855       server_name.append(strstm.str());
856 
857       std::map<std::string, std::string> server_stats;
858       char **list= memcached_stat_get_keys(memc_, &stats[x], &rc);
859       for (char** ptr= list; *ptr; ptr++)
860       {
861         char *value= memcached_stat_get_value(memc_, &stats[x], *ptr, &rc);
862         server_stats[*ptr]= value;
863         free(value);
864       }
865 
866       stats_map[server_name]= server_stats;
867       free(list);
868     }
869 
870     memcached_stat_free(memc_, stats);
871     return true;
872   }
873 
874 private:
875   memcached_st *memc_;
876 };
877 
878 }
879