/* Extracted copy of PylibMC_Client_get_multi */ |
static PyObject *PylibMC_Client_get_multi( |
PylibMC_Client *self, PyObject *args, PyObject *kwds) { |
PyObject *key_seq, **key_objs, *retval = NULL; |
char **keys, *prefix = NULL; |
char *err_func = NULL; |
memcached_result_st *res, *results = NULL; |
int prefix_len = 0; |
Py_ssize_t i; |
PyObject *key_it, *ckey; |
size_t *key_lens; |
size_t nkeys, nresults = 0; |
memcached_return rc; |
static char *kws[] = { "keys", "key_prefix", NULL }; |
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|s#:get_multi", kws, |
&key_seq, &prefix, &prefix_len)) |
return NULL; |
if ((nkeys = (size_t)PySequence_Length(key_seq)) == -1) |
return NULL; |
/* Populate keys and key_lens. */ |
keys = PyMem_New(char *, nkeys); |
key_lens = PyMem_New(size_t, nkeys); |
key_objs = PyMem_New(PyObject *, nkeys); |
if (!keys || !key_lens || !key_objs) { |
PyMem_Free(keys); |
PyMem_Free(key_lens); |
PyMem_Free(key_objs); |
return PyErr_NoMemory(); |
} |
/* Clear potential previous exception, because we explicitly check for |
* exceptions as a loop predicate. */ |
PyErr_Clear(); |
/* Iterate through all keys and set lengths etc. */ |
key_it = PyObject_GetIter(key_seq); |
i = 0; |
while ((ckey = PyIter_Next(key_it)) != NULL) { |
char *key; |
Py_ssize_t key_len; |
PyObject *rkey; |
assert(i < nkeys); |
if (PyErr_Occurred() || !_PylibMC_CheckKey(ckey)) { |
nkeys = i; |
goto earlybird; |
} |
PyString_AsStringAndSize(ckey, &key, &key_len); |
key_lens[i] = (size_t)(key_len + prefix_len); |
/* Skip empty keys */ |
if (!key_lens[i]) |
continue; |
/* determine rkey, the prefixed ckey */ |
if (prefix != NULL) { |
rkey = PyString_FromStringAndSize(prefix, prefix_len); |
PyString_Concat(&rkey, ckey); |
if (rkey == NULL) |
goto earlybird; |
rkey = PyString_FromFormat("%s%s", |
prefix, PyString_AS_STRING(ckey)); |
} else { |
Py_INCREF(ckey); |
rkey = ckey; |
} |
Py_DECREF(ckey); |
keys[i] = PyString_AS_STRING(rkey); |
key_objs[i++] = rkey; |
} |
nkeys = i; |
Py_XDECREF(key_it); |
if (nkeys == 0) { |
retval = PyDict_New(); |
goto earlybird; |
} else if (PyErr_Occurred()) { |
nkeys--; |
goto earlybird; |
} |
/* TODO Make an iterator interface for getting each key separately. |
* |
* This would help large retrievals, as a single dictionary containing all |
* the data at once isn't needed. (Should probably look into if it's even |
* worth it.) |
*/ |
Py_BEGIN_ALLOW_THREADS; |
rc = pylibmc_memcached_fetch_multi(self->mc, |
keys, nkeys, key_lens, |
&results, &nresults, |
&err_func); |
Py_END_ALLOW_THREADS; |
if (rc != MEMCACHED_SUCCESS) { |
PylibMC_ErrFromMemcached(self, err_func, rc); |
goto earlybird; |
} |
retval = PyDict_New(); |
for (i = 0; i < nresults; i++) { |
PyObject *val, *key_obj; |
int rc; |
res = results + i; |
/* Explicitly construct a key string object so that NUL-bytes and the |
* likes can be contained within the keys (this is possible in the |
* binary protocol.) */ |
key_obj = PyString_FromStringAndSize(memcached_result_key_value(res) + prefix_len, |
memcached_result_key_length(res) - prefix_len); |
if (key_obj == NULL) |
goto unpack_error; |
/* Parse out value */ |
val = _PylibMC_parse_memcached_result(res); |
if (val == NULL) |
goto unpack_error; |
rc = PyDict_SetItem(retval, key_obj, val); |
Py_DECREF(key_obj); |
Py_DECREF(val); |
if (rc != 0) |
goto unpack_error; |
continue; |
unpack_error: |
Py_DECREF(retval); |
break; |
} |
earlybird: |
PyMem_Free(key_lens); |
PyMem_Free(keys); |
for (i = 0; i < nkeys; i++) |
Py_DECREF(key_objs[i]); |
PyMem_Free(key_objs); |
if (results != NULL) { |
for (i = 0; i < nresults && results != NULL; i++) { |
memcached_result_free(results + i); |
} |
PyMem_Free(results); |
} |
/* Not INCREFing because the only two outcomes are NULL and a new dict. |
* We're the owner of that dict already, so. */ |
return retval; |
} |
when _PyArg_ParseTupleAndKeywords_SizeT() succeeds
taking False path
when PySequence_Size() succeeds
taking False path
when considering range: 0 <= value <= 0xfffffffffffffff
taking True path
when PyMem_Malloc() succeeds
taking True path
when PyMem_Malloc() succeeds
taking True path
when PyMem_Malloc() succeeds
taking False path
taking False path
taking False path
calling PyErr_Clear()
when PyObject_GetIter() succeeds
when PyIter_Next() retrieves a value (new ref)
taking True path
when considering range: 1 <= nkeys <= 0xfffffffffffffff
taking False path
PyErr_Occurred()
taking False path
when considering range: -0x80000000 <= value <= -1
taking False path
when considering range: -0x8000000000000000 <= value <= -1
taking False path
when treating unknown const char * from libcpychecker/html/test/example2/pylibmc-issue-68.c:68 as non-NULL
taking True path
when PyString_FromStringAndSize() succeeds
when PyString_Concat() succeeds (Py_DECREF() without deallocation on *LHS)
taking False path
when PyString_FromFormat() succeeds
when taking True path
when PyIter_Next() returns NULL without setting an exception (end of iteration)
taking False path
taking False path
when taking True path
taking False path
PyErr_Occurred()
taking False path
releasing the GIL by calling PyEval_SaveThread()
reacquiring the GIL by calling PyEval_RestoreThread()
when considering value == (int)0 from libcpychecker/html/test/example2/pylibmc-issue-68.c:148
taking False path
when PyDict_New() succeeds
when taking True path
when PyString_FromStringAndSize() succeeds
taking False path
when treating unknown struct PyObject * from libcpychecker/html/test/example2/pylibmc-issue-68.c:176 as non-NULL
taking False path
when PyDict_SetItem() fails
when taking True path
when considering range: -0x8000000000000000 <= value <= -1
taking True path
taking True path
when taking False path
calling tp_dealloc on PyDictObject allocated at libcpychecker/html/test/example2/pylibmc-issue-68.c:159
memory deallocated here
calling PyMem_Free on PyMem_Malloc allocated at libcpychecker/html/test/example2/pylibmc-issue-68.c:77
calling PyMem_Free on PyMem_Malloc allocated at libcpychecker/html/test/example2/pylibmc-issue-68.c:76
taking True path
when taking True path
taking False path
calling PyMem_Free on PyMem_Malloc allocated at libcpychecker/html/test/example2/pylibmc-issue-68.c:78
when treating unknown struct memcached_result_st * * from libcpychecker/html/test/example2/pylibmc-issue-68.c:148 as non-NULL
taking True path
when taking True path
taking True path
when taking False path
calling PyMem_Free on Region('heap-region-12')
found 11 similar trace(s) to this