@@ -863,42 +863,56 @@ bounded_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds
863863 }
864864 if (self -> full && self -> root .next != & self -> root ) {
865865 /* Use the oldest item to store the new key and result. */
866- PyObject * oldkey , * oldresult ;
866+ PyObject * oldkey , * oldresult , * popresult ;
867867 /* Extricate the oldest item. */
868868 link = self -> root .next ;
869869 lru_cache_extricate_link (link );
870870 /* Remove it from the cache.
871871 The cache dict holds one reference to the link,
872872 and the linked list holds yet one reference to it. */
873- if (_PyDict_DelItem_KnownHash (self -> cache , link -> key ,
874- link -> hash ) < 0 ) {
873+ popresult = _PyDict_Pop_KnownHash (self -> cache ,
874+ link -> key , link -> hash ,
875+ Py_None );
876+ if (popresult == Py_None ) {
877+ /* Getting here means that this same key was added to the
878+ cache while the lock was released. Since the link
879+ update is already done, we need only return the
880+ computed result and update the count of misses. */
881+ Py_DECREF (popresult );
882+ Py_DECREF (link );
883+ Py_DECREF (key );
884+ }
885+ else if (popresult == NULL ) {
875886 lru_cache_append_link (self , link );
876887 Py_DECREF (key );
877888 Py_DECREF (result );
878889 return NULL ;
879890 }
880- /* Keep a reference to the old key and old result to
881- prevent their ref counts from going to zero during the
882- update. That will prevent potentially arbitrary object
883- clean-up code (i.e. __del__) from running while we're
884- still adjusting the links. */
885- oldkey = link -> key ;
886- oldresult = link -> result ;
887-
888- link -> hash = hash ;
889- link -> key = key ;
890- link -> result = result ;
891- if (_PyDict_SetItem_KnownHash (self -> cache , key , (PyObject * )link ,
892- hash ) < 0 ) {
893- Py_DECREF (link );
891+ else {
892+ Py_DECREF (popresult );
893+ /* Keep a reference to the old key and old result to
894+ prevent their ref counts from going to zero during the
895+ update. That will prevent potentially arbitrary object
896+ clean-up code (i.e. __del__) from running while we're
897+ still adjusting the links. */
898+ oldkey = link -> key ;
899+ oldresult = link -> result ;
900+
901+ link -> hash = hash ;
902+ link -> key = key ;
903+ link -> result = result ;
904+ if (_PyDict_SetItem_KnownHash (self -> cache , key , (PyObject * )link ,
905+ hash ) < 0 ) {
906+ Py_DECREF (link );
907+ Py_DECREF (oldkey );
908+ Py_DECREF (oldresult );
909+ return NULL ;
910+ }
911+ lru_cache_append_link (self , link );
912+ Py_INCREF (result ); /* for return */
894913 Py_DECREF (oldkey );
895914 Py_DECREF (oldresult );
896- return NULL ;
897915 }
898- lru_cache_append_link (self , link );
899- Py_INCREF (result ); /* for return */
900- Py_DECREF (oldkey );
901- Py_DECREF (oldresult );
902916 } else {
903917 /* Put result in a new link at the front of the queue. */
904918 link = (lru_list_elem * )PyObject_GC_New (lru_list_elem ,
0 commit comments