Skip to content

Commit 7416272

Browse files
consistent function naming
1 parent bd59f2d commit 7416272

1 file changed

Lines changed: 30 additions & 18 deletions

File tree

Python/typecache.c

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -41,31 +41,36 @@ static inline size_t cache_nbytes(struct type_cache *cache)
4141
+ (size_t)cache_size(cache) * sizeof(struct type_cache_entry);
4242
}
4343

44-
static struct type_cache *allocate_cache(uint32_t size)
44+
static struct type_cache *cache_allocate(uint32_t size)
4545
{
46+
// size must be a power of two
4647
assert((size & (size - 1)) == 0);
4748
struct type_cache *cache = PyMem_Calloc(1, sizeof(struct type_cache) + size * sizeof(struct type_cache_entry));
4849
if (cache == NULL) {
4950
return NULL;
5051
}
5152
cache->mask = size - 1;
53+
// load factor of 0.75
5254
cache->available = size - (size >> 2);
5355
cache->used = 0;
5456
return cache;
5557
}
5658

57-
static void free_cache_delayed(struct type_cache *cache)
59+
static void cache_free_delayed(struct type_cache *cache)
5860
{
5961
if (cache == NULL || cache == &empty_cache) {
6062
return;
6163
}
6264
#ifndef Py_GIL_DISABLED
65+
// On gil-enabled builds, the cache owns strong references to the interned strings,
66+
// so we need to decref them before freeing the cache memory.
6367
for (uint32_t i = 0; i < cache_size(cache); i++) {
6468
if (cache->hashtable[i].name != NULL) {
6569
Py_DECREF(cache->hashtable[i].name);
6670
}
6771
}
6872
#endif
73+
// Delay the freeing of old cache for concurrent lock-free readers
6974
_PyMem_FreeDelayed(cache, cache_nbytes(cache));
7075
}
7176

@@ -81,12 +86,12 @@ static inline void **cache_slot(PyTypeObject *type)
8186
return &type->_tp_cache;
8287
}
8388

84-
static inline struct type_cache *get_cache(PyTypeObject *type)
89+
static inline struct type_cache *cache_get(PyTypeObject *type)
8590
{
8691
return (struct type_cache *)FT_ATOMIC_LOAD_PTR(*cache_slot(type));
8792
}
8893

89-
static inline void set_cache(PyTypeObject *type, struct type_cache *cache)
94+
static inline void cache_set(PyTypeObject *type, struct type_cache *cache)
9095
{
9196
FT_ATOMIC_STORE_PTR(*cache_slot(type), cache);
9297
}
@@ -96,7 +101,7 @@ void _PyTypeCache_InitType(PyTypeObject *type)
96101
*cache_slot(type) = &empty_cache;
97102
}
98103

99-
static inline void type_cache_insert(struct type_cache *cache, PyObject *name,
104+
static inline void cache_insert(struct type_cache *cache, PyObject *name,
100105
PyObject *value)
101106
{
102107
Py_hash_t hash = PyUnstable_Unicode_GET_CACHED_HASH(name);
@@ -115,57 +120,63 @@ static inline void type_cache_insert(struct type_cache *cache, PyObject *name,
115120
return;
116121
}
117122
else if (cache->hashtable[index].name == name) {
123+
/* someone else added the entry before us. */
118124
return;
119125
}
120126
index = (index + 1) & cache->mask;
121127
}
122128
}
123129

124-
static inline int type_cache_resize(PyTypeObject *type, struct type_cache *cache)
130+
static inline int cache_resize(PyTypeObject *type, struct type_cache *cache)
125131
{
126132
uint32_t old_size = cache_size(cache);
127133
uint32_t new_size;
128134
if (cache->used == 0) {
135+
// the cache is the empty cache, we need to allocate a new cache with the minimum size
129136
new_size = _Py_TYPECACHE_MINSIZE;
130137
}
131138
else {
139+
// double the cache size when resizing
132140
new_size = old_size * 2;
133141
}
134-
struct type_cache *new_cache = allocate_cache(new_size);
142+
struct type_cache *new_cache = cache_allocate(new_size);
135143
if (new_cache == NULL) {
136144
return -1;
137145
}
138146
FT_ATOMIC_STORE_UINT_RELAXED(cache->version_tag, FT_ATOMIC_LOAD_UINT_RELAXED(type->tp_version_tag));
139147
for (uint32_t i = 0; i < old_size; i++) {
140148
if (cache->hashtable[i].name != NULL) {
141-
type_cache_insert(new_cache, cache->hashtable[i].name,
149+
cache_insert(new_cache, cache->hashtable[i].name,
142150
cache->hashtable[i].value);
143151
}
144152
}
145-
set_cache(type, new_cache);
146-
free_cache_delayed(cache);
153+
cache_set(type, new_cache);
154+
cache_free_delayed(cache);
147155
return 0;
148156
}
149157

150158
void _PyTypeCache_Insert(PyTypeObject *type, PyObject *name, PyObject *value)
151159
{
152-
struct type_cache *cache = get_cache(type);
160+
struct type_cache *cache = cache_get(type);
161+
// If the cache is full, resize it before inserting the new entry.
162+
// this also handles the case of empty cache where available is 0 but there are no entries.
153163
if (cache->available == 0) {
154-
if (type_cache_resize(type, cache) == -1) {
164+
if (cache_resize(type, cache) == -1) {
165+
// out of memory, don't cache the value
155166
return;
156167
}
157-
cache = get_cache(type);
168+
cache = cache_get(type);
158169
assert(cache->available > 0);
159170
}
160-
type_cache_insert(cache, name, value);
171+
cache_insert(cache, name, value);
161172
FT_ATOMIC_STORE_UINT_RELAXED(cache->version_tag, FT_ATOMIC_LOAD_UINT_RELAXED(type->tp_version_tag));
162173
}
163174

164175
struct _PyTypeCacheLookupResult _PyTypeCache_Lookup(PyTypeObject *type, PyObject *name)
165176
{
166177
assert(PyUnicode_CheckExact(name) && PyUnicode_CHECK_INTERNED(name));
167178
struct _PyTypeCacheLookupResult miss = {PyStackRef_NULL, 0, 0};
168-
struct type_cache *cache = get_cache(type);
179+
struct type_cache *cache = cache_get(type);
169180
if (cache == NULL) {
170181
return miss;
171182
}
@@ -202,7 +213,8 @@ struct _PyTypeCacheLookupResult _PyTypeCache_Lookup(PyTypeObject *type, PyObject
202213

203214

204215
void _PyTypeCache_Invalidate(PyTypeObject *type) {
205-
struct type_cache *cache = get_cache(type);
206-
set_cache(type, &empty_cache);
207-
free_cache_delayed(cache);
216+
struct type_cache *cache = cache_get(type);
217+
// if the type was modified, the cache is set to the empty cache and the old cache is freed after a delay.
218+
cache_set(type, &empty_cache);
219+
cache_free_delayed(cache);
208220
}

0 commit comments

Comments
 (0)