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