silence unused parameters in ext_memcached.cpp
[hiphop-php.git] / hphp / runtime / ext / memcached / ext_memcached.cpp
blob979edbaaf573e20de169ae8f13c88294701d33ce
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010 Hyves (http://www.hyves.nl) |
6 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
7 | Copyright (c) 1997-2010 The PHP Group |
8 +----------------------------------------------------------------------+
9 | This source file is subject to version 3.01 of the PHP license, |
10 | that is bundled with this package in the file LICENSE, and is |
11 | available through the world-wide-web at the following url: |
12 | http://www.php.net/license/3_01.txt |
13 | If you did not receive a copy of the PHP license and are unable to |
14 | obtain it through the world-wide-web, please send a note to |
15 | license@php.net so we can mail you a copy immediately. |
16 +----------------------------------------------------------------------+
19 #include "hphp/runtime/base/array-init.h"
20 #include "hphp/runtime/ext/extension.h"
21 #include "hphp/runtime/vm/native-data.h"
22 #include "hphp/runtime/ext/memcached/libmemcached_portability.h"
23 #include "hphp/runtime/base/builtin-functions.h"
24 #include "hphp/runtime/ext/json/ext_json.h"
25 #include <map>
26 #include <memory>
27 #include <vector>
28 #include <fastlz.h>
29 #include <zlib.h>
31 #include "hphp/system/systemlib.h"
33 namespace HPHP {
34 ///////////////////////////////////////////////////////////////////////////////
36 // Payload value flags
37 #define MEMC_VAL_TYPE_MASK 0xf
39 #define MEMC_VAL_IS_STRING 0
40 #define MEMC_VAL_IS_LONG 1
41 #define MEMC_VAL_IS_DOUBLE 2
42 #define MEMC_VAL_IS_BOOL 3
43 #define MEMC_VAL_IS_SERIALIZED 4
44 #define MEMC_VAL_IS_IGBINARY 5
45 #define MEMC_VAL_IS_JSON 6
47 #define MEMC_VAL_COMPRESSED (1<<4)
48 #define MEMC_VAL_COMPRESSION_ZLIB (1<<5)
49 #define MEMC_VAL_COMPRESSION_FASTLZ (1<<6)
51 #define MEMC_COMPRESS_THRESHOLD 100
53 #if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX < 0x00052000
54 # define MEMCACHED_SERVER_TEMPORARILY_DISABLED (1024 << 2)
55 #endif
57 #if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX >= 0x01000002
58 # define HAVE_MEMCACHED_TOUCH 1
59 #endif
61 // Class options
62 const int64_t q_Memcached$$OPT_COMPRESSION = -1001;
63 const int64_t q_Memcached$$OPT_PREFIX_KEY = -1002;
64 const int64_t q_Memcached$$OPT_SERIALIZER = -1003;
66 // Our result codes
67 const int64_t q_Memcached$$RES_PAYLOAD_FAILURE = -1001;
69 // Serializer types
70 const int64_t q_Memcached$$SERIALIZER_PHP = 1;
71 const int64_t q_Memcached$$SERIALIZER_IGBINARY = 2;
72 const int64_t q_Memcached$$SERIALIZER_JSON = 3;
74 // Flags
75 const int64_t q_Memcached$$GET_PRESERVE_ORDER = 1;
77 // Keys
78 const StaticString
79 s_key("key"),
80 s_value("value"),
81 s_cas("cas");
83 // INI settings
84 struct MEMCACHEDGlobals final {
85 std::string sess_prefix;
87 static __thread MEMCACHEDGlobals* s_memcached_globals;
88 #define MEMCACHEDG(name) s_memcached_globals->name
90 namespace {
91 struct MemcachedResultWrapper {
92 memcached_result_st value;
93 explicit MemcachedResultWrapper(memcached_st *memcached) {
94 memcached_result_create(memcached, &value);
96 ~MemcachedResultWrapper() {
97 memcached_result_free(&value);
103 * Since libmemcachd is in C, we cannot use lambda functions as lambda functions
104 * are special typed and normally passed by templated types.
106 static memcached_return_t memcached_dump_callback(const memcached_st*,
107 const char* key,
108 size_t len, void* context) {
109 ((Array*)context)->append(Variant{makeStaticString(key, len)});
110 return MEMCACHED_SUCCESS;
113 const StaticString s_MemcachedData("MemcachedData");
115 struct MemcachedData {
116 struct Impl {
117 Impl() :
118 compression(true),
119 serializer(q_Memcached$$SERIALIZER_PHP),
120 rescode(MEMCACHED_SUCCESS) {
121 memcached_create(&memcached);
123 ~Impl() {
124 memcached_free(&memcached);
127 memcached_st memcached;
128 bool compression;
129 int serializer;
130 int rescode;
131 bool is_persistent;
132 bool is_pristine;
134 MemcachedData() {}
135 ~MemcachedData() {}
137 typedef std::shared_ptr<Impl> ImplPtr;
138 ImplPtr m_impl;
140 bool handleError(memcached_return status) {
141 switch (status) {
142 case MEMCACHED_SUCCESS:
143 case MEMCACHED_STORED:
144 case MEMCACHED_DELETED:
145 case MEMCACHED_STAT:
146 return true;
147 case MEMCACHED_END:
148 case MEMCACHED_BUFFERED:
149 m_impl->rescode = status;
150 return true;
151 default:
152 m_impl->rescode = status;
153 return false;
156 void toPayload(const Variant& value, std::vector<char> &payload,
157 uint32_t &flags) {
158 String encoded;
159 if (value.isString() || value.isNumeric()) {
160 encoded = value.toString();
161 if (value.isString()) flags = MEMC_VAL_IS_STRING;
162 else if (value.isInteger()) flags = MEMC_VAL_IS_LONG;
163 else if (value.isDouble()) flags = MEMC_VAL_IS_DOUBLE;
164 else if (value.isBoolean()) flags = MEMC_VAL_IS_BOOL;
165 else not_reached();
166 } else {
167 switch (m_impl->serializer) {
168 case q_Memcached$$SERIALIZER_JSON:
169 encoded = Variant::attach(HHVM_FN(json_encode)(value)).toString();
170 flags = MEMC_VAL_IS_JSON;
171 break;
172 default:
173 encoded = f_serialize(value);
174 flags = MEMC_VAL_IS_SERIALIZED;
175 break;
179 if (m_impl->compression && encoded.length() >= MEMC_COMPRESS_THRESHOLD) {
180 unsigned long payloadCompLength = compressBound(encoded.length());
181 payload.resize(payloadCompLength);
182 if (compress((Bytef*)payload.data(), &payloadCompLength,
183 (const Bytef*)encoded.data(), encoded.length()) == Z_OK) {
184 payload.resize(payloadCompLength);
185 flags |= MEMC_VAL_COMPRESSED;
186 return;
188 raise_warning("could not compress value");
191 payload.resize(0);
192 payload.insert(payload.end(),
193 encoded.data(), encoded.data() + encoded.length());
195 bool toObject(Variant& value, const memcached_result_st &result) {
196 const char *payload = memcached_result_value(&result);
197 size_t payloadLength = memcached_result_length(&result);
198 uint32_t flags = memcached_result_flags(&result);
200 String decompPayload;
201 if (flags & MEMC_VAL_COMPRESSED) {
202 bool done = false;
203 std::vector<char> buffer;
204 unsigned long bufferSize;
205 uint32_t maxLength;
206 int status;
208 /* new-style */
209 if ((flags & MEMC_VAL_COMPRESSION_FASTLZ ||
210 flags & MEMC_VAL_COMPRESSION_ZLIB)
211 && payloadLength > sizeof(uint32_t)) {
212 memcpy(&maxLength, payload, sizeof(uint32_t));
213 if (maxLength < std::numeric_limits<uint32_t>::max()) {
214 buffer.resize(maxLength + 1);
215 payloadLength -= sizeof(uint32_t);
216 payload += sizeof(uint32_t);
217 bufferSize = maxLength;
219 if (flags & MEMC_VAL_COMPRESSION_FASTLZ) {
220 bufferSize = fastlz_decompress(payload, payloadLength,
221 buffer.data(), maxLength);
222 done = (bufferSize > 0);
223 } else if (flags & MEMC_VAL_COMPRESSION_ZLIB) {
224 status = uncompress((Bytef *)buffer.data(), &bufferSize,
225 (const Bytef *)payload, (uLong)payloadLength);
226 done = (status == Z_OK);
231 /* old-style */
232 if (!done) {
233 for (int factor = 1; factor <= 16; ++factor) {
234 if (payloadLength >=
235 std::numeric_limits<unsigned long>::max() / (1 << factor)) {
236 break;
238 bufferSize = payloadLength * (1 << factor) + 1;
239 buffer.resize(bufferSize);
240 status = uncompress((Bytef*)buffer.data(), &bufferSize,
241 (const Bytef*)payload, (uLong)payloadLength);
242 if (status == Z_OK) {
243 done = true;
244 break;
245 } else if (status != Z_BUF_ERROR) {
246 break;
250 if (!done) {
251 raise_warning("could not uncompress value");
252 return false;
254 decompPayload =
255 String::attach(StringData::Make(buffer.data(), bufferSize, CopyString));
256 } else {
257 decompPayload =
258 String::attach(StringData::Make(payload, payloadLength, CopyString));
261 switch (flags & MEMC_VAL_TYPE_MASK) {
262 case MEMC_VAL_IS_STRING:
263 value = decompPayload;
264 break;
265 case MEMC_VAL_IS_LONG:
266 value = decompPayload.toInt64();
267 break;
268 case MEMC_VAL_IS_DOUBLE:
269 value = decompPayload.toDouble();
270 break;
271 case MEMC_VAL_IS_BOOL:
272 value = decompPayload.toBoolean();
273 break;
274 case MEMC_VAL_IS_JSON:
275 value = Variant::attach(HHVM_FN(json_decode)(decompPayload));
276 break;
277 case MEMC_VAL_IS_SERIALIZED:
278 value = unserialize_from_string(decompPayload);
279 break;
280 case MEMC_VAL_IS_IGBINARY:
281 raise_warning("could not unserialize value, no igbinary support");
282 return false;
283 default:
284 raise_warning("unknown payload type");
285 return false;
287 return true;
289 memcached_return doCacheCallback(const Variant& callback, ObjectData* this_,
290 const String& key, Variant& value) {
291 Array params(PackedArrayInit(3).append(Variant(this_))
292 .append(key)
293 .appendRef(value).toArray());
294 if (!vm_call_user_func(callback, params).toBoolean()) {
295 return MEMCACHED_NOTFOUND;
298 std::vector<char> payload; uint32_t flags;
299 toPayload(value, payload, flags);
300 return memcached_set(&m_impl->memcached, key.c_str(), key.length(),
301 payload.data(), payload.size(), 0, flags);
303 bool getMultiImpl(const String& server_key, const Array& keys, bool enableCas,
304 Array *returnValue) {
305 std::vector<const char*> keysCopy;
306 keysCopy.reserve(keys.size());
307 std::vector<size_t> keysLengthCopy;
308 keysLengthCopy.reserve(keys.size());
309 for (ArrayIter iter(keys); iter; ++iter) {
310 Variant vKey = iter.second();
311 if (!vKey.isString()) continue;
312 StringData *key = vKey.getStringData();
313 if (key->empty()) continue;
314 keysCopy.push_back(key->data());
315 keysLengthCopy.push_back(key->size());
316 if (returnValue) returnValue->set(String(key), init_null(), true);
318 if (keysCopy.size() == 0) {
319 m_impl->rescode = MEMCACHED_BAD_KEY_PROVIDED;
320 return false;
323 memcached_behavior_set(&m_impl->memcached, MEMCACHED_BEHAVIOR_SUPPORT_CAS,
324 enableCas ? 1 : 0);
325 const char *myServerKey = server_key.empty() ? nullptr : server_key.c_str();
326 size_t myServerKeyLen = server_key.length();
327 return handleError(memcached_mget_by_key(&m_impl->memcached,
328 myServerKey, myServerKeyLen, keysCopy.data(), keysLengthCopy.data(),
329 keysCopy.size()));
331 bool fetchImpl(memcached_result_st &result, Array &item) {
332 memcached_return status;
333 if (!memcached_fetch_result(&m_impl->memcached, &result, &status)) {
334 handleError(status);
335 return false;
338 Variant value;
339 if (!toObject(value, result)) {
340 m_impl->rescode = q_Memcached$$RES_PAYLOAD_FAILURE;
341 return false;
344 const char *key = memcached_result_key_value(&result);
345 size_t keyLength = memcached_result_key_length(&result);
346 String sKey(key, keyLength, CopyString);
347 double cas = (double) memcached_result_cas(&result);
349 item = make_map_array(s_key, sKey, s_value, value, s_cas, cas);
350 return true;
352 typedef memcached_return_t (*SetOperation)(memcached_st *,
353 const char *, size_t, const char *, size_t, const char *, size_t,
354 time_t, uint32_t);
356 bool setOperationImpl(SetOperation op, const String& server_key,
357 const String& key, const Variant& value,
358 int expiration) {
359 m_impl->rescode = MEMCACHED_SUCCESS;
360 if (key.empty()) {
361 m_impl->rescode = MEMCACHED_BAD_KEY_PROVIDED;
362 return false;
365 std::vector<char> payload; uint32_t flags;
366 toPayload(value, payload, flags);
368 const String& myServerKey = server_key.empty() ? key : server_key;
369 return handleError(op(&m_impl->memcached, myServerKey.c_str(),
370 myServerKey.length(), key.c_str(), key.length(),
371 payload.data(), payload.size(), expiration, flags));
374 Variant incDecOp(bool isInc,
375 const StringData* server_key, const StringData* key,
376 int64_t offset, const Variant& initial_value, int64_t expiry) {
377 m_impl->rescode = MEMCACHED_SUCCESS;
378 if (key->empty() || strchr(key->data(), ' ')) {
379 m_impl->rescode = MEMCACHED_BAD_KEY_PROVIDED;
380 return false;
382 if (offset < 0) {
383 raise_warning("offset has to be >= 0");
384 return false;
387 // Dispatch to the correct memcached_* function depending on initial_value,
388 // server_key, and isInc.
389 uint64_t value;
390 memcached_return_t status;
392 bool use_initial = initial_value.isInteger();
393 auto mc = &m_impl->memcached;
394 if (use_initial) {
395 if (!isBinaryProtocol()) {
396 raise_warning("Initial value is only supported with binary protocol");
397 return false;
400 if (server_key) {
401 if (isInc) {
402 status = memcached_increment_with_initial_by_key(
404 server_key->data(), server_key->size(), key->data(), key->size(),
405 offset, initial_value.asInt64Val(), expiry, &value);
406 } else {
407 status = memcached_decrement_with_initial_by_key(
409 server_key->data(), server_key->size(), key->data(), key->size(),
410 offset, initial_value.asInt64Val(), expiry, &value);
412 } else {
413 if (isInc) {
414 status = memcached_increment_with_initial(
415 mc, key->data(), key->size(),
416 offset, initial_value.asInt64Val(), expiry, &value);
417 } else {
418 status = memcached_decrement_with_initial(
419 mc, key->data(), key->size(),
420 offset, initial_value.asInt64Val(), expiry, &value);
423 } else {
424 if (server_key) {
425 if (isInc) {
426 status = memcached_increment_by_key(
428 server_key->data(), server_key->size(), key->data(), key->size(),
429 offset, &value);
430 } else {
431 status = memcached_decrement_by_key(
433 server_key->data(), server_key->size(), key->data(), key->size(),
434 offset, &value);
436 } else {
437 if (isInc) {
438 status = memcached_increment(
439 mc, key->data(), key->size(), offset, &value);
440 } else {
441 status = memcached_decrement(
442 mc, key->data(), key->size(), offset, &value);
447 if (!handleError(status)) return false;
448 return (int64_t)value;
451 bool isBinaryProtocol() {
452 return memcached_behavior_get(&m_impl->memcached,
453 MEMCACHED_BEHAVIOR_BINARY_PROTOCOL);
456 typedef std::map<std::string, ImplPtr> ImplMap;
457 static DECLARE_THREAD_LOCAL(ImplMap, s_persistentMap);
460 void HHVM_METHOD(Memcached, __construct,
461 const Variant& persistent_id /*= null*/) {
462 auto data = Native::data<MemcachedData>(this_);
463 if (persistent_id.isNull()) {
464 data->m_impl.reset(new MemcachedData::Impl);
465 data->m_impl->is_persistent = false;
466 data->m_impl->is_pristine = true;
467 } else {
468 bool is_pristine = false;
469 MemcachedData::ImplPtr &impl = (*data->s_persistentMap)[
470 persistent_id.toString().toCppString()
472 if (!impl) {
473 impl.reset(new MemcachedData::Impl);
474 is_pristine = true;
476 data->m_impl = impl;
477 data->m_impl->is_persistent = true;
478 data->m_impl->is_pristine = is_pristine;
482 bool HHVM_METHOD(Memcached, quit) {
483 auto data = Native::data<MemcachedData>(this_);
484 memcached_quit(&data->m_impl->memcached);
485 return true;
488 Variant HHVM_METHOD(Memcached, getallkeys) {
489 auto data = Native::data<MemcachedData>(this_);
490 memcached_dump_fn callbacks[] = {
491 &memcached_dump_callback,
494 Array allKeys;
495 memcached_return status = memcached_dump(&data->m_impl->memcached, callbacks,
496 &allKeys,
497 sizeof(callbacks) /
498 sizeof(memcached_dump_fn));
499 if (!data->handleError(status)) {
500 return false;
503 return allKeys;
506 Variant HHVM_METHOD(Memcached, getbykey, const String& server_key,
507 const String& key,
508 const Variant& cache_cb /*= null*/,
509 VRefParam cas_token /*= null*/) {
510 auto data = Native::data<MemcachedData>(this_);
511 data->m_impl->rescode = MEMCACHED_SUCCESS;
512 if (key.empty()) {
513 data->m_impl->rescode = MEMCACHED_BAD_KEY_PROVIDED;
514 return false;
517 memcached_behavior_set(&data->m_impl->memcached,
518 MEMCACHED_BEHAVIOR_SUPPORT_CAS,
519 cas_token.isReferenced() ? 1 : 0);
520 const char *myServerKey = server_key.empty() ? nullptr : server_key.c_str();
521 size_t myServerKeyLen = server_key.length();
522 const char *myKey = key.c_str();
523 size_t myKeyLen = key.length();
524 memcached_return status = memcached_mget_by_key(&data->m_impl->memcached,
525 myServerKey, myServerKeyLen, &myKey, &myKeyLen, 1);
526 if (!data->handleError(status)) return false;
528 Variant returnValue;
529 MemcachedResultWrapper result(&data->m_impl->memcached);
530 if (!memcached_fetch_result(&data->m_impl->memcached,
531 &result.value, &status)) {
532 if (status == MEMCACHED_END) status = MEMCACHED_NOTFOUND;
533 if (status == MEMCACHED_NOTFOUND && !cache_cb.isNull()) {
534 status = data->doCacheCallback(cache_cb, this_, key, returnValue);
535 if (!data->handleError(status)) return false;
536 cas_token.assignIfRef(0.0);
537 return returnValue;
539 data->handleError(status);
540 return false;
543 if (!data->toObject(returnValue, result.value)) {
544 data->m_impl->rescode = q_Memcached$$RES_PAYLOAD_FAILURE;
545 return false;
547 cas_token.assignIfRef((double) memcached_result_cas(&result.value));
548 return returnValue;
551 Variant HHVM_METHOD(Memcached, getmultibykey, const String& server_key,
552 const Array& keys,
553 VRefParam cas_tokens /*= uninit_variant*/,
554 int flags /*= 0*/) {
555 auto data = Native::data<MemcachedData>(this_);
556 data->m_impl->rescode = MEMCACHED_SUCCESS;
558 bool preserveOrder = flags & q_Memcached$$GET_PRESERVE_ORDER;
559 Array returnValue = Array::Create();
560 if (!data->getMultiImpl(server_key, keys, cas_tokens.isReferenced(),
561 preserveOrder ? &returnValue : nullptr)) {
562 return false;
565 Array cas_tokens_arr;
566 SCOPE_EXIT { cas_tokens.assignIfRef(cas_tokens_arr); };
568 MemcachedResultWrapper result(&data->m_impl->memcached);
569 memcached_return status;
570 while (memcached_fetch_result(&data->m_impl->memcached, &result.value,
571 &status)) {
572 if (status != MEMCACHED_SUCCESS) {
573 status = MEMCACHED_SOME_ERRORS;
574 data->handleError(status);
575 continue;
577 Variant value;
578 if (!data->toObject(value, result.value)) {
579 data->m_impl->rescode = q_Memcached$$RES_PAYLOAD_FAILURE;
580 return false;
582 const char *key = memcached_result_key_value(&result.value);
583 size_t keyLength = memcached_result_key_length(&result.value);
584 String sKey(key, keyLength, CopyString);
585 returnValue.set(sKey, value, true);
586 if (cas_tokens.isReferenced()) {
587 double cas = (double) memcached_result_cas(&result.value);
588 cas_tokens_arr.set(sKey, cas, true);
591 return returnValue;
594 bool HHVM_METHOD(Memcached, getdelayedbykey, const String& server_key,
595 const Array& keys, bool with_cas /*= false*/,
596 const Variant& value_cb /*= uninit_variant*/) {
597 auto data = Native::data<MemcachedData>(this_);
598 data->m_impl->rescode = MEMCACHED_SUCCESS;
600 if (!data->getMultiImpl(server_key, keys, with_cas, nullptr)) return false;
601 if (value_cb.isNull()) return true;
603 MemcachedResultWrapper result(&data->m_impl->memcached); Array item;
604 while (data->fetchImpl(result.value, item)) {
605 vm_call_user_func(value_cb, make_packed_array(Variant(this_), item));
608 if (data->m_impl->rescode != MEMCACHED_END) return false;
609 data->m_impl->rescode = MEMCACHED_SUCCESS;
610 return true;
613 Variant HHVM_METHOD(Memcached, fetch) {
614 auto data = Native::data<MemcachedData>(this_);
615 data->m_impl->rescode = MEMCACHED_SUCCESS;
617 MemcachedResultWrapper result(&data->m_impl->memcached); Array item;
618 if (!data->fetchImpl(result.value, item)) return false;
620 return item;
623 Variant HHVM_METHOD(Memcached, fetchall) {
624 auto data = Native::data<MemcachedData>(this_);
625 data->m_impl->rescode = MEMCACHED_SUCCESS;
627 Array returnValue;
628 MemcachedResultWrapper result(&data->m_impl->memcached); Array item;
629 while (data->fetchImpl(result.value, item)) {
630 returnValue.append(item);
633 if (data->m_impl->rescode != MEMCACHED_END) return false;
634 return returnValue;
637 bool HHVM_METHOD(Memcached, setbykey, const String& server_key,
638 const String& key, const Variant& value,
639 int expiration /*= 0*/) {
640 auto data = Native::data<MemcachedData>(this_);
641 return data->setOperationImpl(memcached_set_by_key, server_key, key, value,
642 expiration);
645 bool HHVM_METHOD(Memcached, addbykey, const String& server_key,
646 const String& key, const Variant& value,
647 int expiration /*= 0*/) {
648 auto data = Native::data<MemcachedData>(this_);
649 return data->setOperationImpl(memcached_add_by_key, server_key, key, value,
650 expiration);
653 bool HHVM_METHOD(Memcached, appendbykey, const String& server_key,
654 const String& key,
655 const String& value) {
656 auto data = Native::data<MemcachedData>(this_);
657 if (data->m_impl->compression) {
658 raise_warning("cannot append/prepend with compression turned on");
659 return false;
661 return data->setOperationImpl(memcached_append_by_key, server_key, key,
662 value, 0);
665 bool HHVM_METHOD(Memcached, prependbykey, const String& server_key,
666 const String& key,
667 const String& value) {
668 auto data = Native::data<MemcachedData>(this_);
669 if (data->m_impl->compression) {
670 raise_warning("cannot append/prepend with compression turned on");
671 return false;
673 return data->setOperationImpl(memcached_prepend_by_key, server_key, key,
674 value, 0);
677 bool HHVM_METHOD(Memcached, replacebykey, const String& server_key,
678 const String& key,
679 const Variant& value,
680 int expiration /*= 0*/) {
681 auto data = Native::data<MemcachedData>(this_);
682 return data->setOperationImpl(memcached_replace_by_key, server_key, key,
683 value, expiration);
686 bool HHVM_METHOD(Memcached, casbykey, double cas_token,
687 const String& server_key,
688 const String& key,
689 const Variant& value,
690 int expiration /*= 0*/) {
691 auto data = Native::data<MemcachedData>(this_);
692 data->m_impl->rescode = MEMCACHED_SUCCESS;
693 if (key.empty()) {
694 data->m_impl->rescode = MEMCACHED_BAD_KEY_PROVIDED;
695 return false;
698 std::vector<char> payload; uint32_t flags;
699 data->toPayload(value, payload, flags);
701 const String& myServerKey = server_key.empty() ? key : server_key;
702 return data->handleError(memcached_cas_by_key(&data->m_impl->memcached,
703 myServerKey.c_str(), myServerKey.length(), key.c_str(), key.length(),
704 payload.data(), payload.size(), expiration, flags, (uint64_t)cas_token));
707 bool HHVM_METHOD(Memcached, deletebykey, const String& server_key,
708 const String& key,
709 int time /*= 0*/) {
710 auto data = Native::data<MemcachedData>(this_);
711 data->m_impl->rescode = MEMCACHED_SUCCESS;
712 if (key.empty()) {
713 data->m_impl->rescode = MEMCACHED_BAD_KEY_PROVIDED;
714 return false;
717 const String& myServerKey = server_key.empty() ? key : server_key;
718 return data->handleError(memcached_delete_by_key(&data->m_impl->memcached,
719 myServerKey.c_str(), myServerKey.length(),
720 key.c_str(), key.length(), time));
723 Variant HHVM_METHOD(Memcached, deletemultibykey, const String& server_key,
724 const Array& keys,
725 int64_t time /*= 0*/) {
726 auto data = Native::data<MemcachedData>(this_);
727 data->m_impl->rescode = MEMCACHED_SUCCESS;
729 memcached_return status_memcached;
730 bool status;
731 Array returnValue = Array::Create();
732 for (ArrayIter iter(keys); iter; ++iter) {
733 Variant vKey = iter.second();
734 if (!vKey.isString()) continue;
735 const String& key = vKey.toString();
736 if (key.empty()) continue;
737 const String& myServerKey = server_key.empty() ? key : server_key;
738 status_memcached = memcached_delete_by_key(&data->m_impl->memcached,
739 myServerKey.c_str(), myServerKey.length(),
740 key.c_str(), key.length(), time);
742 status = data->handleError(status_memcached);
743 if (!status) {
744 returnValue.set(key, status_memcached, true);
745 } else {
746 returnValue.set(key, status, true);
749 return returnValue;
752 Variant HHVM_METHOD(Memcached, increment,
753 const String& key,
754 int64_t offset /* = 1 */,
755 const Variant& initial_value /* = false */,
756 int64_t expiry /* = 0 */) {
757 return Native::data<MemcachedData>(this_)->incDecOp(
758 true, nullptr, key.get(), offset, initial_value, expiry);
761 Variant HHVM_METHOD(Memcached, incrementbykey,
762 const String& server_key,
763 const String& key,
764 int64_t offset /* = 1 */,
765 const Variant& initial_value /* = false */,
766 int64_t expiry /* = 0 */) {
767 return Native::data<MemcachedData>(this_)->incDecOp(
768 true, server_key.get(), key.get(), offset, initial_value, expiry);
771 Variant HHVM_METHOD(Memcached, decrement,
772 const String& key,
773 int64_t offset /* = 1 */,
774 const Variant& initial_value /* = false */,
775 int64_t expiry /* = 0 */) {
776 return Native::data<MemcachedData>(this_)->incDecOp(
777 false, nullptr, key.get(), offset, initial_value, expiry);
780 Variant HHVM_METHOD(Memcached, decrementbykey,
781 const String& server_key,
782 const String& key,
783 int64_t offset /* = 1 */,
784 const Variant& initial_value /* = false */,
785 int64_t expiry /* = 0 */) {
786 return Native::data<MemcachedData>(this_)->incDecOp(
787 false, server_key.get(), key.get(), offset, initial_value, expiry);
790 bool HHVM_METHOD(Memcached, addserver, const String& host, int port,
791 int weight /*= 0*/) {
792 auto data = Native::data<MemcachedData>(this_);
793 data->m_impl->rescode = MEMCACHED_SUCCESS;
794 if (!host.empty() && host[0] == '/') {
795 return data->handleError(memcached_server_add_unix_socket_with_weight(
796 &data->m_impl->memcached, host.c_str(), weight));
797 } else {
798 return data->handleError(memcached_server_add_with_weight(
799 &data->m_impl->memcached, host.c_str(), port, weight
804 namespace {
806 const StaticString s_host("host"), s_port("port");
807 #ifdef LMCD_SERVER_QUERY_INCLUDES_WEIGHT
808 const StaticString s_weight("weight");
809 #endif
811 memcached_return_t doServerListCallback(const memcached_st *ptr,
812 LMCD_SERVER_CALLBACK_INSTANCE_TYPE server, void *context) {
813 Array *returnValue = (Array*) context;
814 const char* hostname = LMCD_SERVER_HOSTNAME(server);
815 in_port_t port = LMCD_SERVER_PORT(server);
816 #ifdef LMCD_SERVER_QUERY_INCLUDES_WEIGHT
817 returnValue->append(make_map_array(s_host, String(hostname, CopyString),
818 s_port, (int32_t)port,
819 s_weight, (int32_t)server->weight));
820 #else
821 returnValue->append(make_map_array(s_host, String(hostname, CopyString),
822 s_port, (int32_t)port));
823 #endif
824 return MEMCACHED_SUCCESS;
828 Array HHVM_METHOD(Memcached, getserverlist) {
829 auto data = Native::data<MemcachedData>(this_);
830 Array returnValue = Array::Create();
831 memcached_server_function callbacks[] = { doServerListCallback };
832 memcached_server_cursor(&data->m_impl->memcached, callbacks, &returnValue, 1);
833 return returnValue;
836 bool HHVM_METHOD(Memcached, resetserverlist) {
837 auto data = Native::data<MemcachedData>(this_);
838 memcached_servers_reset(&data->m_impl->memcached);
839 return true;
842 Variant HHVM_METHOD(Memcached, getserverbykey, const String& server_key) {
843 auto data = Native::data<MemcachedData>(this_);
844 data->m_impl->rescode = MEMCACHED_SUCCESS;
845 if (server_key.empty()) {
846 data->m_impl->rescode = MEMCACHED_BAD_KEY_PROVIDED;
847 return false;
850 memcached_return_t error;
851 LMCD_SERVER_BY_KEY_INSTANCE_TYPE server = memcached_server_by_key(
852 &data->m_impl->memcached, server_key.c_str(), server_key.size(), &error);
853 if (!server) {
854 data->handleError(error);
855 return false;
858 const char* hostname = LMCD_SERVER_HOSTNAME(server);
859 in_port_t port = LMCD_SERVER_PORT(server);
860 #ifdef LMCD_SERVER_QUERY_INCLUDES_WEIGHT
861 Array returnValue = make_map_array(s_host, String(hostname, CopyString),
862 s_port, (int32_t)port,
863 s_weight, (int32_t)server->weight);
864 #else
865 Array returnValue = make_map_array(s_host, String(hostname, CopyString),
866 s_port, (int32_t)port);
867 #endif
868 return returnValue;
871 namespace {
872 struct StatsContext {
873 memcached_stat_st *stats;
874 Array returnValue;
877 const StaticString
878 s_pid("pid"),
879 s_uptime("uptime"),
880 s_threads("threads"),
881 s_time("time"),
882 s_pointer_size("pointer_size"),
883 s_rusage_user_seconds("rusage_user_seconds"),
884 s_rusage_user_microseconds("rusage_user_microseconds"),
885 s_rusage_system_seconds("rusage_system_seconds"),
886 s_rusage_system_microseconds("rusage_system_microseconds"),
887 s_curr_items("curr_items"),
888 s_total_items("total_items"),
889 s_limit_maxbytes("limit_maxbytes"),
890 s_curr_connections("curr_connections"),
891 s_total_connections("total_connections"),
892 s_connection_structures("connection_structures"),
893 s_bytes("bytes"),
894 s_cmd_get("cmd_get"),
895 s_cmd_set("cmd_set"),
896 s_get_hits("get_hits"),
897 s_get_misses("get_misses"),
898 s_evictions("evictions"),
899 s_bytes_read("bytes_read"),
900 s_bytes_written("bytes_written"),
901 s_version("version");
903 memcached_return_t doStatsCallback(const memcached_st *ptr,
904 LMCD_SERVER_CALLBACK_INSTANCE_TYPE server, void *inContext) {
905 StatsContext *context = (StatsContext*) inContext;
906 char key[NI_MAXHOST + 6];
907 const char* hostname = LMCD_SERVER_HOSTNAME(server);
908 in_port_t port = LMCD_SERVER_PORT(server);
909 snprintf(key, sizeof(key), "%s:%d", hostname, port);
910 memcached_stat_st *stats = context->stats;
911 ssize_t i = context->returnValue.size();
913 context->returnValue.set(String(key, CopyString),
914 make_map_array(
915 s_pid, (int64_t)stats[i].pid,
916 s_uptime, (int64_t)stats[i].uptime,
917 s_threads, (int64_t)stats[i].threads,
918 s_time, (int64_t)stats[i].time,
919 s_pointer_size, (int64_t)stats[i].pointer_size,
920 s_rusage_user_seconds, (int64_t)stats[i].rusage_user_seconds,
921 s_rusage_user_microseconds, (int64_t)stats[i]
922 .rusage_user_microseconds,
923 s_rusage_system_seconds, (int64_t)stats[i].rusage_system_seconds,
924 s_rusage_system_microseconds, (int64_t)stats[i]
925 .rusage_system_microseconds,
926 s_curr_items, (int64_t)stats[i].curr_items,
927 s_total_items, (int64_t)stats[i].total_items,
928 s_limit_maxbytes, (int64_t)stats[i].limit_maxbytes,
929 s_curr_connections, (int64_t)stats[i].curr_connections,
930 s_total_connections, (int64_t)stats[i].total_connections,
931 s_connection_structures, (int64_t)stats[i].connection_structures,
932 s_bytes, (int64_t)stats[i].bytes,
933 s_cmd_get, (int64_t)stats[i].cmd_get,
934 s_cmd_set, (int64_t)stats[i].cmd_set,
935 s_get_hits, (int64_t)stats[i].get_hits,
936 s_get_misses, (int64_t)stats[i].get_misses,
937 s_evictions, (int64_t)stats[i].evictions,
938 s_bytes_read, (int64_t)stats[i].bytes_read,
939 s_bytes_written, (int64_t)stats[i].bytes_written,
940 s_version, String(stats[i].version, CopyString)
944 return MEMCACHED_SUCCESS;
948 Variant HHVM_METHOD(Memcached, getstats) {
949 auto data = Native::data<MemcachedData>(this_);
950 memcached_return_t error;
951 memcached_stat_st *stats = memcached_stat(&data->m_impl->memcached,
952 nullptr, &error);
953 if (!stats) {
954 data->handleError(error);
955 return false;
958 memcached_server_function callbacks[] = { doStatsCallback };
959 StatsContext context; context.stats = stats;
960 memcached_server_cursor(&data->m_impl->memcached, callbacks, &context, 1);
962 memcached_stat_free(&data->m_impl->memcached, stats);
963 return context.returnValue;
966 namespace {
967 memcached_return_t doVersionCallback(const memcached_st *ptr,
968 LMCD_SERVER_CALLBACK_INSTANCE_TYPE server, void *context) {
969 Array *returnValue = (Array*) context;
970 char key[NI_MAXHOST + 6], version[16];
972 const char* hostname = LMCD_SERVER_HOSTNAME(server);
973 in_port_t port = LMCD_SERVER_PORT(server);
974 uint8_t majorVersion = LMCD_SERVER_MAJOR_VERSION(server);
975 uint8_t minorVersion = LMCD_SERVER_MINOR_VERSION(server);
976 uint8_t microVersion = LMCD_SERVER_MICRO_VERSION(server);
978 // libmemcached starting with 0.46 use UINT8_MAX as the default version, not 0
979 #if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX <= 0x00045000
980 if (majorVersion == 0 && minorVersion == 0 && microVersion == 0) {
981 majorVersion = UINT8_MAX;
982 minorVersion = UINT8_MAX;
983 microVersion = UINT8_MAX;
985 #endif
987 snprintf(key, sizeof(key), "%s:%d", hostname, port);
988 snprintf(version, sizeof(version), "%" PRIu8 ".%" PRIu8 ".%" PRIu8,
989 majorVersion, minorVersion, microVersion);
990 returnValue->set(String(key, CopyString), String(version, CopyString));
991 return MEMCACHED_SUCCESS;
995 Variant HHVM_METHOD(Memcached, getversion) {
996 auto data = Native::data<MemcachedData>(this_);
997 memcached_version(&data->m_impl->memcached);
999 Array returnValue = Array::Create();
1000 memcached_server_function callbacks[] = { doVersionCallback };
1001 memcached_server_cursor(&data->m_impl->memcached, callbacks, &returnValue, 1);
1002 return returnValue;
1005 bool HHVM_METHOD(Memcached, flush, int delay /*= 0*/) {
1006 auto data = Native::data<MemcachedData>(this_);
1007 return data->handleError(memcached_flush(&data->m_impl->memcached, delay));
1010 Variant HHVM_METHOD(Memcached, getoption, int option) {
1011 auto data = Native::data<MemcachedData>(this_);
1012 switch (option) {
1013 case q_Memcached$$OPT_COMPRESSION:
1014 return data->m_impl->compression;
1016 case q_Memcached$$OPT_PREFIX_KEY:
1018 memcached_return retval;
1019 char *result = (char*) memcached_callback_get(&data->m_impl->memcached,
1020 MEMCACHED_CALLBACK_PREFIX_KEY, &retval);
1021 if (retval == MEMCACHED_SUCCESS && result) {
1022 return String(result, CopyString);
1024 else return empty_string_variant();
1027 case q_Memcached$$OPT_SERIALIZER:
1028 return data->m_impl->serializer;
1030 case MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE:
1031 case MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE:
1032 if (memcached_server_count(&data->m_impl->memcached) == 0) {
1033 raise_warning("no servers defined");
1034 return init_null();
1036 // fall through
1038 default:
1039 // Assume that it's a libmemcached behavior option
1040 return (int64_t) memcached_behavior_get(&data->m_impl->memcached,
1041 (memcached_behavior_t)option);
1045 bool HHVM_METHOD(Memcached, setoption, int option, const Variant& value) {
1046 auto data = Native::data<MemcachedData>(this_);
1047 switch (option) {
1048 case q_Memcached$$OPT_COMPRESSION:
1049 data->m_impl->compression = value.toBoolean();
1050 break;
1052 case q_Memcached$$OPT_PREFIX_KEY:
1054 String sValue = value.toString();
1055 char *key = const_cast<char*>(sValue.empty() ? nullptr : sValue.c_str());
1056 if (memcached_callback_set(&data->m_impl->memcached,
1057 MEMCACHED_CALLBACK_PREFIX_KEY, key) == MEMCACHED_BAD_KEY_PROVIDED) {
1058 raise_warning("bad key provided");
1059 return false;
1061 break;
1064 case MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED:
1066 uint64_t lValue = value.toInt64();
1067 if (memcached_behavior_set(&data->m_impl->memcached,
1068 MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED, lValue) == MEMCACHED_FAILURE) {
1069 raise_warning("error setting memcached option");
1070 return false;
1073 /* This is necessary because libmemcached doesn't reset hash/distribution
1074 * options on false case, like it does for MEMCACHED_BEHAVIOR_KETAMA
1075 * (non-weighted) case. We have to clean up ourselves.
1077 if (!lValue) {
1078 memcached_behavior_set_key_hash(&data->m_impl->memcached,
1079 MEMCACHED_HASH_DEFAULT);
1080 memcached_behavior_set_distribution_hash(&data->m_impl->memcached,
1081 MEMCACHED_HASH_DEFAULT);
1082 memcached_behavior_set_distribution(&data->m_impl->memcached,
1083 MEMCACHED_DISTRIBUTION_MODULA);
1085 break;
1088 case q_Memcached$$OPT_SERIALIZER:
1090 int iValue = value.toInt32(10);
1091 switch (iValue) {
1092 case q_Memcached$$SERIALIZER_PHP:
1093 case q_Memcached$$SERIALIZER_JSON:
1094 data->m_impl->serializer = iValue;
1095 break;
1096 default:
1097 data->m_impl->serializer = q_Memcached$$SERIALIZER_PHP;
1098 raise_warning("invalid serializer provided");
1099 return false;
1101 break;
1104 default:
1106 if ((option < 0) || (option >= MEMCACHED_BEHAVIOR_MAX)) {
1107 raise_warning("error setting memcached option");
1108 return false;
1111 // Assume that it's a libmemcached behavior option
1112 uint64_t lValue = value.toInt64();
1113 if (memcached_behavior_set(&data->m_impl->memcached,
1114 (memcached_behavior_t)option, lValue) == MEMCACHED_FAILURE) {
1115 raise_warning("error setting memcached option");
1116 return false;
1118 break;
1121 return true;
1124 int64_t HHVM_METHOD(Memcached, getresultcode) {
1125 auto data = Native::data<MemcachedData>(this_);
1126 return data->m_impl->rescode;
1129 String HHVM_METHOD(Memcached, getresultmessage) {
1130 auto data = Native::data<MemcachedData>(this_);
1131 if (data->m_impl->rescode == q_Memcached$$RES_PAYLOAD_FAILURE) {
1132 return "PAYLOAD FAILURE";
1133 } else {
1134 return memcached_strerror(&data->m_impl->memcached,
1135 (memcached_return_t)data->m_impl->rescode);
1139 bool HHVM_METHOD(Memcached, ispersistent) {
1140 auto data = Native::data<MemcachedData>(this_);
1141 return data->m_impl->is_persistent;
1144 bool HHVM_METHOD(Memcached, ispristine) {
1145 auto data = Native::data<MemcachedData>(this_);
1146 return data->m_impl->is_pristine;
1149 bool HHVM_METHOD(Memcached, touchbykey,
1150 ATTRIBUTE_UNUSED const String& server_key,
1151 ATTRIBUTE_UNUSED const String& key,
1152 ATTRIBUTE_UNUSED int expiration /*= 0*/) {
1154 #ifndef HAVE_MEMCACHED_TOUCH
1155 throw_not_supported(__func__, "Not Implemented in libmemcached versions below"
1156 " 1.0.2");
1157 return false;
1158 #else
1159 auto data = Native::data<MemcachedData>(this_);
1160 data->m_impl->rescode = MEMCACHED_SUCCESS;
1161 if (key.empty()) {
1162 data->m_impl->rescode = MEMCACHED_BAD_KEY_PROVIDED;
1163 return false;
1166 #if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX < 0x01000016
1167 if (memcached_behavior_get(&data->m_impl->memcached,
1168 MEMCACHED_BEHAVIOR_BINARY_PROTOCOL)) {
1169 raise_warning("using touch command with binary protocol is not "
1170 "recommended with libmemcached versions below 1.0.16");
1172 #endif
1174 memcached_return_t status;
1175 const String& myServerKey = server_key.empty() ? key : server_key;
1176 status = memcached_touch_by_key(&data->m_impl->memcached,
1177 myServerKey.c_str(), myServerKey.length(),
1178 key.c_str(), key.length(), expiration);
1180 if (!data->handleError(status)) return false;
1181 data->m_impl->rescode = MEMCACHED_SUCCESS;
1182 return true;
1183 #endif
1186 ///////////////////////////////////////////////////////////////////////////////
1188 IMPLEMENT_THREAD_LOCAL(MemcachedData::ImplMap, MemcachedData::s_persistentMap);
1190 const StaticString s_Memcached("Memcached");
1192 struct MemcachedExtension final : Extension {
1193 MemcachedExtension() : Extension("memcached", "2.2.0b1") {}
1194 void threadInit() override {
1195 if (s_memcached_globals) {
1196 return;
1198 s_memcached_globals = new MEMCACHEDGlobals;
1199 IniSetting::Bind(this, IniSetting::PHP_INI_ALL,
1200 "memcached.sess_prefix", &MEMCACHEDG(sess_prefix));
1203 void threadShutdown() override {
1204 delete s_memcached_globals;
1205 s_memcached_globals = nullptr;
1208 void moduleInit() override {
1209 HHVM_ME(Memcached, __construct);
1210 HHVM_ME(Memcached, quit);
1211 HHVM_ME(Memcached, getallkeys);
1212 HHVM_ME(Memcached, getbykey);
1213 HHVM_ME(Memcached, getmultibykey);
1214 HHVM_ME(Memcached, getdelayedbykey);
1215 HHVM_ME(Memcached, fetch);
1216 HHVM_ME(Memcached, fetchall);
1217 HHVM_ME(Memcached, setbykey);
1218 HHVM_ME(Memcached, addbykey);
1219 HHVM_ME(Memcached, appendbykey);
1220 HHVM_ME(Memcached, prependbykey);
1221 HHVM_ME(Memcached, replacebykey);
1222 HHVM_ME(Memcached, casbykey);
1223 HHVM_ME(Memcached, deletebykey);
1224 HHVM_ME(Memcached, deletemultibykey);
1225 HHVM_ME(Memcached, increment);
1226 HHVM_ME(Memcached, incrementbykey);
1227 HHVM_ME(Memcached, decrement);
1228 HHVM_ME(Memcached, decrementbykey);
1229 HHVM_ME(Memcached, addserver);
1230 HHVM_ME(Memcached, getserverlist);
1231 HHVM_ME(Memcached, resetserverlist);
1232 HHVM_ME(Memcached, getserverbykey);
1233 HHVM_ME(Memcached, getstats);
1234 HHVM_ME(Memcached, getversion);
1235 HHVM_ME(Memcached, flush);
1236 HHVM_ME(Memcached, getoption);
1237 HHVM_ME(Memcached, setoption);
1238 HHVM_ME(Memcached, getresultcode);
1239 HHVM_ME(Memcached, getresultmessage);
1240 HHVM_ME(Memcached, ispersistent);
1241 HHVM_ME(Memcached, ispristine);
1242 HHVM_ME(Memcached, touchbykey);
1244 Native::registerNativeDataInfo<MemcachedData>(s_MemcachedData.get());
1246 HHVM_RCC_BOOL(Memcached, HAVE_IGBINARY, false);
1247 HHVM_RCC_BOOL(Memcached, HAVE_JSON, true);
1249 HHVM_RCC_INT(Memcached, DISTRIBUTION_CONSISTENT,
1250 MEMCACHED_DISTRIBUTION_CONSISTENT);
1251 HHVM_RCC_INT(Memcached, DISTRIBUTION_CONSISTENT_KETAMA,
1252 MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA);
1253 #ifdef MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED
1254 HHVM_RCC_INT(Memcached, DISTRIBUTION_CONSISTENT_WEIGHTED,
1255 MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED);
1256 #endif
1257 HHVM_RCC_INT(Memcached, DISTRIBUTION_MODULA, MEMCACHED_DISTRIBUTION_MODULA);
1258 HHVM_RCC_INT(Memcached, GET_PRESERVE_ORDER,
1259 q_Memcached$$GET_PRESERVE_ORDER);
1260 HHVM_RCC_INT(Memcached, HASH_CRC, MEMCACHED_HASH_CRC);
1261 HHVM_RCC_INT(Memcached, HASH_DEFAULT, MEMCACHED_HASH_DEFAULT);
1262 HHVM_RCC_INT(Memcached, HASH_FNV1_32, MEMCACHED_HASH_FNV1_32);
1263 HHVM_RCC_INT(Memcached, HASH_FNV1_64, MEMCACHED_HASH_FNV1_64);
1264 HHVM_RCC_INT(Memcached, HASH_FNV1A_32, MEMCACHED_HASH_FNV1A_32);
1265 HHVM_RCC_INT(Memcached, HASH_FNV1A_64, MEMCACHED_HASH_FNV1A_64);
1266 HHVM_RCC_INT(Memcached, HASH_HSIEH, MEMCACHED_HASH_HSIEH);
1267 HHVM_RCC_INT(Memcached, HASH_MD5, MEMCACHED_HASH_MD5);
1268 HHVM_RCC_INT(Memcached, HASH_MURMUR, MEMCACHED_HASH_MURMUR);
1269 HHVM_RCC_INT(Memcached, OPT_BINARY_PROTOCOL,
1270 MEMCACHED_BEHAVIOR_BINARY_PROTOCOL);
1271 HHVM_RCC_INT(Memcached, OPT_BUFFER_WRITES,
1272 MEMCACHED_BEHAVIOR_BUFFER_REQUESTS);
1273 HHVM_RCC_INT(Memcached, OPT_CACHE_LOOKUPS,
1274 MEMCACHED_BEHAVIOR_CACHE_LOOKUPS);
1275 HHVM_RCC_INT(Memcached, OPT_COMPRESSION, q_Memcached$$OPT_COMPRESSION);
1276 HHVM_RCC_INT(Memcached, OPT_CONNECT_TIMEOUT,
1277 MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT);
1278 HHVM_RCC_INT(Memcached, OPT_DISTRIBUTION, MEMCACHED_BEHAVIOR_DISTRIBUTION);
1279 HHVM_RCC_INT(Memcached, OPT_HASH, MEMCACHED_BEHAVIOR_HASH);
1280 HHVM_RCC_INT(Memcached, OPT_LIBKETAMA_COMPATIBLE,
1281 MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED);
1282 HHVM_RCC_INT(Memcached, OPT_LIBKETAMA_HASH, MEMCACHED_BEHAVIOR_KETAMA_HASH);
1283 HHVM_RCC_INT(Memcached, OPT_NO_BLOCK, MEMCACHED_BEHAVIOR_NO_BLOCK);
1284 HHVM_RCC_INT(Memcached, OPT_POLL_TIMEOUT, MEMCACHED_BEHAVIOR_POLL_TIMEOUT);
1285 HHVM_RCC_INT(Memcached, OPT_PREFIX_KEY, q_Memcached$$OPT_PREFIX_KEY);
1286 HHVM_RCC_INT(Memcached, OPT_HASH_WITH_PREFIX_KEY,
1287 MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY);
1288 HHVM_RCC_INT(Memcached, OPT_RECV_TIMEOUT, MEMCACHED_BEHAVIOR_RCV_TIMEOUT);
1289 HHVM_RCC_INT(Memcached, OPT_RETRY_TIMEOUT,
1290 MEMCACHED_BEHAVIOR_RETRY_TIMEOUT);
1291 HHVM_RCC_INT(Memcached, OPT_SEND_TIMEOUT, MEMCACHED_BEHAVIOR_SND_TIMEOUT);
1292 HHVM_RCC_INT(Memcached, OPT_SERIALIZER, q_Memcached$$OPT_SERIALIZER);
1293 HHVM_RCC_INT(Memcached, OPT_SERVER_FAILURE_LIMIT,
1294 MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT);
1295 HHVM_RCC_INT(Memcached, OPT_SOCKET_RECV_SIZE,
1296 MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE);
1297 HHVM_RCC_INT(Memcached, OPT_SOCKET_SEND_SIZE,
1298 MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE);
1299 HHVM_RCC_INT(Memcached, OPT_TCP_NODELAY, MEMCACHED_BEHAVIOR_TCP_NODELAY);
1300 HHVM_RCC_INT(Memcached, RES_BAD_KEY_PROVIDED, MEMCACHED_BAD_KEY_PROVIDED);
1301 HHVM_RCC_INT(Memcached, RES_BUFFERED, MEMCACHED_BUFFERED);
1302 HHVM_RCC_INT(Memcached, RES_CLIENT_ERROR, MEMCACHED_CLIENT_ERROR);
1303 HHVM_RCC_INT(Memcached, RES_CONNECTION_SOCKET_CREATE_FAILURE,
1304 MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE);
1305 HHVM_RCC_INT(Memcached, RES_DATA_EXISTS, MEMCACHED_DATA_EXISTS);
1306 HHVM_RCC_INT(Memcached, RES_END, MEMCACHED_END);
1307 HHVM_RCC_INT(Memcached, RES_ERRNO, MEMCACHED_ERRNO);
1308 HHVM_RCC_INT(Memcached, RES_FAILURE, MEMCACHED_FAILURE);
1309 HHVM_RCC_INT(Memcached, RES_HOST_LOOKUP_FAILURE,
1310 MEMCACHED_HOST_LOOKUP_FAILURE);
1311 HHVM_RCC_INT(Memcached, RES_INVALID_HOST_PROTOCOL,
1312 MEMCACHED_INVALID_HOST_PROTOCOL);
1313 HHVM_RCC_INT(Memcached, RES_NO_SERVERS, MEMCACHED_NO_SERVERS);
1314 HHVM_RCC_INT(Memcached, RES_NOT_SUPPORTED, MEMCACHED_NOT_SUPPORTED);
1315 HHVM_RCC_INT(Memcached, RES_NOTFOUND, MEMCACHED_NOTFOUND);
1316 HHVM_RCC_INT(Memcached, RES_NOTSTORED, MEMCACHED_NOTSTORED);
1317 HHVM_RCC_INT(Memcached, RES_PARTIAL_READ, MEMCACHED_PARTIAL_READ);
1318 HHVM_RCC_INT(Memcached, RES_PAYLOAD_FAILURE,
1319 q_Memcached$$RES_PAYLOAD_FAILURE);
1320 HHVM_RCC_INT(Memcached, RES_PROTOCOL_ERROR, MEMCACHED_PROTOCOL_ERROR);
1321 HHVM_RCC_INT(Memcached, RES_SERVER_ERROR, MEMCACHED_SERVER_ERROR);
1322 HHVM_RCC_INT(Memcached, RES_SOME_ERRORS, MEMCACHED_SOME_ERRORS);
1323 HHVM_RCC_INT(Memcached, RES_SUCCESS, MEMCACHED_SUCCESS);
1324 HHVM_RCC_INT(Memcached, RES_TIMEOUT, MEMCACHED_TIMEOUT);
1325 HHVM_RCC_INT(Memcached, RES_UNKNOWN_READ_FAILURE,
1326 MEMCACHED_UNKNOWN_READ_FAILURE);
1327 HHVM_RCC_INT(Memcached, RES_WRITE_FAILURE, MEMCACHED_WRITE_FAILURE);
1328 HHVM_RCC_INT(Memcached, SERIALIZER_IGBINARY,
1329 q_Memcached$$SERIALIZER_IGBINARY);
1330 HHVM_RCC_INT(Memcached, SERIALIZER_JSON, q_Memcached$$SERIALIZER_JSON);
1331 HHVM_RCC_INT(Memcached, SERIALIZER_PHP, q_Memcached$$SERIALIZER_PHP);
1332 HHVM_RCC_INT(Memcached, OPT_VERIFY_KEY, MEMCACHED_BEHAVIOR_VERIFY_KEY);
1333 HHVM_RCC_INT(Memcached, OPT_SORT_HOSTS, MEMCACHED_BEHAVIOR_SORT_HOSTS);
1334 HHVM_RCC_INT(Memcached, RES_SERVER_MARKED_DEAD,
1335 MEMCACHED_SERVER_MARKED_DEAD);
1336 #if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX >= 0x00049000
1337 HHVM_RCC_INT(Memcached, OPT_REMOVE_FAILED_SERVERS,
1338 MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS);
1339 #endif
1340 #if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX >= 0x01000003
1341 HHVM_RCC_INT(Memcached, OPT_DEAD_TIMEOUT, MEMCACHED_BEHAVIOR_DEAD_TIMEOUT);
1342 #endif
1343 HHVM_RCC_INT(Memcached, RES_SERVER_TEMPORARILY_DISABLED,
1344 MEMCACHED_SERVER_TEMPORARILY_DISABLED);
1345 HHVM_RCC_INT(Memcached, LIBMEMCACHED_VERSION_HEX, LIBMEMCACHED_VERSION_HEX);
1346 HHVM_RCC_BOOL(Memcached, GET_ERROR_RETURN_VALUE, false);
1349 loadSystemlib();
1351 } s_memcached_extension;