memcachedplugin.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2014 HPCC Systems®.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include "platform.h"
  14. #include "memcachedplugin.hpp"
  15. #include "eclrtl.hpp"
  16. #include "jexcept.hpp"
  17. #include "jstring.hpp"
  18. #include "jthread.hpp"
  19. #include <libmemcached/memcached.hpp>
  20. #include <libmemcached/util.h>
  21. #define MEMCACHED_VERSION "memcached plugin 1.0.0"
  22. ECL_MEMCACHED_API bool getECLPluginDefinition(ECLPluginDefinitionBlock *pb)
  23. {
  24. if (pb->size != sizeof(ECLPluginDefinitionBlock))
  25. return false;
  26. pb->magicVersion = PLUGIN_VERSION;
  27. pb->version = MEMCACHED_VERSION;
  28. pb->moduleName = "lib_memcached";
  29. pb->ECL = NULL;
  30. pb->flags = PLUGIN_IMPLICIT_MODULE;
  31. pb->description = "ECL plugin library for the C/C++ API libmemcached (http://libmemcached.org/)\n";
  32. return true;
  33. }
  34. namespace MemCachedPlugin {
  35. enum eclDataType {
  36. ECL_BOOLEAN,
  37. ECL_DATA,
  38. ECL_INTEGER,
  39. ECL_REAL,
  40. ECL_STRING,
  41. ECL_UTF8,
  42. ECL_UNICODE,
  43. ECL_UNSIGNED,
  44. ECL_NONE
  45. };
  46. const char * enumToStr(eclDataType type)
  47. {
  48. switch(type)
  49. {
  50. case ECL_BOOLEAN:
  51. return "BOOLEAN";
  52. case ECL_INTEGER:
  53. return "INTEGER";
  54. case ECL_UNSIGNED:
  55. return "UNSIGNED";
  56. case ECL_REAL:
  57. return "REAL";
  58. case ECL_STRING:
  59. return "STRING";
  60. case ECL_UTF8:
  61. return "UTF8";
  62. case ECL_UNICODE:
  63. return "UNICODE";
  64. case ECL_DATA:
  65. return "DATA";
  66. case ECL_NONE:
  67. return "Nonexistent";
  68. default:
  69. return "UNKNOWN";
  70. }
  71. }
  72. class MCached : public CInterface
  73. {
  74. public :
  75. MCached(ICodeContext * ctx, const char * _options);
  76. ~MCached();
  77. //set
  78. template <class type> void set(ICodeContext * ctx, const char * partitionKey, const char * key, type value, unsigned __int64 expire, eclDataType eclType);
  79. template <class type> void set(ICodeContext * ctx, const char * partitionKey, const char * key, size32_t valueLength, const type * value, unsigned __int64 expire, eclDataType eclType);
  80. //get
  81. template <class type> void get(ICodeContext * ctx, const char * partitionKey, const char * key, type & value, eclDataType eclType);
  82. template <class type> void get(ICodeContext * ctx, const char * partitionKey, const char * key, size_t & valueLength, type * & value, eclDataType eclType);
  83. void getVoidPtrLenPair(ICodeContext * ctx, const char * partitionKey, const char * key, size_t & valueLength, void * & value, eclDataType eclType);
  84. void clear(ICodeContext * ctx, unsigned when);
  85. bool exists(ICodeContext * ctx, const char * key, const char * partitionKey);
  86. void deleteKey(ICodeContext * ctx, const char * key, const char * partitionKey);
  87. eclDataType getKeyType(const char * key, const char * partitionKey);
  88. bool isSameConnection(const char * _options) const;
  89. private :
  90. void checkServersUp(ICodeContext * ctx);
  91. void assertOnError(memcached_return_t rc, const char * _msg);
  92. const char * appendIfKeyNotFoundMsg(memcached_return_t rc, const char * key, StringBuffer & target) const;
  93. void connect(ICodeContext * ctx);
  94. bool logErrorOnFail(ICodeContext * ctx, memcached_return_t rc, const char * _msg);
  95. void reportKeyTypeMismatch(ICodeContext * ctx, const char * key, uint32_t flag, eclDataType eclType);
  96. void * cpy(const char * src, size_t length);
  97. void setPoolSettings();
  98. void assertPool();//For internal purposes to insure correct order of the above processes and instantiation.
  99. private :
  100. memcached_st * connection;
  101. memcached_pool_st * pool;
  102. StringAttr options;
  103. unsigned typeMismatchCount;
  104. };
  105. typedef Owned<MCached> OwnedMCached;
  106. static const unsigned MAX_TYPEMISMATCHCOUNT = 10;
  107. static __thread MCached * cachedConnection;
  108. static __thread bool threadHooked;
  109. //The following class is here to ensure destruction of the cachedConnection within the main thread
  110. //as this is not handled by the thread hook mechanism.
  111. static class mainThreadCachedConnection
  112. {
  113. public :
  114. mainThreadCachedConnection() { }
  115. ~mainThreadCachedConnection()
  116. {
  117. if (cachedConnection)
  118. {
  119. cachedConnection->Release();
  120. cachedConnection = NULL;
  121. }
  122. }
  123. } mainThread;
  124. static bool releaseContext(bool isPooled)
  125. {
  126. if (cachedConnection)
  127. {
  128. cachedConnection->Release();
  129. cachedConnection = NULL;
  130. }
  131. threadHooked = false;
  132. return false;
  133. }
  134. MCached * createConnection(ICodeContext * ctx, const char * options)
  135. {
  136. if (!cachedConnection)
  137. {
  138. cachedConnection = new MemCachedPlugin::MCached(ctx, options);
  139. if (!threadHooked)
  140. {
  141. addThreadTermFunc(releaseContext);
  142. threadHooked = true;
  143. }
  144. return LINK(cachedConnection);
  145. }
  146. if (cachedConnection->isSameConnection(options))
  147. return LINK(cachedConnection);
  148. cachedConnection->Release();
  149. cachedConnection = NULL;
  150. cachedConnection = new MemCachedPlugin::MCached(ctx, options);
  151. return LINK(cachedConnection);
  152. }
  153. //-------------------------------------------SET-----------------------------------------
  154. template<class type> void MSet(ICodeContext * ctx, const char * _options, const char * partitionKey, const char * key, type value, unsigned __int64 expire, eclDataType eclType)
  155. {
  156. OwnedMCached serverPool = createConnection(ctx, _options);
  157. serverPool->set(ctx, partitionKey, key, value, expire, eclType);
  158. }
  159. //Set pointer types
  160. template<class type> void MSet(ICodeContext * ctx, const char * _options, const char * partitionKey, const char * key, size32_t valueLength, const type * value, unsigned __int64 expire, eclDataType eclType)
  161. {
  162. OwnedMCached serverPool = createConnection(ctx, _options);
  163. serverPool->set(ctx, partitionKey, key, valueLength, value, expire, eclType);
  164. }
  165. //-------------------------------------------GET-----------------------------------------
  166. template<class type> void MGet(ICodeContext * ctx, const char * options, const char * partitionKey, const char * key, type & returnValue, eclDataType eclType)
  167. {
  168. OwnedMCached serverPool = createConnection(ctx, options);
  169. serverPool->get(ctx, partitionKey, key, returnValue, eclType);
  170. }
  171. template<class type> void MGet(ICodeContext * ctx, const char * options, const char * partitionKey, const char * key, size_t & returnLength, type * & returnValue, eclDataType eclType)
  172. {
  173. OwnedMCached serverPool = createConnection(ctx, options);
  174. serverPool->get(ctx, partitionKey, key, returnLength, returnValue, eclType);
  175. }
  176. void MGetVoidPtrLenPair(ICodeContext * ctx, const char * options, const char * partitionKey, const char * key, size_t & returnLength, void * & returnValue, eclDataType eclType)
  177. {
  178. OwnedMCached serverPool = createConnection(ctx, options);
  179. serverPool->getVoidPtrLenPair(ctx, partitionKey, key, returnLength, returnValue, eclType);
  180. }
  181. //----------------------------------SET----------------------------------------
  182. template<class type> void MemCachedPlugin::MCached::set(ICodeContext * ctx, const char * partitionKey, const char * key, type value, unsigned __int64 expire, eclDataType eclType)
  183. {
  184. const char * _value = reinterpret_cast<const char *>(&value);//Do this even for char * to prevent compiler complaining
  185. size_t partitionKeyLength = strlen(partitionKey);
  186. const char * msg = "'Set' request failed - ";
  187. if (partitionKeyLength)
  188. assertOnError(memcached_set_by_key(connection, partitionKey, partitionKeyLength, key, strlen(key), _value, sizeof(value), (time_t)expire, (uint32_t)eclType), msg);
  189. else
  190. assertOnError(memcached_set(connection, key, strlen(key), _value, sizeof(value), (time_t)expire, (uint32_t)eclType), msg);
  191. }
  192. template<class type> void MemCachedPlugin::MCached::set(ICodeContext * ctx, const char * partitionKey, const char * key, size32_t valueLength, const type * value, unsigned __int64 expire, eclDataType eclType)
  193. {
  194. const char * _value = reinterpret_cast<const char *>(value);//Do this even for char * to prevent compiler complaining
  195. size_t partitionKeyLength = strlen(partitionKey);
  196. const char * msg = "'Set' request failed - ";
  197. if (partitionKeyLength)
  198. assertOnError(memcached_set_by_key(connection, partitionKey, partitionKeyLength, key, strlen(key), _value, (size_t)(valueLength), (time_t)expire, (uint32_t)eclType), msg);
  199. else
  200. assertOnError(memcached_set(connection, key, strlen(key), _value, (size_t)(valueLength), (time_t)expire, (uint32_t)eclType), msg);
  201. }
  202. //----------------------------------GET----------------------------------------
  203. template<class type> void MemCachedPlugin::MCached::get(ICodeContext * ctx, const char * partitionKey, const char * key, type & returnValue, eclDataType eclType)
  204. {
  205. uint32_t flag = 0;
  206. size_t returnLength = 0;
  207. memcached_return_t rc;
  208. OwnedMalloc<char> value;
  209. size_t partitionKeyLength = strlen(partitionKey);
  210. if (partitionKeyLength)
  211. value.setown(memcached_get_by_key(connection, partitionKey, partitionKeyLength, key, strlen(key), &returnLength, &flag, &rc));
  212. else
  213. value.setown(memcached_get(connection, key, strlen(key), &returnLength, &flag, &rc));
  214. StringBuffer keyMsg("'Get<type>' request failed - ");
  215. assertOnError(rc, appendIfKeyNotFoundMsg(rc, key, keyMsg));
  216. reportKeyTypeMismatch(ctx, key, flag, eclType);
  217. if (sizeof(type)!=returnLength)
  218. {
  219. VStringBuffer msg("MemCachedPlugin: ERROR - Requested type of different size (%uB) from that stored (%uB). Check logs for more information.", (unsigned)sizeof(type), (unsigned)returnLength);
  220. rtlFail(0, msg.str());
  221. }
  222. memcpy(&returnValue, value, returnLength);
  223. }
  224. template<class type> void MemCachedPlugin::MCached::get(ICodeContext * ctx, const char * partitionKey, const char * key, size_t & returnLength, type * & returnValue, eclDataType eclType)
  225. {
  226. uint32_t flag = 0;
  227. memcached_return_t rc;
  228. OwnedMalloc<char> value;
  229. size_t partitionKeyLength = strlen(partitionKey);
  230. if (partitionKeyLength)
  231. value.setown(memcached_get_by_key(connection, partitionKey, partitionKeyLength, key, strlen(key), &returnLength, &flag, &rc));
  232. else
  233. value.setown(memcached_get(connection, key, strlen(key), &returnLength, &flag, &rc));
  234. StringBuffer keyMsg("'Get<type>' request failed - ");
  235. assertOnError(rc, appendIfKeyNotFoundMsg(rc, key, keyMsg));
  236. reportKeyTypeMismatch(ctx, key, flag, eclType);
  237. returnValue = reinterpret_cast<type*>(cpy(value, returnLength));
  238. }
  239. void MemCachedPlugin::MCached::getVoidPtrLenPair(ICodeContext * ctx, const char * partitionKey, const char * key, size_t & returnLength, void * & returnValue, eclDataType eclType)
  240. {
  241. uint32_t flag = 0;
  242. size_t returnValueLength = 0;
  243. memcached_return_t rc;
  244. OwnedMalloc<char> value;
  245. size_t partitionKeyLength = strlen(partitionKey);
  246. if (partitionKeyLength)
  247. value.setown(memcached_get_by_key(connection, partitionKey, partitionKeyLength, key, strlen(key), &returnValueLength, &flag, &rc));
  248. else
  249. value.setown(memcached_get(connection, key, strlen(key), &returnValueLength, &flag, &rc));
  250. StringBuffer keyMsg("'Get<type>' request failed - ");
  251. assertOnError(rc, appendIfKeyNotFoundMsg(rc, key, keyMsg));
  252. reportKeyTypeMismatch(ctx, key, flag, eclType);
  253. returnLength = (size32_t)(returnValueLength);
  254. returnValue = reinterpret_cast<void*>(cpy(value, returnLength));
  255. }
  256. MemCachedPlugin::MCached::MCached(ICodeContext * ctx, const char * _options) : connection(NULL), pool(NULL), typeMismatchCount(0)
  257. {
  258. #if (LIBMEMCACHED_VERSION_HEX < 0x01000010)
  259. StringBuffer msg("Memcached Plugin: libmemcached version '");
  260. msg.append(LIBMEMCACHED_VERSION_STRING).append("' incompatible with min version>=1.0.10");
  261. rtlFail(0, msg.str());
  262. #endif
  263. options.set(_options);
  264. pool = memcached_pool(_options, strlen(_options));
  265. assertPool();
  266. setPoolSettings();
  267. connect(ctx);
  268. checkServersUp(ctx);
  269. }
  270. //-----------------------------------------------------------------------------
  271. MemCachedPlugin::MCached::~MCached()
  272. {
  273. if (pool)
  274. {
  275. memcached_pool_release(pool, connection);
  276. connection = NULL;//For safety (from changing this destructor) as not implicit in either the above or below.
  277. memcached_st *memc = memcached_pool_destroy(pool);
  278. if (memc)
  279. memcached_free(memc);
  280. }
  281. else if (connection)//This should never be needed but just in case.
  282. {
  283. memcached_free(connection);
  284. }
  285. }
  286. bool MemCachedPlugin::MCached::isSameConnection(const char * _options) const
  287. {
  288. if (!_options)
  289. return false;
  290. return stricmp(options.get(), _options) == 0;
  291. }
  292. void MemCachedPlugin::MCached::assertPool()
  293. {
  294. if (!pool)
  295. {
  296. StringBuffer msg("Memcached Plugin: Failed to instantiate server pool with:");
  297. msg.newline().append(options);
  298. rtlFail(0, msg.str());
  299. }
  300. }
  301. void * MemCachedPlugin::MCached::cpy(const char * src, size_t length)
  302. {
  303. void * value = rtlMalloc(length);
  304. return memcpy(value, src, length);
  305. }
  306. void MemCachedPlugin::MCached::checkServersUp(ICodeContext * ctx)
  307. {
  308. memcached_return_t rc;
  309. char * args = NULL;
  310. OwnedMalloc<memcached_stat_st> stats;
  311. stats.setown(memcached_stat(connection, args, &rc));
  312. assertex(stats);
  313. unsigned int numberOfServers = memcached_server_count(connection);
  314. unsigned int numberOfServersDown = 0;
  315. for (unsigned i = 0; i < numberOfServers; ++i)
  316. {
  317. if (stats[i].pid == -1)//perhaps not the best test?
  318. {
  319. numberOfServersDown++;
  320. VStringBuffer msg("Memcached Plugin: Failed connecting to entry %u\nwithin the server list: %s", i+1, options.str());
  321. ctx->logString(msg.str());
  322. }
  323. }
  324. if (numberOfServersDown == numberOfServers)
  325. rtlFail(0,"Memcached Plugin: Failed connecting to ALL servers. Check memcached on all servers and \"memcached -B ascii\" not used.");
  326. //check memcached version homogeneity
  327. for (unsigned i = 0; i < numberOfServers-1; ++i)
  328. {
  329. if (strcmp(stats[i].version, stats[i+1].version) != 0)
  330. ctx->logString("Memcached Plugin: Inhomogeneous versions of memcached across servers.");
  331. }
  332. }
  333. bool MemCachedPlugin::MCached::logErrorOnFail(ICodeContext * ctx, memcached_return_t rc, const char * _msg)
  334. {
  335. if (rc == MEMCACHED_SUCCESS)
  336. return false;
  337. VStringBuffer msg("Memcached Plugin: %s%s", _msg, memcached_strerror(connection, rc));
  338. ctx->logString(msg.str());
  339. return true;
  340. }
  341. void MemCachedPlugin::MCached::assertOnError(memcached_return_t rc, const char * _msg)
  342. {
  343. if (rc != MEMCACHED_SUCCESS)
  344. {
  345. VStringBuffer msg("Memcached Plugin: %s%s", _msg, memcached_strerror(connection, rc));
  346. rtlFail(0, msg.str());
  347. }
  348. }
  349. const char * MemCachedPlugin::MCached::appendIfKeyNotFoundMsg(memcached_return_t rc, const char * key, StringBuffer & target) const
  350. {
  351. if (rc == MEMCACHED_NOTFOUND)
  352. target.append("(key: '").append(key).append("') ");
  353. return target.str();
  354. }
  355. void MemCachedPlugin::MCached::clear(ICodeContext * ctx, unsigned when)
  356. {
  357. //NOTE: memcached_flush is the actual cache flush/clear/delete and not an io buffer flush.
  358. assertOnError(memcached_flush(connection, (time_t)(when)), "'Clear' request failed - ");
  359. }
  360. bool MemCachedPlugin::MCached::exists(ICodeContext * ctx, const char * key, const char * partitionKey)
  361. {
  362. #if (LIBMEMCACHED_VERSION_HEX<0x53000)
  363. throw makeStringException(0, "memcached_exist not supported in this version of libmemcached");
  364. #else
  365. memcached_return_t rc;
  366. size_t partitionKeyLength = strlen(partitionKey);
  367. if (partitionKeyLength)
  368. rc = memcached_exist_by_key(connection, partitionKey, partitionKeyLength, key, strlen(key));
  369. else
  370. rc = memcached_exist(connection, key, strlen(key));
  371. if (rc == MEMCACHED_NOTFOUND)
  372. return false;
  373. else
  374. {
  375. assertOnError(rc, "'Exists' request failed - ");
  376. return true;
  377. }
  378. #endif
  379. }
  380. void MemCachedPlugin::MCached::deleteKey(ICodeContext * ctx, const char * key, const char * partitionKey)
  381. {
  382. memcached_return_t rc;
  383. size_t partitionKeyLength = strlen(partitionKey);
  384. if (partitionKeyLength)
  385. rc = memcached_delete_by_key(connection, partitionKey, partitionKeyLength, key, strlen(key), (time_t)0);
  386. else
  387. rc = memcached_delete(connection, key, strlen(key), (time_t)0);
  388. assertOnError(rc, "'Delete' request failed - ");
  389. }
  390. MemCachedPlugin::eclDataType MemCachedPlugin::MCached::getKeyType(const char * key, const char * partitionKey)
  391. {
  392. size_t returnValueLength;
  393. uint32_t flag;
  394. memcached_return_t rc;
  395. size_t partitionKeyLength = strlen(partitionKey);
  396. if (partitionKeyLength)
  397. memcached_get_by_key(connection, partitionKey, partitionKeyLength, key, strlen(key), &returnValueLength, &flag, &rc);
  398. else
  399. memcached_get(connection, key, strlen(key), &returnValueLength, &flag, &rc);
  400. if (rc == MEMCACHED_SUCCESS)
  401. return (MemCachedPlugin::eclDataType)(flag);
  402. else if (rc == MEMCACHED_NOTFOUND)
  403. return ECL_NONE;
  404. else
  405. {
  406. VStringBuffer msg("Memcached Plugin: 'KeyType' request failed - %s", memcached_strerror(connection, rc));
  407. rtlFail(0, msg.str());
  408. }
  409. }
  410. void MemCachedPlugin::MCached::reportKeyTypeMismatch(ICodeContext * ctx, const char * key, uint32_t flag, eclDataType eclType)
  411. {
  412. if (flag && eclType != ECL_DATA && flag != eclType)
  413. {
  414. VStringBuffer msg("Memcached Plugin: The requested key '%s' is of type %s, not %s as requested.", key, enumToStr((eclDataType)(flag)), enumToStr(eclType));
  415. if (++typeMismatchCount <= MAX_TYPEMISMATCHCOUNT)
  416. ctx->logString(msg.str());
  417. }
  418. }
  419. void MemCachedPlugin::MCached::setPoolSettings()
  420. {
  421. assertPool();
  422. const char * msg = "memcached_pool_behavior_set failed - ";
  423. assertOnError(memcached_pool_behavior_set(pool, MEMCACHED_BEHAVIOR_KETAMA, 1), msg);//NOTE: alias of MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA amongst others.
  424. memcached_pool_behavior_set(pool, MEMCACHED_BEHAVIOR_USE_UDP, 0); // Note that this fails on early versions of libmemcached, so ignore result
  425. assertOnError(memcached_pool_behavior_set(pool, MEMCACHED_BEHAVIOR_NO_BLOCK, 0), msg);
  426. assertOnError(memcached_pool_behavior_set(pool, MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT, 1000), msg);//units of ms.
  427. assertOnError(memcached_pool_behavior_set(pool, MEMCACHED_BEHAVIOR_SND_TIMEOUT, 1000000), msg);//units of mu-s.
  428. assertOnError(memcached_pool_behavior_set(pool, MEMCACHED_BEHAVIOR_RCV_TIMEOUT, 1000000), msg);//units of mu-s.
  429. assertOnError(memcached_pool_behavior_set(pool, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 0), msg);
  430. assertOnError(memcached_pool_behavior_set(pool, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, 1), "memcached_pool_behavior_set failed - ");
  431. }
  432. void MemCachedPlugin::MCached::connect(ICodeContext * ctx)
  433. {
  434. assertPool();
  435. if (connection)
  436. #if (LIBMEMCACHED_VERSION_HEX<0x53000)
  437. memcached_pool_push(pool, connection);
  438. #else
  439. memcached_pool_release(pool, connection);
  440. #endif
  441. memcached_return_t rc;
  442. #if (LIBMEMCACHED_VERSION_HEX<0x53000)
  443. connection = memcached_pool_pop(pool, (struct timespec *)0 , &rc);
  444. #else
  445. connection = memcached_pool_fetch(pool, (struct timespec *)0 , &rc);
  446. #endif
  447. assertOnError(rc, "memcached_pool_pop failed - ");
  448. }
  449. //--------------------------------------------------------------------------------
  450. // ECL SERVICE ENTRYPOINTS
  451. //--------------------------------------------------------------------------------
  452. ECL_MEMCACHED_API void ECL_MEMCACHED_CALL MClear(ICodeContext * ctx, const char * options)
  453. {
  454. OwnedMCached serverPool = MemCachedPlugin::createConnection(ctx, options);
  455. serverPool->clear(ctx, 0);
  456. }
  457. ECL_MEMCACHED_API bool ECL_MEMCACHED_CALL MExists(ICodeContext * ctx, const char * key, const char * options, const char * partitionKey)
  458. {
  459. OwnedMCached serverPool = MemCachedPlugin::createConnection(ctx, options);
  460. return serverPool->exists(ctx, key, partitionKey);
  461. }
  462. ECL_MEMCACHED_API const char * ECL_MEMCACHED_CALL MKeyType(ICodeContext * ctx, const char * key, const char * options, const char * partitionKey)
  463. {
  464. OwnedMCached serverPool = MemCachedPlugin::createConnection(ctx, options);
  465. const char * keyType = enumToStr(serverPool->getKeyType(key, partitionKey));
  466. return keyType;
  467. }
  468. ECL_MEMCACHED_API void ECL_MEMCACHED_CALL MDelete(ICodeContext * ctx, const char * key, const char * options, const char * partitionKey)
  469. {
  470. OwnedMCached serverPool = MemCachedPlugin::createConnection(ctx, options);
  471. serverPool->deleteKey(ctx, key, partitionKey);
  472. }
  473. //-----------------------------------SET------------------------------------------
  474. //NOTE: These were all overloaded by 'value' type, however; this caused problems since ecl implicitly casts and doesn't type check.
  475. ECL_MEMCACHED_API void ECL_MEMCACHED_CALL MSet(ICodeContext * ctx, const char * key, size32_t valueLength, const char * value, const char * options, const char * partitionKey, unsigned __int64 expire /* = 0 (ECL default)*/)
  476. {
  477. MemCachedPlugin::MSet(ctx, options, partitionKey, key, valueLength, value, expire, MemCachedPlugin::ECL_STRING);
  478. }
  479. ECL_MEMCACHED_API void ECL_MEMCACHED_CALL MSet(ICodeContext * ctx, const char * key, size32_t valueLength, const UChar * value, const char * options, const char * partitionKey, unsigned __int64 expire /* = 0 (ECL default)*/)
  480. {
  481. MemCachedPlugin::MSet(ctx, options, partitionKey, key, (valueLength)*sizeof(UChar), value, expire, MemCachedPlugin::ECL_UNICODE);
  482. }
  483. ECL_MEMCACHED_API void ECL_MEMCACHED_CALL MSet(ICodeContext * ctx, const char * key, signed __int64 value, const char * options, const char * partitionKey, unsigned __int64 expire /* = 0 (ECL default)*/)
  484. {
  485. MemCachedPlugin::MSet(ctx, options, partitionKey, key, value, expire, MemCachedPlugin::ECL_INTEGER);
  486. }
  487. ECL_MEMCACHED_API void ECL_MEMCACHED_CALL MSet(ICodeContext * ctx, const char * key, unsigned __int64 value, const char * options, const char * partitionKey, unsigned __int64 expire /* = 0 (ECL default)*/)
  488. {
  489. MemCachedPlugin::MSet(ctx, options, partitionKey, key, value, expire, MemCachedPlugin::ECL_UNSIGNED);
  490. }
  491. ECL_MEMCACHED_API void ECL_MEMCACHED_CALL MSet(ICodeContext * ctx, const char * key, double value, const char * options, const char * partitionKey, unsigned __int64 expire /* = 0 (ECL default)*/)
  492. {
  493. MemCachedPlugin::MSet(ctx, options, partitionKey, key, value, expire, MemCachedPlugin::ECL_REAL);
  494. }
  495. ECL_MEMCACHED_API void ECL_MEMCACHED_CALL MSet(ICodeContext * ctx, const char * key, bool value, const char * options, const char * partitionKey, unsigned __int64 expire)
  496. {
  497. MemCachedPlugin::MSet(ctx, options, partitionKey, key, value, expire, MemCachedPlugin::ECL_BOOLEAN);
  498. }
  499. ECL_MEMCACHED_API void ECL_MEMCACHED_CALL MSetData(ICodeContext * ctx, const char * key, size32_t valueLength, const void * value, const char * options, const char * partitionKey, unsigned __int64 expire)
  500. {
  501. MemCachedPlugin::MSet(ctx, options, partitionKey, key, valueLength, value, expire, MemCachedPlugin::ECL_DATA);
  502. }
  503. ECL_MEMCACHED_API void ECL_MEMCACHED_CALL MSetUtf8(ICodeContext * ctx, const char * key, size32_t valueLength, const char * value, const char * options, const char * partitionKey, unsigned __int64 expire /* = 0 (ECL default)*/)
  504. {
  505. MemCachedPlugin::MSet(ctx, options, partitionKey, key, rtlUtf8Size(valueLength, value), value, expire, MemCachedPlugin::ECL_UTF8);
  506. }
  507. //-------------------------------------GET----------------------------------------
  508. ECL_MEMCACHED_API bool ECL_MEMCACHED_CALL MGetBool(ICodeContext * ctx, const char * key, const char * options, const char * partitionKey)
  509. {
  510. bool value;
  511. MemCachedPlugin::MGet(ctx, options, partitionKey, key, value, MemCachedPlugin::ECL_BOOLEAN);
  512. return value;
  513. }
  514. ECL_MEMCACHED_API double ECL_MEMCACHED_CALL MGetDouble(ICodeContext * ctx, const char * key, const char * options, const char * partitionKey)
  515. {
  516. double value;
  517. MemCachedPlugin::MGet(ctx, options, partitionKey, key, value, MemCachedPlugin::ECL_REAL);
  518. return value;
  519. }
  520. ECL_MEMCACHED_API signed __int64 ECL_MEMCACHED_CALL MGetInt8(ICodeContext * ctx, const char * key, const char * options, const char * partitionKey)
  521. {
  522. signed __int64 value;
  523. MemCachedPlugin::MGet(ctx, options, partitionKey, key, value, MemCachedPlugin::ECL_INTEGER);
  524. return value;
  525. }
  526. ECL_MEMCACHED_API unsigned __int64 ECL_MEMCACHED_CALL MGetUint8(ICodeContext * ctx, const char * key, const char * options, const char * partitionKey)
  527. {
  528. unsigned __int64 value;
  529. MemCachedPlugin::MGet(ctx, options, partitionKey, key, value, MemCachedPlugin::ECL_UNSIGNED);
  530. return value;
  531. }
  532. ECL_MEMCACHED_API void ECL_MEMCACHED_CALL MGetStr(ICodeContext * ctx, size32_t & returnLength, char * & returnValue, const char * key, const char * options, const char * partitionKey)
  533. {
  534. size_t _returnLength;
  535. MemCachedPlugin::MGet(ctx, options, partitionKey, key, _returnLength, returnValue, MemCachedPlugin::ECL_STRING);
  536. returnLength = static_cast<size32_t>(_returnLength);
  537. }
  538. ECL_MEMCACHED_API void ECL_MEMCACHED_CALL MGetUChar(ICodeContext * ctx, size32_t & returnLength, UChar * & returnValue, const char * key, const char * options, const char * partitionKey)
  539. {
  540. size_t _returnSize;
  541. MemCachedPlugin::MGet(ctx, options, partitionKey, key, _returnSize, returnValue, MemCachedPlugin::ECL_UNICODE);
  542. returnLength = static_cast<size32_t>(_returnSize/sizeof(UChar));
  543. }
  544. ECL_MEMCACHED_API void ECL_MEMCACHED_CALL MGetUtf8(ICodeContext * ctx, size32_t & returnLength, char * & returnValue, const char * key, const char * options, const char * partitionKey)
  545. {
  546. size_t returnSize;
  547. MemCachedPlugin::MGet(ctx, options, partitionKey, key, returnSize, returnValue, MemCachedPlugin::ECL_UTF8);
  548. returnLength = static_cast<size32_t>(rtlUtf8Length(returnSize, returnValue));
  549. }
  550. ECL_MEMCACHED_API void ECL_MEMCACHED_CALL MGetData(ICodeContext * ctx, size32_t & returnLength, void * & returnValue, const char * key, const char * options, const char * partitionKey)
  551. {
  552. size_t _returnLength;
  553. MemCachedPlugin::MGetVoidPtrLenPair(ctx, options, partitionKey, key, _returnLength, returnValue, MemCachedPlugin::ECL_DATA);
  554. returnLength = static_cast<size32_t>(_returnLength);
  555. }
  556. }//close namespace