Const issue for C++ include.
[m6w6/libmemcached] / libmemcached-1.0 / memcached.hpp
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
76 Memcache()
77 {
78 memc= memcached("", 0);
79 }
80
81 Memcache(const std::string &config)
82 {
83 memc= memcached(config.c_str(), config.size());
84 }
85
86 Memcache(const std::string &hostname, in_port_t port)
87 {
88 memc= memcached("", 0);
89 if (memc)
90 {
91 memcached_server_add(memc, hostname.c_str(), port);
92 }
93 }
94
95 Memcache(memcached_st *clone)
96 {
97 memc= memcached_clone(NULL, clone);
98 }
99
100 Memcache(const Memcache &rhs)
101 {
102 memc= memcached_clone(NULL, rhs.getImpl());
103 }
104
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
116 ~Memcache()
117 {
118 memcached_free(memc);
119 }
120
121 /**
122 * Get the internal memcached_st *
123 */
124 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 */
135 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
141 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
152 bool error() const
153 {
154 if (memcached_failed(memcached_last_error(memc)))
155 {
156 return true;
157 }
158
159 return false;
160 }
161
162 bool error(memcached_return_t& arg) const
163 {
164 arg= memcached_last_error(memc);
165 return memcached_failed(arg);
166 }
167
168 bool setBehavior(memcached_behavior_t flag, uint64_t data)
169 {
170 return (memcached_success(memcached_behavior_set(memc, flag, data)));
171 }
172
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 */
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 */
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 */
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 */
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));
258
259 // Misc
260 flags= memcached_result_flags(result);
261 cas_value= memcached_result_cas(result);
262 }
263 memcached_result_free(result);
264
265 return rc;
266 }
267
268 memcached_return_t fetch(std::string &key,
269 std::vector<char> &ret_val)
270 {
271 uint32_t flags= 0;
272 uint64_t cas_value= 0;
273
274 return fetch(key, ret_val, flags, cas_value);
275 }
276
277 /**
278 * Fetches an individual value from the server.
279 *
280 * @param[in] key key of object whose value to get
281 * @param[out] ret_val object that is retrieved is stored in
282 * this vector
283 * @return true on success; false otherwise
284 */
285 bool get(const std::string &key, std::vector<char> &ret_val)
286 {
287 uint32_t flags= 0;
288 memcached_return_t rc;
289 size_t value_length= 0;
290
291 char *value= memcached_get(memc, key.c_str(), key.length(),
292 &value_length, &flags, &rc);
293 if (value != NULL && ret_val.empty())
294 {
295 ret_val.reserve(value_length);
296 ret_val.assign(value, value +value_length);
297 free(value);
298 return true;
299 }
300
301 return false;
302 }
303
304 /**
305 * Fetches an individual from a server which is specified by
306 * the master_key parameter that is used for determining which
307 * server an object was stored in if key partitioning was
308 * used for storage.
309 *
310 * @param[in] master_key key that specifies server object is stored on
311 * @param[in] key key of object whose value to get
312 * @param[out] ret_val object that is retrieved is stored in
313 * this vector
314 * @return true on success; false otherwise
315 */
316 bool getByKey(const std::string &master_key,
317 const std::string &key,
318 std::vector<char> &ret_val)
319 {
320 uint32_t flags= 0;
321 memcached_return_t rc;
322 size_t value_length= 0;
323
324 char *value= memcached_get_by_key(memc,
325 master_key.c_str(), master_key.length(),
326 key.c_str(), key.length(),
327 &value_length, &flags, &rc);
328 if (value)
329 {
330 ret_val.reserve(value_length);
331 ret_val.assign(value, value +value_length);
332 free(value);
333 return true;
334 }
335 return false;
336 }
337
338 /**
339 * Selects multiple keys at once. This method always
340 * works asynchronously.
341 *
342 * @param[in] keys vector of keys to select
343 * @return true if all keys are found
344 */
345 bool mget(const std::vector<std::string>& keys)
346 {
347 std::vector<const char *> real_keys;
348 std::vector<size_t> key_len;
349 /*
350 * Construct an array which will contain the length
351 * of each of the strings in the input vector. Also, to
352 * interface with the memcached C API, we need to convert
353 * the vector of std::string's to a vector of char *.
354 */
355 real_keys.reserve(keys.size());
356 key_len.reserve(keys.size());
357
358 std::vector<std::string>::const_iterator it= keys.begin();
359
360 while (it != keys.end())
361 {
362 real_keys.push_back(const_cast<char *>((*it).c_str()));
363 key_len.push_back((*it).length());
364 ++it;
365 }
366
367 /*
368 * If the std::vector of keys is empty then we cannot
369 * call memcached_mget as we will get undefined behavior.
370 */
371 if (not real_keys.empty())
372 {
373 return memcached_success(memcached_mget(memc, &real_keys[0], &key_len[0], real_keys.size()));
374 }
375
376 return false;
377 }
378
379 /**
380 * Writes an object to the server. If the object already exists, it will
381 * overwrite the existing object. This method always returns true
382 * when using non-blocking mode unless a network error occurs.
383 *
384 * @param[in] key key of object to write to server
385 * @param[in] value value of object to write to server
386 * @param[in] expiration time to keep the object stored in the server for
387 * @param[in] flags flags to store with the object
388 * @return true on succcess; false otherwise
389 */
390 bool set(const std::string &key,
391 const std::vector<char> &value,
392 time_t expiration,
393 uint32_t flags)
394 {
395 memcached_return_t rc= memcached_set(memc,
396 key.c_str(), key.length(),
397 &value[0], value.size(),
398 expiration, flags);
399 return memcached_success(rc);
400 }
401
402 /**
403 * Writes an object to a server specified by the master_key parameter.
404 * If the object already exists, it will overwrite the existing object.
405 *
406 * @param[in] master_key key that specifies server to write to
407 * @param[in] key key of object to write to server
408 * @param[in] value value of object to write to server
409 * @param[in] expiration time to keep the object stored in the server for
410 * @param[in] flags flags to store with the object
411 * @return true on succcess; false otherwise
412 */
413 bool setByKey(const std::string& master_key,
414 const std::string& key,
415 const std::vector<char> &value,
416 time_t expiration,
417 uint32_t flags)
418 {
419 return memcached_success(memcached_set_by_key(memc, master_key.c_str(),
420 master_key.length(),
421 key.c_str(), key.length(),
422 &value[0], value.size(),
423 expiration,
424 flags));
425 }
426
427 /**
428 * Writes a list of objects to the server. Objects are specified by
429 * 2 vectors - 1 vector of keys and 1 vector of values.
430 *
431 * @param[in] keys vector of keys of objects to write to server
432 * @param[in] values vector of values of objects to write to server
433 * @param[in] expiration time to keep the objects stored in server for
434 * @param[in] flags flags to store with the objects
435 * @return true on success; false otherwise
436 */
437 bool setAll(const std::vector<std::string>& keys,
438 const std::vector< std::vector<char> *>& values,
439 time_t expiration,
440 uint32_t flags)
441 {
442 bool retval= true;
443 std::vector<std::string>::const_iterator key_it= keys.begin();
444 std::vector< std::vector<char> *>::const_iterator val_it= values.begin();
445 while (key_it != keys.end())
446 {
447 retval= set((*key_it), *(*val_it), expiration, flags);
448 if (retval == false)
449 {
450 return retval;
451 }
452 ++key_it;
453 ++val_it;
454 }
455 return retval;
456 }
457
458 /**
459 * Writes a list of objects to the server. Objects are specified by
460 * a map of keys to values.
461 *
462 * @param[in] key_value_map map of keys and values to store in server
463 * @param[in] expiration time to keep the objects stored in server for
464 * @param[in] flags flags to store with the objects
465 * @return true on success; false otherwise
466 */
467 bool setAll(const std::map<const std::string, std::vector<char> >& key_value_map,
468 time_t expiration,
469 uint32_t flags)
470 {
471 bool retval= true;
472 std::map<const std::string, std::vector<char> >::const_iterator it= key_value_map.begin();
473
474 while (it != key_value_map.end())
475 {
476 retval= set(it->first, it->second, expiration, flags);
477 if (retval == false)
478 {
479 // We should tell the user what the key that failed was
480 return false;
481 }
482 ++it;
483 }
484
485 return true;
486 }
487
488 /**
489 * Increment the value of the object associated with the specified
490 * key by the offset given. The resulting value is saved in the value
491 * parameter.
492 *
493 * @param[in] key key of object in server whose value to increment
494 * @param[in] offset amount to increment object's value by
495 * @param[out] value store the result of the increment here
496 * @return true on success; false otherwise
497 */
498 bool increment(const std::string& key, uint32_t offset, uint64_t *value)
499 {
500 return memcached_success(memcached_increment(memc, key.c_str(), key.length(), offset, value));
501 }
502
503 /**
504 * Decrement the value of the object associated with the specified
505 * key by the offset given. The resulting value is saved in the value
506 * parameter.
507 *
508 * @param[in] key key of object in server whose value to decrement
509 * @param[in] offset amount to increment object's value by
510 * @param[out] value store the result of the decrement here
511 * @return true on success; false otherwise
512 */
513 bool decrement(const std::string& key, uint32_t offset, uint64_t *value)
514 {
515 return memcached_success(memcached_decrement(memc, key.c_str(),
516 key.length(),
517 offset, value));
518 }
519
520
521 /**
522 * Add an object with the specified key and value to the server. This
523 * function returns false if the object already exists on the server.
524 *
525 * @param[in] key key of object to add
526 * @param[in] value of object to add
527 * @return true on success; false otherwise
528 */
529 bool add(const std::string& key, const std::vector<char>& value)
530 {
531 return memcached_success(memcached_add(memc, key.c_str(), key.length(),
532 &value[0], value.size(), 0, 0));
533 }
534
535 /**
536 * Add an object with the specified key and value to the server. This
537 * function returns false if the object already exists on the server. The
538 * server to add the object to is specified by the master_key parameter.
539 *
540 * @param[in[ master_key key of server to add object to
541 * @param[in] key key of object to add
542 * @param[in] value of object to add
543 * @return true on success; false otherwise
544 */
545 bool addByKey(const std::string& master_key,
546 const std::string& key,
547 const std::vector<char>& value)
548 {
549 return memcached_success(memcached_add_by_key(memc,
550 master_key.c_str(),
551 master_key.length(),
552 key.c_str(),
553 key.length(),
554 &value[0],
555 value.size(),
556 0, 0));
557 }
558
559 /**
560 * Replaces an object on the server. This method only succeeds
561 * if the object is already present on the server.
562 *
563 * @param[in] key key of object to replace
564 * @param[in[ value value to replace object with
565 * @return true on success; false otherwise
566 */
567 bool replace(const std::string& key, const std::vector<char>& value)
568 {
569 return memcached_success(memcached_replace(memc, key.c_str(), key.length(),
570 &value[0], value.size(),
571 0, 0));
572 }
573
574 /**
575 * Replaces an object on the server. This method only succeeds
576 * if the object is already present on the server. The server
577 * to replace the object on is specified by the master_key param.
578 *
579 * @param[in] master_key key of server to replace object on
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 */
584 bool replaceByKey(const std::string& master_key,
585 const std::string& key,
586 const std::vector<char>& value)
587 {
588 return memcached_success(memcached_replace_by_key(memc,
589 master_key.c_str(),
590 master_key.length(),
591 key.c_str(),
592 key.length(),
593 &value[0],
594 value.size(),
595 0, 0));
596 }
597
598 /**
599 * Places a segment of data before the last piece of data stored.
600 *
601 * @param[in] key key of object whose value we will prepend data to
602 * @param[in] value data to prepend to object's value
603 * @return true on success; false otherwise
604 */
605 bool prepend(const std::string& key, const std::vector<char>& value)
606 {
607 return memcached_success(memcached_prepend(memc, key.c_str(), key.length(),
608 &value[0], value.size(), 0, 0));
609 }
610
611 /**
612 * Places a segment of data before the last piece of data stored. The
613 * server on which the object where we will be prepending data is stored
614 * on is specified by the master_key parameter.
615 *
616 * @param[in] master_key key of server where object is stored
617 * @param[in] key key of object whose value we will prepend data to
618 * @param[in] value data to prepend to object's value
619 * @return true on success; false otherwise
620 */
621 bool prependByKey(const std::string& master_key,
622 const std::string& key,
623 const std::vector<char>& value)
624 {
625 return memcached_success(memcached_prepend_by_key(memc,
626 master_key.c_str(),
627 master_key.length(),
628 key.c_str(),
629 key.length(),
630 &value[0],
631 value.size(),
632 0,
633 0));
634 }
635
636 /**
637 * Places a segment of data at the end of the last piece of data stored.
638 *
639 * @param[in] key key of object whose value we will append data to
640 * @param[in] value data to append to object's value
641 * @return true on success; false otherwise
642 */
643 bool append(const std::string& key, const std::vector<char>& value)
644 {
645 return memcached_success(memcached_append(memc,
646 key.c_str(),
647 key.length(),
648 &value[0],
649 value.size(),
650 0, 0));
651 }
652
653 /**
654 * Places a segment of data at the end of the last piece of data stored. The
655 * server on which the object where we will be appending data is stored
656 * on is specified by the master_key parameter.
657 *
658 * @param[in] master_key key of server where object is stored
659 * @param[in] key key of object whose value we will append data to
660 * @param[in] value data to append to object's value
661 * @return true on success; false otherwise
662 */
663 bool appendByKey(const std::string& master_key,
664 const std::string& key,
665 const std::vector<char> &value)
666 {
667 return memcached_success(memcached_append_by_key(memc,
668 master_key.c_str(),
669 master_key.length(),
670 key.c_str(),
671 key.length(),
672 &value[0],
673 value.size(),
674 0, 0));
675 }
676
677 /**
678 * Overwrite data in the server as long as the cas_arg value
679 * is still the same in the server.
680 *
681 * @param[in] key key of object in server
682 * @param[in] value value to store for object in server
683 * @param[in] cas_arg "cas" value
684 */
685 bool cas(const std::string& key,
686 const std::vector<char>& value,
687 uint64_t cas_arg)
688 {
689 return memcached_success(memcached_cas(memc, key.c_str(), key.length(),
690 &value[0], value.size(),
691 0, 0, cas_arg));
692 }
693
694 /**
695 * Overwrite data in the server as long as the cas_arg value
696 * is still the same in the server. The server to use is
697 * specified by the master_key parameter.
698 *
699 * @param[in] master_key specifies server to operate on
700 * @param[in] key key of object in server
701 * @param[in] value value to store for object in server
702 * @param[in] cas_arg "cas" value
703 */
704 bool casByKey(const std::string& master_key,
705 const std::string& key,
706 const std::vector<char> &value,
707 uint64_t cas_arg)
708 {
709 return memcached_success(memcached_cas_by_key(memc,
710 master_key.c_str(),
711 master_key.length(),
712 key.c_str(),
713 key.length(),
714 &value[0],
715 value.size(),
716 0, 0, cas_arg));
717 }
718
719 /**
720 * Delete an object from the server specified by the key given.
721 *
722 * @param[in] key key of object to delete
723 * @return true on success; false otherwise
724 */
725 bool remove(const std::string& key)
726 {
727 return memcached_success(memcached_delete(memc, key.c_str(), key.length(), 0));
728 }
729
730 /**
731 * Delete an object from the server specified by the key given.
732 *
733 * @param[in] key key of object to delete
734 * @param[in] expiration time to delete the object after
735 * @return true on success; false otherwise
736 */
737 bool remove(const std::string& key, time_t expiration)
738 {
739 return memcached_success(memcached_delete(memc,
740 key.c_str(),
741 key.length(),
742 expiration));
743 }
744
745 /**
746 * Delete an object from the server specified by the key given.
747 *
748 * @param[in] master_key specifies server to remove object from
749 * @param[in] key key of object to delete
750 * @return true on success; false otherwise
751 */
752 bool removeByKey(const std::string& master_key,
753 const std::string& key)
754 {
755 return memcached_success(memcached_delete_by_key(memc,
756 master_key.c_str(),
757 master_key.length(),
758 key.c_str(),
759 key.length(),
760 0));
761 }
762
763 /**
764 * Delete an object from the server specified by the key given.
765 *
766 * @param[in] master_key specifies server to remove object from
767 * @param[in] key key of object to delete
768 * @param[in] expiration time to delete the object after
769 * @return true on success; false otherwise
770 */
771 bool removeByKey(const std::string& master_key,
772 const std::string& key,
773 time_t expiration)
774 {
775 return memcached_success(memcached_delete_by_key(memc,
776 master_key.c_str(),
777 master_key.length(),
778 key.c_str(),
779 key.length(),
780 expiration));
781 }
782
783 /**
784 * Wipe the contents of memcached servers.
785 *
786 * @param[in] expiration time to wait until wiping contents of
787 * memcached servers
788 * @return true on success; false otherwise
789 */
790 bool flush(time_t expiration= 0)
791 {
792 return memcached_success(memcached_flush(memc, expiration));
793 }
794
795 /**
796 * Get the library version string.
797 * @return std::string containing a copy of the library version string.
798 */
799 const std::string libVersion() const
800 {
801 const char *ver= memcached_lib_version();
802 const std::string version(ver);
803 return version;
804 }
805
806 /**
807 * Retrieve memcached statistics. Populate a std::map with the retrieved
808 * stats. Each server will map to another std::map of the key:value stats.
809 *
810 * @param[out] stats_map a std::map to be populated with the memcached
811 * stats
812 * @return true on success; false otherwise
813 */
814 bool getStats(std::map< std::string, std::map<std::string, std::string> >& stats_map)
815 {
816 memcached_return_t rc;
817 memcached_stat_st *stats= memcached_stat(memc, NULL, &rc);
818
819 if (rc != MEMCACHED_SUCCESS &&
820 rc != MEMCACHED_SOME_ERRORS)
821 {
822 return false;
823 }
824
825 uint32_t server_count= memcached_server_count(memc);
826
827 /*
828 * For each memcached server, construct a std::map for its stats and add
829 * it to the std::map of overall stats.
830 */
831 for (uint32_t x= 0; x < server_count; x++)
832 {
833 memcached_server_instance_st instance= memcached_server_instance_by_position(memc, x);
834 std::ostringstream strstm;
835 std::string server_name(memcached_server_name(instance));
836 server_name.append(":");
837 strstm << memcached_server_port(instance);
838 server_name.append(strstm.str());
839
840 std::map<std::string, std::string> server_stats;
841 char **list= memcached_stat_get_keys(memc, &stats[x], &rc);
842 for (char** ptr= list; *ptr; ptr++)
843 {
844 char *value= memcached_stat_get_value(memc, &stats[x], *ptr, &rc);
845 server_stats[*ptr]= value;
846 free(value);
847 }
848
849 stats_map[server_name]= server_stats;
850 free(list);
851 }
852
853 memcached_stat_free(memc, stats);
854 return true;
855 }
856
857 private:
858 memcached_st *memc;
859 };
860
861 }