Skip to content

Commit d60c12c

Browse files
committed
gh-131757: allow lru_cache functions to execute concurrently
1 parent 96ef4c5 commit d60c12c

File tree

1 file changed

+57
-25
lines changed

1 file changed

+57
-25
lines changed

Modules/_functoolsmodule.c

Lines changed: 57 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1195,14 +1195,13 @@ infinite_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwd
11951195
Py_DECREF(key);
11961196
return NULL;
11971197
}
1198-
result = _PyDict_GetItem_KnownHash(self->cache, key, hash);
1199-
if (result) {
1200-
Py_INCREF(result);
1198+
int res = _PyDict_GetItemRef_KnownHash((PyDictObject *)self->cache, key, hash, &result);
1199+
if (res > 0) {
12011200
self->hits++;
12021201
Py_DECREF(key);
12031202
return result;
12041203
}
1205-
if (PyErr_Occurred()) {
1204+
if (res < 0) {
12061205
Py_DECREF(key);
12071206
return NULL;
12081207
}
@@ -1281,37 +1280,45 @@ lru_cache_prepend_link(lru_cache_object *self, lru_list_elem *link)
12811280
so that we know the cache is a consistent state.
12821281
*/
12831282

1284-
static PyObject *
1285-
bounded_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
1283+
static int
1284+
bounded_lru_cache_wrapper_pre_call_lock_held(lru_cache_object *self, PyObject *args, PyObject *kwds,
1285+
PyObject **result, PyObject **key, Py_hash_t *hash)
12861286
{
12871287
lru_list_elem *link;
1288-
PyObject *key, *result, *testresult;
1289-
Py_hash_t hash;
12901288

1291-
key = lru_cache_make_key(self->kwd_mark, args, kwds, self->typed);
1292-
if (!key)
1293-
return NULL;
1294-
hash = PyObject_Hash(key);
1295-
if (hash == -1) {
1296-
Py_DECREF(key);
1297-
return NULL;
1289+
PyObject *_key = *key = lru_cache_make_key(self->kwd_mark, args, kwds, self->typed);
1290+
if (!_key)
1291+
return -1;
1292+
Py_hash_t _hash = *hash = PyObject_Hash(_key);
1293+
if (_hash == -1) {
1294+
Py_DECREF(_key);
1295+
return -1;
12981296
}
1299-
link = (lru_list_elem *)_PyDict_GetItem_KnownHash(self->cache, key, hash);
1297+
link = (lru_list_elem *)_PyDict_GetItem_KnownHash(self->cache, _key, _hash);
13001298
if (link != NULL) {
13011299
lru_cache_extract_link(link);
13021300
lru_cache_append_link(self, link);
1303-
result = link->result;
1301+
*result = link->result;
13041302
self->hits++;
1305-
Py_INCREF(result);
1306-
Py_DECREF(key);
1307-
return result;
1303+
Py_INCREF(link->result);
1304+
Py_DECREF(_key);
1305+
return 1;
13081306
}
13091307
if (PyErr_Occurred()) {
1310-
Py_DECREF(key);
1311-
return NULL;
1308+
Py_DECREF(_key);
1309+
return -1;
13121310
}
13131311
self->misses++;
1314-
result = PyObject_Call(self->func, args, kwds);
1312+
return 0;
1313+
}
1314+
1315+
PyObject *
1316+
bounded_lru_cache_wrapper_post_call_lock_held(lru_cache_object *self,
1317+
PyObject *result, PyObject *key, Py_hash_t hash)
1318+
{
1319+
lru_list_elem *link;
1320+
PyObject *testresult;
1321+
13151322
if (!result) {
13161323
Py_DECREF(key);
13171324
return NULL;
@@ -1447,6 +1454,33 @@ bounded_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds
14471454
return result;
14481455
}
14491456

1457+
static PyObject *
1458+
bounded_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
1459+
{
1460+
PyObject *key, *result;
1461+
Py_hash_t hash;
1462+
int res;
1463+
1464+
Py_BEGIN_CRITICAL_SECTION(self);
1465+
res = bounded_lru_cache_wrapper_pre_call_lock_held(self, args, kwds, &result, &key, &hash);
1466+
Py_END_CRITICAL_SECTION();
1467+
1468+
if (res < 0) {
1469+
return NULL;
1470+
}
1471+
if (res > 0) {
1472+
return result;
1473+
}
1474+
1475+
result = PyObject_Call(self->func, args, kwds);
1476+
1477+
Py_BEGIN_CRITICAL_SECTION(self);
1478+
result = bounded_lru_cache_wrapper_post_call_lock_held(self, result, key, hash);
1479+
Py_END_CRITICAL_SECTION();
1480+
1481+
return result;
1482+
}
1483+
14501484
static PyObject *
14511485
lru_cache_new(PyTypeObject *type, PyObject *args, PyObject *kw)
14521486
{
@@ -1579,9 +1613,7 @@ lru_cache_call(PyObject *op, PyObject *args, PyObject *kwds)
15791613
{
15801614
lru_cache_object *self = lru_cache_object_CAST(op);
15811615
PyObject *result;
1582-
Py_BEGIN_CRITICAL_SECTION(self);
15831616
result = self->wrapper(self, args, kwds);
1584-
Py_END_CRITICAL_SECTION();
15851617
return result;
15861618
}
15871619

0 commit comments

Comments
 (0)