From 5fd68b34c7bbb3d51204c45ad37cf79f122d633e Mon Sep 17 00:00:00 2001 From: lericson Date: Sat, 5 Sep 2009 02:08:04 +0200 Subject: [PATCH] Merge patch from amix Add support for bool values, use ssize_t in some places (not sure about this) and some other stuff. --- _pylibmcmodule.c | 86 ++++++++++++++++++++++++++++-------------------- _pylibmcmodule.h | 1 + pylibmc.py | 3 ++ setup.py | 16 +++++++++ 4 files changed, 70 insertions(+), 36 deletions(-) diff --git a/_pylibmcmodule.c b/_pylibmcmodule.c index d23bf4a..9ab38f4 100644 --- a/_pylibmcmodule.c +++ b/_pylibmcmodule.c @@ -135,8 +135,12 @@ static PyObject *_PylibMC_parse_memcached_value(char *value, size_t size, case PYLIBMC_FLAG_LONG: retval = PyInt_FromString(value, NULL, 10); break; + case PYLIBMC_FLAG_BOOL: + retval = PyInt_FromString(value, NULL, 10); + retval = PyBool_FromLong(PyInt_AS_LONG(retval)); + break; case PYLIBMC_FLAG_NONE: - retval = PyString_FromStringAndSize(value, (Py_ssize_t)size); + retval = PyString_FromStringAndSize(value, (size_t)size); break; default: PyErr_Format(PylibMCExc_MemcachedError, @@ -199,6 +203,9 @@ static PyObject *_PylibMC_RunSetCommand(PylibMC_Client *self, } else if (PyString_Check(val)) { store_val = val; Py_INCREF(store_val); + } else if (PyBool_Check(val)) { + store_flags |= PYLIBMC_FLAG_BOOL; + store_val = PyObject_Str(PyNumber_Int(val)); } else if (PyInt_Check(val)) { store_flags |= PYLIBMC_FLAG_INTEGER; store_val = PyObject_Str(PyNumber_Int(val)); @@ -345,7 +352,8 @@ static PyObject *PylibMC_Client_get_multi(PylibMC_Client *self, PyObject *args, char **keys, *prefix = NULL; unsigned int prefix_len = 0; size_t *key_lens; - Py_ssize_t nkeys; + size_t nkeys; + unsigned int valid_keys_len = 0; memcached_return rc; char curr_key[MEMCACHED_MAX_KEY]; @@ -394,6 +402,7 @@ static PyObject *PylibMC_Client_get_multi(PylibMC_Client *self, PyObject *args, } keys[i] = PyString_AS_STRING(rkey); key_objs[i++] = rkey; + valid_keys_len++; } } Py_DECREF(key_it); @@ -416,44 +425,46 @@ static PyObject *PylibMC_Client_get_multi(PylibMC_Client *self, PyObject *args, */ retval = PyDict_New(); - if ((rc = memcached_mget(self->mc, keys, key_lens, nkeys)) - == MEMCACHED_SUCCESS) { - char *curr_val; + if(valid_keys_len > 0) { + if ((rc = memcached_mget(self->mc, keys, key_lens, nkeys)) + == MEMCACHED_SUCCESS) { + char *curr_val; - while ((curr_val = memcached_fetch( - self->mc, curr_key, &curr_key_len, &curr_val_len, - &curr_flags, &rc)) != NULL - && !PyErr_Occurred()) { - if (curr_val == NULL && rc == MEMCACHED_END) { - break; - } else if (rc == MEMCACHED_BAD_KEY_PROVIDED - || rc == MEMCACHED_NO_KEY_PROVIDED) { - /* Do nothing at all. :-) */ - } else if (rc != MEMCACHED_SUCCESS) { - Py_DECREF(retval); - retval = PylibMC_ErrFromMemcached( - self, "memcached_fetch", rc); - } else { - PyObject *val; + while ((curr_val = memcached_fetch( + self->mc, curr_key, &curr_key_len, &curr_val_len, + &curr_flags, &rc)) != NULL + && !PyErr_Occurred()) { + if (curr_val == NULL && rc == MEMCACHED_END) { + break; + } else if (rc == MEMCACHED_BAD_KEY_PROVIDED + || rc == MEMCACHED_NO_KEY_PROVIDED) { + /* Do nothing at all. :-) */ + } else if (rc != MEMCACHED_SUCCESS) { + Py_DECREF(retval); + retval = PylibMC_ErrFromMemcached( + self, "memcached_fetch", rc); + } else { + PyObject *val; - /* This is safe because libmemcached's max key length - * includes space for a NUL-byte. */ - curr_key[curr_key_len] = 0; - val = _PylibMC_parse_memcached_value( - curr_val, curr_val_len, curr_flags); - PyDict_SetItemString(retval, curr_key + prefix_len, val); - Py_DECREF(val); + /* This is safe because libmemcached's max key length + * includes space for a NUL-byte. */ + curr_key[curr_key_len] = 0; + val = _PylibMC_parse_memcached_value( + curr_val, curr_val_len, curr_flags); + PyDict_SetItemString(retval, curr_key + prefix_len, val); + Py_DECREF(val); + } + free(curr_val); } - free(curr_val); + /* Need to cleanup. */ + if (PyErr_Occurred()) { + /* Not checking rc because an exception already occured, and + * we wouldn't want to mask it. */ + memcached_quit(self->mc); + } + } else { + retval = PylibMC_ErrFromMemcached(self, "memcached_mget", rc); } - /* Need to cleanup. */ - if (PyErr_Occurred()) { - /* Not checking rc because an exception already occured, and - * we wouldn't want to mask it. */ - memcached_quit(self->mc); - } - } else { - retval = PylibMC_ErrFromMemcached(self, "memcached_mget", rc); } free(key_lens); @@ -712,6 +723,9 @@ static PyObject *PylibMC_ErrFromMemcached(PylibMC_Client *self, const char *what if (error == MEMCACHED_ERRNO) { PyErr_Format(PylibMCExc_MemcachedError, "system error %d from %s: %s", errno, what, strerror(errno)); + /* The key exists, but it has no value */ + } else if (error == 0) { + PyErr_SetString(PyExc_RuntimeError, "error == 0? " __FILE__ ":" __LINE__); } else { PyErr_Format(PylibMCExc_MemcachedError, "error %d from %s: %s", error, what, memcached_strerror(self->mc, error)); diff --git a/_pylibmcmodule.h b/_pylibmcmodule.h index bdd597b..6d188c8 100644 --- a/_pylibmcmodule.h +++ b/_pylibmcmodule.h @@ -47,6 +47,7 @@ #define PYLIBMC_FLAG_PICKLE (1 << 0) #define PYLIBMC_FLAG_INTEGER (1 << 1) #define PYLIBMC_FLAG_LONG (1 << 2) +#define PYLIBMC_FLAG_BOOL (1 << 3) #define PYLIBMC_INC (1 << 0) #define PYLIBMC_DEC (1 << 1) diff --git a/pylibmc.py b/pylibmc.py index adcfd2e..ac1e867 100644 --- a/pylibmc.py +++ b/pylibmc.py @@ -72,6 +72,9 @@ class Client(_pylibmc.client): stype = _pylibmc.server_type_tcp addr_tups.append((stype, addr, port)) super(Client, self).__init__(addr_tups) + # Perfomance is generally a lot better with tcp_nodelay + # so set that as the default + self.behaviors["tcp_nodelay"] = True def get_behaviors(self): """Gets the behaviors from the underlying C client instance. diff --git a/setup.py b/setup.py index 7afa0fb..13d0314 100644 --- a/setup.py +++ b/setup.py @@ -10,8 +10,24 @@ if "LIBMEMCACHED_DIR" in os.environ: libdirs.append(os.path.join(libdir, "lib")) readme_text = open("README.rst", "U").read() + +BASE_CFLAGS = ["-O3"] +BASE_LDFLAGS = [] + +mac_snow_leopard = (os.path.exists("/Developer/SDKs/MacOSX10.6.sdk/") and + int(os.uname()[2].split('.')[0]) >= 8) + +if mac_snow_leopard: + # Only compile the 64bit version on Snow Leopard + # libmemcached should also be compiled with make + # CFLAGS="-arch x86_64" + # else one will expereince seg. faults + BASE_LDFLAGS.extend(['-arch', 'x86_64']) + BASE_CFLAGS.extend(['-arch', 'x86_64']) pylibmc_ext = Extension("_pylibmc", ["_pylibmcmodule.c"], + extra_compile_args=BASE_CFLAGS, + extra_link_args=BASE_LDFLAGS, libraries=["memcached"], include_dirs=incdirs, library_dirs=libdirs)