1 /*
2  * Summary: C++ interface for memcached server
3  *
4  * Copy: See Copyright for the status of this software.
5  *
6  * Authors: Padraig O'Sullivan <osullivan.padraig@gmail.com>
7  *          Patrick Galbraith <patg@patg.net>
8  */
9 
10 /**
11  * @file memcached.hpp
12  * @brief Libmemcached C++ interface
13  */
14 
15 #ifndef LIBMEMCACHEDPP_H
16 #define LIBMEMCACHEDPP_H
17 
18 #include <libmemcached/memcached.h>
19 #include <libmemcached/exception.hpp>
20 
21 #include <string.h>
22 
23 #include <sstream>
24 #include <string>
25 #include <vector>
26 #include <map>
27 
28 namespace memcache
29 {
30 
31 /**
32  * This is the core memcached library (if later, other objects
33  * are needed, they will be created from this class).
34  */
35 class Memcache
36 {
37 public:
38 
Memcache()39   Memcache()
40     :
41       servers_list(),
42       memc(),
43       result()
44   {
45     memcached_create(&memc);
46   }
47 
Memcache(const std::string &in_servers_list)48   Memcache(const std::string &in_servers_list)
49     :
50       servers_list(in_servers_list),
51       memc(),
52       result()
53   {
54     memcached_create(&memc);
55     init();
56   }
57 
Memcache(const std::string &hostname, in_port_t port)58   Memcache(const std::string &hostname,
59            in_port_t port)
60     :
61       servers_list(),
62       memc(),
63       result()
64   {
65     memcached_create(&memc);
66 
67     servers_list.append(hostname);
68     servers_list.append(":");
69     std::ostringstream strsmt;
70     strsmt << port;
71     servers_list.append(strsmt.str());
72 
73     init();
74   }
75 
Memcache(memcached_st *clone)76   Memcache(memcached_st *clone)
77     :
78       servers_list(),
79       memc(),
80       result()
81   {
82     memcached_clone(&memc, clone);
83   }
84 
Memcache(const Memcache &rhs)85   Memcache(const Memcache &rhs)
86     :
87       servers_list(rhs.servers_list),
88       memc(),
89       result()
90   {
91     memcached_clone(&memc, const_cast<memcached_st *>(&rhs.getImpl()));
92     init();
93   }
94 
operator =(const Memcache &rhs)95   Memcache &operator=(const Memcache &rhs)
96   {
97     if (this != &rhs)
98     {
99       memcached_clone(&memc, const_cast<memcached_st *>(&rhs.getImpl()));
100       init();
101     }
102 
103     return *this;
104   }
105 
~Memcache()106   ~Memcache()
107   {
108     memcached_free(&memc);
109   }
110 
init()111   void init()
112   {
113     memcached_server_st *servers;
114     servers= memcached_servers_parse(servers_list.c_str());
115     memcached_server_push(&memc, servers);
116     memcached_server_free(servers);
117   }
118 
119   /**
120    * Get the internal memcached_st *
121    */
getImpl()122   memcached_st &getImpl()
123   {
124     return memc;
125   }
126 
127   /**
128    * Get the internal memcached_st *
129    */
getImpl() const130   const memcached_st &getImpl() const
131   {
132     return memc;
133   }
134 
135   /**
136    * Return an error string for the given return structure.
137    *
138    * @param[in] rc a memcached_return_t structure
139    * @return error string corresponding to given return code in the library.
140    */
getError(memcached_return_t rc) const141   const std::string getError(memcached_return_t rc) const
142   {
143     /* first parameter to strerror is unused */
144     return memcached_strerror(NULL, rc);
145   }
146 
147 
setBehavior(memcached_behavior_t flag, uint64_t data)148   bool setBehavior(memcached_behavior_t flag, uint64_t data)
149   {
150     memcached_return_t rc;
151     rc= memcached_behavior_set(&memc, flag, data);
152     return (rc == MEMCACHED_SUCCESS);
153   }
154 
getBehavior(memcached_behavior_t flag)155   uint64_t getBehavior(memcached_behavior_t flag) {
156     return memcached_behavior_get(&memc, flag);
157   }
158 
159   /**
160    * Return the string which contains the list of memcached servers being
161    * used.
162    *
163    * @return a std::string containing the list of memcached servers
164    */
getServersList() const165   const std::string getServersList() const
166   {
167     return servers_list;
168   }
169 
170   /**
171    * Set the list of memcached servers to use.
172    *
173    * @param[in] in_servers_list list of servers
174    * @return true on success; false otherwise
175    */
setServers(const std::string &in_servers_list)176   bool setServers(const std::string &in_servers_list)
177   {
178     servers_list.assign(in_servers_list);
179     init();
180 
181     return (memcached_server_count(&memc));
182   }
183 
184   /**
185    * Add a server to the list of memcached servers to use.
186    *
187    * @param[in] server_name name of the server to add
188    * @param[in] port port number of server to add
189    * @return true on success; false otherwise
190    */
addServer(const std::string &server_name, in_port_t port)191   bool addServer(const std::string &server_name, in_port_t port)
192   {
193     memcached_return_t rc;
194 
195     rc= memcached_server_add(&memc, server_name.c_str(), port);
196 
197     return (rc == MEMCACHED_SUCCESS);
198   }
199 
200   /**
201    * Remove a server from the list of memcached servers to use.
202    *
203    * @param[in] server_name name of the server to remove
204    * @param[in] port port number of server to remove
205    * @return true on success; false otherwise
206    */
removeServer(const std::string &server_name, in_port_t port)207   bool removeServer(const std::string &server_name, in_port_t port)
208   {
209     std::string tmp_str;
210     std::ostringstream strstm;
211     tmp_str.append(",");
212     tmp_str.append(server_name);
213     tmp_str.append(":");
214     strstm << port;
215     tmp_str.append(strstm.str());
216 
217     //memcached_return_t rc= memcached_server_remove(server);
218 
219     return false;
220   }
221 
222   /**
223    * Fetches an individual value from the server. mget() must always
224    * be called before using this method.
225    *
226    * @param[in] key key of object to fetch
227    * @param[out] ret_val store returned object in this vector
228    * @return a memcached return structure
229    */
fetch(std::string &key, std::vector<char> &ret_val)230   memcached_return_t fetch(std::string &key,
231                          std::vector<char> &ret_val)
232   {
233     char ret_key[MEMCACHED_MAX_KEY];
234     size_t value_length= 0;
235     size_t key_length= 0;
236     memcached_return_t rc;
237     uint32_t flags= 0;
238     char *value= memcached_fetch(&memc, ret_key, &key_length,
239                                  &value_length, &flags, &rc);
240     if (value && ret_val.empty())
241     {
242       ret_val.reserve(value_length);
243       ret_val.assign(value, value + value_length);
244       key.assign(ret_key);
245       free(value);
246     }
247     else if (value)
248     {
249       free(value);
250     }
251 
252     return rc;
253   }
254 
255   /**
256    * Fetches an individual value from the server.
257    *
258    * @param[in] key key of object whose value to get
259    * @param[out] ret_val object that is retrieved is stored in
260    *                     this vector
261    * @return true on success; false otherwise
262    */
get(const std::string &key, std::vector<char> &ret_val)263   bool get(const std::string &key,
264            std::vector<char> &ret_val) throw (Error)
265   {
266     uint32_t flags= 0;
267     memcached_return_t rc;
268     size_t value_length= 0;
269 
270     if (key.empty())
271     {
272       throw(Error("the key supplied is empty!", false));
273     }
274     char *value= memcached_get(&memc, key.c_str(), key.length(),
275                                &value_length, &flags, &rc);
276     if (value != NULL && ret_val.empty())
277     {
278       ret_val.reserve(value_length);
279       ret_val.assign(value, value + value_length);
280       free(value);
281       return true;
282     }
283     return false;
284   }
285 
286   /**
287    * Fetches an individual from a server which is specified by
288    * the master_key parameter that is used for determining which
289    * server an object was stored in if key partitioning was
290    * used for storage.
291    *
292    * @param[in] master_key key that specifies server object is stored on
293    * @param[in] key key of object whose value to get
294    * @param[out] ret_val object that is retrieved is stored in
295    *                     this vector
296    * @return true on success; false otherwise
297    */
getByKey(const std::string &master_key, const std::string &key, std::vector<char> &ret_val)298   bool getByKey(const std::string &master_key,
299                 const std::string &key,
300                 std::vector<char> &ret_val) throw(Error)
301   {
302     uint32_t flags= 0;
303     memcached_return_t rc;
304     size_t value_length= 0;
305 
306     if (master_key.empty() || key.empty())
307     {
308       throw(Error("the master key or key supplied is empty!", false));
309     }
310     char *value= memcached_get_by_key(&memc,
311                                       master_key.c_str(), master_key.length(),
312                                       key.c_str(), key.length(),
313                                       &value_length, &flags, &rc);
314     if (value)
315     {
316       ret_val.reserve(value_length);
317       ret_val.assign(value, value + value_length);
318       free(value);
319       return true;
320     }
321     return false;
322   }
323 
324   /**
325    * Selects multiple keys at once. This method always
326    * works asynchronously.
327    *
328    * @param[in] keys vector of keys to select
329    * @return true if all keys are found
330    */
mget(std::vector<std::string> &keys)331   bool mget(std::vector<std::string> &keys)
332   {
333     std::vector<const char *> real_keys;
334     std::vector<size_t> key_len;
335     /*
336      * Construct an array which will contain the length
337      * of each of the strings in the input vector. Also, to
338      * interface with the memcached C API, we need to convert
339      * the vector of std::string's to a vector of char *.
340      */
341     real_keys.reserve(keys.size());
342     key_len.reserve(keys.size());
343 
344     std::vector<std::string>::iterator it= keys.begin();
345 
346     while (it != keys.end())
347     {
348       real_keys.push_back(const_cast<char *>((*it).c_str()));
349       key_len.push_back((*it).length());
350       ++it;
351     }
352 
353     /*
354      * If the std::vector of keys is empty then we cannot
355      * call memcached_mget as we will get undefined behavior.
356      */
357     if (! real_keys.empty())
358     {
359       memcached_return_t rc= memcached_mget(&memc, &real_keys[0], &key_len[0],
360                                           real_keys.size());
361       return (rc == MEMCACHED_SUCCESS);
362     }
363 
364     return false;
365   }
366 
367   /**
368    * Writes an object to the server. If the object already exists, it will
369    * overwrite the existing object. This method always returns true
370    * when using non-blocking mode unless a network error occurs.
371    *
372    * @param[in] key key of object to write to server
373    * @param[in] value value of object to write to server
374    * @param[in] expiration time to keep the object stored in the server for
375    * @param[in] flags flags to store with the object
376    * @return true on succcess; false otherwise
377    */
set(const std::string &key, const std::vector<char> &value, time_t expiration, uint32_t flags)378   bool set(const std::string &key,
379            const std::vector<char> &value,
380            time_t expiration,
381            uint32_t flags) throw(Error)
382   {
383     if (key.empty() || value.empty())
384     {
385       throw(Error("the key or value supplied is empty!", false));
386     }
387     memcached_return_t rc= memcached_set(&memc,
388                                        key.c_str(), key.length(),
389                                        &value[0], value.size(),
390                                        expiration, flags);
391     return (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
392   }
393 
394   /**
395    * Writes an object to a server specified by the master_key parameter.
396    * If the object already exists, it will overwrite the existing object.
397    *
398    * @param[in] master_key key that specifies server to write to
399    * @param[in] key key of object to write to server
400    * @param[in] value value of object to write to server
401    * @param[in] expiration time to keep the object stored in the server for
402    * @param[in] flags flags to store with the object
403    * @return true on succcess; false otherwise
404    */
setByKey(const std::string &master_key, const std::string &key, const std::vector<char> &value, time_t expiration, uint32_t flags)405   bool setByKey(const std::string &master_key,
406                 const std::string &key,
407                 const std::vector<char> &value,
408                 time_t expiration,
409                 uint32_t flags) throw(Error)
410   {
411     if (master_key.empty() ||
412         key.empty() ||
413         value.empty())
414     {
415       throw(Error("the key or value supplied is empty!", false));
416     }
417     memcached_return_t rc= memcached_set_by_key(&memc, master_key.c_str(),
418                                               master_key.length(),
419                                               key.c_str(), key.length(),
420                                               &value[0], value.size(),
421                                               expiration,
422                                               flags);
423     return (rc == MEMCACHED_SUCCESS);
424   }
425 
426   /**
427    * Writes a list of objects to the server. Objects are specified by
428    * 2 vectors - 1 vector of keys and 1 vector of values.
429    *
430    * @param[in] keys vector of keys of objects to write to server
431    * @param[in] values vector of values of objects to write to server
432    * @param[in] expiration time to keep the objects stored in server for
433    * @param[in] flags flags to store with the objects
434    * @return true on success; false otherwise
435    */
setAll(std::vector<std::string> &keys, std::vector< std::vector<char> *> &values, time_t expiration, uint32_t flags)436   bool setAll(std::vector<std::string> &keys,
437               std::vector< std::vector<char> *> &values,
438               time_t expiration,
439               uint32_t flags) throw(Error)
440   {
441     if (keys.size() != values.size())
442     {
443       throw(Error("The number of keys and values do not match!", false));
444     }
445     bool retval= true;
446     std::vector<std::string>::iterator key_it= keys.begin();
447     std::vector< std::vector<char> *>::iterator val_it= values.begin();
448     while (key_it != keys.end())
449     {
450       retval= set((*key_it), *(*val_it), expiration, flags);
451       if (retval == false)
452       {
453         return retval;
454       }
455       ++key_it;
456       ++val_it;
457     }
458     return retval;
459   }
460 
461   /**
462    * Writes a list of objects to the server. Objects are specified by
463    * a map of keys to values.
464    *
465    * @param[in] key_value_map map of keys and values to store in server
466    * @param[in] expiration time to keep the objects stored in server for
467    * @param[in] flags flags to store with the objects
468    * @return true on success; false otherwise
469    */
setAll(std::map<const std::string, std::vector<char> > &key_value_map, time_t expiration, uint32_t flags)470   bool setAll(std::map<const std::string, std::vector<char> > &key_value_map,
471               time_t expiration,
472               uint32_t flags) throw(Error)
473   {
474     if (key_value_map.empty())
475     {
476       throw(Error("The key/values are not properly set!", false));
477     }
478     bool retval= true;
479     std::map<const std::string, std::vector<char> >::iterator it=
480       key_value_map.begin();
481     while (it != key_value_map.end())
482     {
483       retval= set(it->first, it->second, expiration, flags);
484       if (retval == false)
485       {
486         std::string err_buff("There was an error setting the key ");
487         err_buff.append(it->first);
488         throw(Error(err_buff, false));
489       }
490       ++it;
491     }
492     return true;
493   }
494 
495   /**
496    * Increment the value of the object associated with the specified
497    * key by the offset given. The resulting value is saved in the value
498    * parameter.
499    *
500    * @param[in] key key of object in server whose value to increment
501    * @param[in] offset amount to increment object's value by
502    * @param[out] value store the result of the increment here
503    * @return true on success; false otherwise
504    */
increment(const std::string &key, uint32_t offset, uint64_t *value)505   bool increment(const std::string &key, uint32_t offset, uint64_t *value) throw(Error)
506   {
507     if (key.empty())
508     {
509       throw(Error("the key supplied is empty!", false));
510     }
511     memcached_return_t rc= memcached_increment(&memc, key.c_str(), key.length(),
512                                              offset, value);
513     return (rc == MEMCACHED_SUCCESS);
514   }
515 
516   /**
517    * Decrement the value of the object associated with the specified
518    * key by the offset given. The resulting value is saved in the value
519    * parameter.
520    *
521    * @param[in] key key of object in server whose value to decrement
522    * @param[in] offset amount to increment object's value by
523    * @param[out] value store the result of the decrement here
524    * @return true on success; false otherwise
525    */
decrement(const std::string &key, uint32_t offset, uint64_t *value)526   bool decrement(const std::string &key, uint32_t offset, uint64_t *value)
527     throw(Error)
528   {
529     if (key.empty())
530     {
531       throw(Error("the key supplied is empty!", false));
532     }
533     memcached_return_t rc= memcached_decrement(&memc, key.c_str(),
534                                              key.length(),
535                                              offset, value);
536     return (rc == MEMCACHED_SUCCESS);
537   }
538 
539 
540   /**
541    * Add an object with the specified key and value to the server. This
542    * function returns false if the object already exists on the server.
543    *
544    * @param[in] key key of object to add
545    * @param[in] value of object to add
546    * @return true on success; false otherwise
547    */
add(const std::string &key, const std::vector<char> &value)548   bool add(const std::string &key, const std::vector<char> &value)
549     throw(Error)
550   {
551     if (key.empty() || value.empty())
552     {
553       throw(Error("the key or value supplied is empty!", false));
554     }
555     memcached_return_t rc= memcached_add(&memc, key.c_str(), key.length(),
556                                        &value[0], value.size(), 0, 0);
557     return (rc == MEMCACHED_SUCCESS);
558   }
559 
560   /**
561    * Add an object with the specified key and value to the server. This
562    * function returns false if the object already exists on the server. The
563    * server to add the object to is specified by the master_key parameter.
564    *
565    * @param[in[ master_key key of server to add object to
566    * @param[in] key key of object to add
567    * @param[in] value of object to add
568    * @return true on success; false otherwise
569    */
addByKey(const std::string &master_key, const std::string &key, const std::vector<char> &value)570   bool addByKey(const std::string &master_key,
571                 const std::string &key,
572                 const std::vector<char> &value) throw(Error)
573   {
574     if (master_key.empty() ||
575         key.empty() ||
576         value.empty())
577     {
578       throw(Error("the master key or key supplied is empty!", false));
579     }
580     memcached_return_t rc= memcached_add_by_key(&memc,
581                                               master_key.c_str(),
582                                               master_key.length(),
583                                               key.c_str(),
584                                               key.length(),
585                                               &value[0],
586                                               value.size(),
587                                               0, 0);
588     return (rc == MEMCACHED_SUCCESS);
589   }
590 
591   /**
592    * Replaces an object on the server. This method only succeeds
593    * if the object is already present on the server.
594    *
595    * @param[in] key key of object to replace
596    * @param[in[ value value to replace object with
597    * @return true on success; false otherwise
598    */
replace(const std::string &key, const std::vector<char> &value)599   bool replace(const std::string &key, const std::vector<char> &value) throw(Error)
600   {
601     if (key.empty() ||
602         value.empty())
603     {
604       throw(Error("the key or value supplied is empty!", false));
605     }
606     memcached_return_t rc= memcached_replace(&memc, key.c_str(), key.length(),
607                                            &value[0], value.size(),
608                                            0, 0);
609     return (rc == MEMCACHED_SUCCESS);
610   }
611 
612   /**
613    * Replaces an object on the server. This method only succeeds
614    * if the object is already present on the server. The server
615    * to replace the object on is specified by the master_key param.
616    *
617    * @param[in] master_key key of server to replace object on
618    * @param[in] key key of object to replace
619    * @param[in[ value value to replace object with
620    * @return true on success; false otherwise
621    */
replaceByKey(const std::string &master_key, const std::string &key, const std::vector<char> &value)622   bool replaceByKey(const std::string &master_key,
623                     const std::string &key,
624                     const std::vector<char> &value)
625   {
626     if (master_key.empty() ||
627         key.empty() ||
628         value.empty())
629     {
630       throw(Error("the master key or key supplied is empty!", false));
631     }
632     memcached_return_t rc= memcached_replace_by_key(&memc,
633                                                   master_key.c_str(),
634                                                   master_key.length(),
635                                                   key.c_str(),
636                                                   key.length(),
637                                                   &value[0],
638                                                   value.size(),
639                                                   0, 0);
640     return (rc == MEMCACHED_SUCCESS);
641   }
642 
643   /**
644    * Places a segment of data before the last piece of data stored.
645    *
646    * @param[in] key key of object whose value we will prepend data to
647    * @param[in] value data to prepend to object's value
648    * @return true on success; false otherwise
649    */
prepend(const std::string &key, const std::vector<char> &value)650   bool prepend(const std::string &key, const std::vector<char> &value)
651     throw(Error)
652   {
653     if (key.empty() || value.empty())
654     {
655       throw(Error("the key or value supplied is empty!", false));
656     }
657     memcached_return_t rc= memcached_prepend(&memc, key.c_str(), key.length(),
658                                            &value[0], value.size(), 0, 0);
659     return (rc == MEMCACHED_SUCCESS);
660   }
661 
662   /**
663    * Places a segment of data before the last piece of data stored. The
664    * server on which the object where we will be prepending data is stored
665    * on is specified by the master_key parameter.
666    *
667    * @param[in] master_key key of server where object is stored
668    * @param[in] key key of object whose value we will prepend data to
669    * @param[in] value data to prepend to object's value
670    * @return true on success; false otherwise
671    */
prependByKey(const std::string &master_key, const std::string &key, const std::vector<char> &value)672   bool prependByKey(const std::string &master_key,
673                     const std::string &key,
674                     const std::vector<char> &value)
675       throw(Error)
676   {
677     if (master_key.empty() ||
678         key.empty() ||
679         value.empty())
680     {
681       throw(Error("the master key or key supplied is empty!", false));
682     }
683     memcached_return_t rc= memcached_prepend_by_key(&memc,
684                                                   master_key.c_str(),
685                                                   master_key.length(),
686                                                   key.c_str(),
687                                                   key.length(),
688                                                   &value[0],
689                                                   value.size(),
690                                                   0,
691                                                   0);
692     return (rc == MEMCACHED_SUCCESS);
693   }
694 
695   /**
696    * Places a segment of data at the end of the last piece of data stored.
697    *
698    * @param[in] key key of object whose value we will append data to
699    * @param[in] value data to append to object's value
700    * @return true on success; false otherwise
701    */
append(const std::string &key, const std::vector<char> &value)702   bool append(const std::string &key, const std::vector<char> &value)
703     throw(Error)
704   {
705     if (key.empty() || value.empty())
706     {
707       throw(Error("the key or value supplied is empty!", false));
708     }
709     memcached_return_t rc= memcached_append(&memc,
710                                           key.c_str(),
711                                           key.length(),
712                                           &value[0],
713                                           value.size(),
714                                           0, 0);
715     return (rc == MEMCACHED_SUCCESS);
716   }
717 
718   /**
719    * Places a segment of data at the end of the last piece of data stored. The
720    * server on which the object where we will be appending data is stored
721    * on is specified by the master_key parameter.
722    *
723    * @param[in] master_key key of server where object is stored
724    * @param[in] key key of object whose value we will append data to
725    * @param[in] value data to append to object's value
726    * @return true on success; false otherwise
727    */
appendByKey(const std::string &master_key, const std::string &key, const std::vector<char> &value)728   bool appendByKey(const std::string &master_key,
729                    const std::string &key,
730                    const std::vector<char> &value)
731     throw(Error)
732   {
733     if (master_key.empty() ||
734         key.empty() ||
735         value.empty())
736     {
737       throw(Error("the master key or key supplied is empty!", false));
738     }
739     memcached_return_t rc= memcached_append_by_key(&memc,
740                                                  master_key.c_str(),
741                                                  master_key.length(),
742                                                  key.c_str(),
743                                                  key.length(),
744                                                  &value[0],
745                                                  value.size(),
746                                                  0, 0);
747     return (rc == MEMCACHED_SUCCESS);
748   }
749 
750   /**
751    * Overwrite data in the server as long as the cas_arg value
752    * is still the same in the server.
753    *
754    * @param[in] key key of object in server
755    * @param[in] value value to store for object in server
756    * @param[in] cas_arg "cas" value
757    */
cas(const std::string &key, const std::vector<char> &value, uint64_t cas_arg)758   bool cas(const std::string &key,
759            const std::vector<char> &value,
760            uint64_t cas_arg) throw(Error)
761   {
762     if (key.empty() || value.empty())
763     {
764       throw(Error("the key or value supplied is empty!", false));
765     }
766     memcached_return_t rc= memcached_cas(&memc, key.c_str(), key.length(),
767                                        &value[0], value.size(),
768                                        0, 0, cas_arg);
769     return (rc == MEMCACHED_SUCCESS);
770   }
771 
772   /**
773    * Overwrite data in the server as long as the cas_arg value
774    * is still the same in the server. The server to use is
775    * specified by the master_key parameter.
776    *
777    * @param[in] master_key specifies server to operate on
778    * @param[in] key key of object in server
779    * @param[in] value value to store for object in server
780    * @param[in] cas_arg "cas" value
781    */
casByKey(const std::string &master_key, const std::string &key, const std::vector<char> &value, uint64_t cas_arg)782   bool casByKey(const std::string &master_key,
783                 const std::string &key,
784                 const std::vector<char> &value,
785                 uint64_t cas_arg) throw(Error)
786   {
787     if (master_key.empty() ||
788         key.empty() ||
789         value.empty())
790     {
791       throw(Error("the master key, key or value supplied is empty!", false));
792     }
793     memcached_return_t rc= memcached_cas_by_key(&memc,
794                                               master_key.c_str(),
795                                               master_key.length(),
796                                               key.c_str(),
797                                               key.length(),
798                                               &value[0],
799                                               value.size(),
800                                               0, 0, cas_arg);
801     return (rc == MEMCACHED_SUCCESS);
802   }
803 
804   /**
805    * Delete an object from the server specified by the key given.
806    *
807    * @param[in] key key of object to delete
808    * @return true on success; false otherwise
809    */
remove(const std::string &key)810   bool remove(const std::string &key) throw(Error)
811   {
812     if (key.empty())
813     {
814       throw(Error("the key supplied is empty!", false));
815     }
816     memcached_return_t rc= memcached_delete(&memc, key.c_str(), key.length(), 0);
817     return (rc == MEMCACHED_SUCCESS);
818   }
819 
820   /**
821    * Delete an object from the server specified by the key given.
822    *
823    * @param[in] key key of object to delete
824    * @param[in] expiration time to delete the object after
825    * @return true on success; false otherwise
826    */
remove(const std::string &key, time_t expiration)827   bool remove(const std::string &key,
828               time_t expiration) throw(Error)
829   {
830     if (key.empty())
831     {
832       throw(Error("the key supplied is empty!", false));
833     }
834     memcached_return_t rc= memcached_delete(&memc,
835                                           key.c_str(),
836                                           key.length(),
837                                           expiration);
838     return (rc == MEMCACHED_SUCCESS);
839   }
840 
841   /**
842    * Delete an object from the server specified by the key given.
843    *
844    * @param[in] master_key specifies server to remove object from
845    * @param[in] key key of object to delete
846    * @return true on success; false otherwise
847    */
removeByKey(const std::string &master_key, const std::string &key)848   bool removeByKey(const std::string &master_key,
849                    const std::string &key) throw(Error)
850   {
851     if (master_key.empty() || key.empty())
852     {
853       throw(Error("the master key or key supplied is empty!", false));
854     }
855     memcached_return_t rc= memcached_delete_by_key(&memc,
856                                                  master_key.c_str(),
857                                                  master_key.length(),
858                                                  key.c_str(),
859                                                  key.length(),
860                                                  0);
861     return (rc == MEMCACHED_SUCCESS);
862   }
863 
864   /**
865    * Delete an object from the server specified by the key given.
866    *
867    * @param[in] master_key specifies server to remove object from
868    * @param[in] key key of object to delete
869    * @param[in] expiration time to delete the object after
870    * @return true on success; false otherwise
871    */
removeByKey(const std::string &master_key, const std::string &key, time_t expiration)872   bool removeByKey(const std::string &master_key,
873                    const std::string &key,
874                    time_t expiration) throw(Error)
875   {
876     if (master_key.empty() || key.empty())
877     {
878       throw(Error("the master key or key supplied is empty!", false));
879     }
880     memcached_return_t rc= memcached_delete_by_key(&memc,
881                                                  master_key.c_str(),
882                                                  master_key.length(),
883                                                  key.c_str(),
884                                                  key.length(),
885                                                  expiration);
886     return (rc == MEMCACHED_SUCCESS);
887   }
888 
889   /**
890    * Wipe the contents of memcached servers.
891    *
892    * @param[in] expiration time to wait until wiping contents of
893    *                       memcached servers
894    * @return true on success; false otherwise
895    */
flush(time_t expiration)896   bool flush(time_t expiration)
897   {
898     memcached_return_t rc= memcached_flush(&memc, expiration);
899     return (rc == MEMCACHED_SUCCESS);
900   }
901 
902   /**
903    * Callback function for result sets. It passes the result
904    * sets to the list of functions provided.
905    *
906    * @param[in] callback list of callback functions
907    * @param[in] context pointer to memory reference that is
908    *                    supplied to the calling function
909    * @param[in] num_of_callbacks number of callback functions
910    * @return true on success; false otherwise
911    */
fetchExecute(memcached_execute_fn *callback, void *context, uint32_t num_of_callbacks)912   bool fetchExecute(memcached_execute_fn *callback,
913                     void *context,
914                     uint32_t num_of_callbacks)
915   {
916     memcached_return_t rc= memcached_fetch_execute(&memc,
917                                                  callback,
918                                                  context,
919                                                  num_of_callbacks);
920     return (rc == MEMCACHED_SUCCESS);
921   }
922 
923   /**
924    * Get the library version string.
925    * @return std::string containing a copy of the library version string.
926    */
libVersion() const927   const std::string libVersion() const
928   {
929     const char *ver= memcached_lib_version();
930     const std::string version(ver);
931     return version;
932   }
933 
934   /**
935    * Retrieve memcached statistics. Populate a std::map with the retrieved
936    * stats. Each server will map to another std::map of the key:value stats.
937    *
938    * @param[out] stats_map a std::map to be populated with the memcached
939    *                       stats
940    * @return true on success; false otherwise
941    */
getStats(std::map< std::string, std::map<std::string, std::string> > &stats_map)942   bool getStats(std::map< std::string, std::map<std::string, std::string> >
943                 &stats_map)
944   {
945     memcached_return_t rc;
946     memcached_stat_st *stats= memcached_stat(&memc, NULL, &rc);
947 
948     if (rc != MEMCACHED_SUCCESS &&
949         rc != MEMCACHED_SOME_ERRORS)
950     {
951       return false;
952     }
953 
954     uint32_t server_count= memcached_server_count(&memc);
955 
956     /*
957      * For each memcached server, construct a std::map for its stats and add
958      * it to the std::map of overall stats.
959      */
960     for (uint32_t x= 0; x < server_count; x++)
961     {
962       memcached_server_instance_st instance=
963         memcached_server_instance_by_position(&memc, x);
964       std::ostringstream strstm;
965       std::string server_name(memcached_server_name(instance));
966       server_name.append(":");
967       strstm << memcached_server_port(instance);
968       server_name.append(strstm.str());
969 
970       std::map<std::string, std::string> server_stats;
971       char **list= NULL;
972       char **ptr= NULL;
973 
974       list= memcached_stat_get_keys(&memc, &stats[x], &rc);
975       for (ptr= list; *ptr; ptr++)
976       {
977         char *value= memcached_stat_get_value(&memc, &stats[x], *ptr, &rc);
978         server_stats[*ptr]= value;
979         free(value);
980       }
981 
982       stats_map[server_name]= server_stats;
983       free(list);
984     }
985 
986     memcached_stat_free(&memc, stats);
987     return true;
988   }
989 
990 private:
991 
992   std::string servers_list;
993   memcached_st memc;
994   memcached_result_st result;
995 };
996 
997 }
998 
999 #endif /* LIBMEMCACHEDPP_H */
1000