--- /dev/null
+#include "ml-memcached.h"
+#include "motorconst.h"
+#include "ml.h"
+#include "mlenv.h"
+#include "motorenv.h"
+#include "ustring.h"
+#include "expr.h"
+#include <libmemcached/memcached.h>
+#include <time.h>
+#include <vector>
+#include <exception>
+
+#define MEMCACHED_LOCALHOST "127.0.0.1"
+#define MEMCACHED_PORT MEMCACHED_DEFAULT_PORT
+#define MEMCACHED_SOCKET "memcached/cache.sock"
+
+/*DOC:
+==memcached module==
+
+*/
+
+/*DOC:
+===$memcached===
+ ($memcached [SUBFUNCTION...]) -> VALUE
+
+*/
+//#MFUNC $memcached ml_memcached cMLMemcachedID
+MNode* ml_memcached (MNode* cell, MlEnv* mlenv) {
+ MNode* arg = cell->cdr ();
+ MLMemcached obj (mlenv);
+ MNodePtr ans;
+ memcached_return_t rc;
+
+ if (obj.mem == NULL) {
+ throw (ustring (CharConst ("can't connect to the memcached server")));
+ }
+// rc = memcached_server_add (obj.mem, MEMCACHED_LOCALHOST, MEMCACHED_PORT);
+ rc = memcached_server_add_unix_socket (obj.mem, mlenv->env->path_to_etc (ustring (CharConst (MEMCACHED_SOCKET))).c_str ());
+ rc = memcached_behavior_set (obj.mem, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, 1);
+
+ mlenv->setMStack (&obj);
+ ans = progn (arg, mlenv);
+ if (mlenv->breaksym ()
+ && (mlenv->breaksym ()->isNil () || eq (mlenv->breaksym (), cell->car ()))) {
+ mlenv->setBreaksym (NULL);
+ }
+
+ return mlenv->retval = ans ();
+}
+
+/*DOC:
+===subfunctions of $memcached===
+
+*/
+/*DOC:
+====cache-set====
+ (cache-set KEY VALUE [:expire TIMESEC]) -> NULL
+
+*/
+//#SFUNC cache-set ml_memcached_cache_set
+MNode* ml_memcached_cache_set (MNode* cell, MlEnv* mlenv, MLFunc* mobj) {
+ MNode* arg = cell->cdr ();
+ MLMemcached* obj = MObjRef<MLMemcached> (mobj, cMLMemcachedID);
+ ustring key;
+ ustring val;
+ time_t expire = 0;
+ memcached_return_t rc;
+ std::vector<MNode*> params;
+ std::vector<MNode*> keywords;
+ static paramList kwlist[] = {
+ {CharConst ("expire"), false},
+ {NULL, 0, 0}
+ };
+
+ setParams (arg, 2, ¶ms, kwlist, &keywords, NULL);
+ key = eval_str (params[0], mlenv);
+ val = eval_str (params[1], mlenv);
+ if (keywords[0]) {
+ expire = eval_int (keywords[0], mlenv);
+ }
+
+ rc = memcached_set (obj->mem, key.data (), key.length (), val.data (), val.length (), expire, 0);
+
+ return NULL;
+}
+
+/*DOC:
+====cache-get====
+ (cache-get KEY) -> STRING
+
+*/
+//#SFUNC cache-get ml_memcached_cache_get
+MNode* ml_memcached_cache_get (MNode* cell, MlEnv* mlenv, MLFunc* mobj) {
+ MNode* arg = cell->cdr ();
+ MLMemcached* obj = MObjRef<MLMemcached> (mobj, cMLMemcachedID);
+ ustring key;
+ char* val;
+ size_t valLen = 0;
+ uint32_t flag;
+ memcached_return_t rc;
+ MNode* ans = NULL;
+
+ if (!arg)
+ throw (uErrorWrongNumber);
+ key = eval_str (arg->car (), mlenv);
+ nextNode (arg);
+ if (arg)
+ throw (uErrorWrongNumber);
+
+ val = memcached_get (obj->mem, key.data (), key.length (), &valLen, &flag, &rc);
+ if (val) {
+ ans = newMNode_str (new ustring (val, valLen));
+ }
+
+ return ans;
+}
+
+/*DOC:
+====cache-delete====
+ (cache-delete KEY [:expire TIMESEC]) -> NULL
+
+*/
+//#SFUNC cache-delete ml_memcached_cache_delete
+MNode* ml_memcached_cache_delete (MNode* cell, MlEnv* mlenv, MLFunc* mobj) {
+ MNode* arg = cell->cdr ();
+ MLMemcached* obj = MObjRef<MLMemcached> (mobj, cMLMemcachedID);
+ ustring key;
+ time_t expire = 0;
+ memcached_return_t rc;
+ std::vector<MNode*> params;
+ std::vector<MNode*> keywords;
+ static paramList kwlist[] = {
+ {CharConst ("expire"), false},
+ {NULL, 0, 0}
+ };
+
+ setParams (arg, 1, ¶ms, kwlist, &keywords, NULL);
+ key = eval_str (params[0], mlenv);
+ if (keywords[0]) {
+ expire = eval_int (keywords[0], mlenv);
+ }
+
+ rc = memcached_delete (obj->mem, key.data (), key.length (), expire);
+
+ return NULL;
+}
+
+/*DOC:
+====cache-increment====
+ (cache-increment KEY [:offset INTEGER] [:initial INTEGER] [:expire TIME]) -> NULL
+
+*/
+//#SFUNC cache-increment ml_memcached_cache_increment
+MNode* ml_memcached_cache_increment (MNode* cell, MlEnv* mlenv, MLFunc* mobj) {
+ MNode* arg = cell->cdr ();
+ MLMemcached* obj = MObjRef<MLMemcached> (mobj, cMLMemcachedID);
+ ustring key;
+ memcached_return_t rc;
+ uint64_t offset = 1;
+ uint64_t initial = 0;
+ time_t expire = 0;
+ uint64_t val;
+ std::vector<MNode*> params;
+ std::vector<MNode*> keywords;
+ static paramList kwlist[] = {
+ {CharConst ("offset"), false},
+ {CharConst ("initial"), false},
+ {CharConst ("expire"), false},
+ {NULL, 0, 0}
+ };
+
+ setParams (arg, 1, ¶ms, kwlist, &keywords, NULL);
+ key = eval_str (params[0], mlenv);
+ if (keywords[0]) { // offset
+ offset = eval_int (keywords[0], mlenv);
+ }
+ if (keywords[1]) { // initial
+ initial = eval_int (keywords[1], mlenv); // XXX: not uint64_t
+ if (keywords[2]) { // expire
+ expire = eval_int (keywords[2], mlenv);
+ }
+ rc = memcached_increment_with_initial (obj->mem, key.data (), key.length (), offset, initial, expire, &val);
+ } else {
+ rc = memcached_increment (obj->mem, key.data (), key.length (), offset, &val);
+ }
+
+ if (rc == MEMCACHED_SUCCESS) {
+ return newMNode_num (val); // XXX: no uint64_t
+ } else {
+ return NULL;
+ }
+}
+
+/*DOC:
+====cache-decrement====
+ (cache-decrement KEY [:offset INTEGER] [:initial INTEGER] [:expire TIME]) -> NULL
+
+*/
+//#SFUNC cache-decrement ml_memcached_cache_decrement
+MNode* ml_memcached_cache_decrement (MNode* cell, MlEnv* mlenv, MLFunc* mobj) {
+ MNode* arg = cell->cdr ();
+ MLMemcached* obj = MObjRef<MLMemcached> (mobj, cMLMemcachedID);
+ ustring key;
+ memcached_return_t rc;
+ uint64_t offset = 1;
+ uint64_t initial = 0;
+ time_t expire = 0;
+ uint64_t val;
+ std::vector<MNode*> params;
+ std::vector<MNode*> keywords;
+ static paramList kwlist[] = {
+ {CharConst ("offset"), false},
+ {CharConst ("initial"), false},
+ {CharConst ("expire"), false},
+ {NULL, 0, 0}
+ };
+
+ setParams (arg, 1, ¶ms, kwlist, &keywords, NULL);
+ key = eval_str (params[0], mlenv);
+ if (keywords[0]) { // offset
+ offset = eval_int (keywords[0], mlenv);
+ }
+ if (keywords[1]) { // initial
+ initial = eval_int (keywords[1], mlenv); // XXX: not uint64_t
+ if (keywords[2]) { // expire
+ expire = eval_int (keywords[2], mlenv);
+ }
+ rc = memcached_decrement_with_initial (obj->mem, key.data (), key.length (), offset, initial, expire, &val);
+ } else {
+ rc = memcached_decrement (obj->mem, key.data (), key.length (), offset, &val);
+ }
+
+ if (rc == MEMCACHED_SUCCESS) {
+ return newMNode_num (val); // XXX: no uint64_t
+ } else {
+ return NULL;
+ }
+}