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