@@ -155,18 +155,20 @@ cache_resize(PyTypeObject *type, struct type_cache *cache)
155155 if (new_cache == NULL ) {
156156 return -1 ;
157157 }
158- FT_ATOMIC_STORE_UINT_RELAXED (cache -> version_tag , FT_ATOMIC_LOAD_UINT_RELAXED (type -> tp_version_tag ));
159158 for (uint32_t i = 0 ; i < old_size ; i ++ ) {
160159 if (cache -> hashtable [i ].name != NULL ) {
161160 cache_insert (new_cache , cache -> hashtable [i ].name ,
162161 cache -> hashtable [i ].value );
163162 }
164163 }
164+ new_cache -> version_tag = cache -> version_tag ;
165165 cache_set (type , new_cache );
166166 cache_free_delayed (cache );
167167 return 0 ;
168168}
169169
170+ // Insert a new entry to the type cache. If the cache is full, resize it before inserting the new entry.
171+ // The TYPE_LOCK should be held while calling this function.
170172void
171173_PyTypeCache_Insert (PyTypeObject * type , PyObject * name , PyObject * value )
172174{
@@ -185,6 +187,10 @@ _PyTypeCache_Insert(PyTypeObject *type, PyObject *name, PyObject *value)
185187 FT_ATOMIC_STORE_UINT_RELAXED (cache -> version_tag , FT_ATOMIC_LOAD_UINT_RELAXED (type -> tp_version_tag ));
186188}
187189
190+
191+ // Lookup the given name in the type cache.
192+ // The cache is lock-free so it is possible that cache becomes stale during the lookup,
193+ // to prevent returning stale cache entry, the cache version is compared with the type version tag.
188194struct _PyTypeCacheLookupResult
189195_PyTypeCache_Lookup (PyTypeObject * type , PyObject * name )
190196{
@@ -225,12 +231,13 @@ _PyTypeCache_Lookup(PyTypeObject *type, PyObject *name)
225231 return (struct _PyTypeCacheLookupResult ){out_ref , 1 , cache_version };
226232}
227233
228-
234+ // Invalidate the type cache of the type.
235+ // The cache is set to the empty cache and the old cache is freed with QSBR.
236+ // The TYPE_LOCK should be held while calling this function.
229237void
230238_PyTypeCache_Invalidate (PyTypeObject * type )
231239{
232240 struct type_cache * cache = cache_get (type );
233- // if the type was modified, the cache is set to the empty cache and the old cache is freed after a delay.
234241 cache_set (type , & empty_cache );
235242 cache_free_delayed (cache );
236243}
0 commit comments