Skip to content

Commit 5aa91c5

Browse files
authored
gh-124296: Remove private dictionary version tag (PEP 699) (#124472)
1 parent 60ff67d commit 5aa91c5

File tree

13 files changed

+35
-354
lines changed

13 files changed

+35
-354
lines changed

Include/cpython/dictobject.h

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,11 @@ typedef struct {
1414
/* Number of items in the dictionary */
1515
Py_ssize_t ma_used;
1616

17-
/* Dictionary version: globally unique, value change each time
18-
the dictionary is modified */
19-
#ifdef Py_BUILD_CORE
20-
/* Bits 0-7 are for dict watchers.
17+
/* This is a private field for CPython's internal use.
18+
* Bits 0-7 are for dict watchers.
2119
* Bits 8-11 are for the watched mutation counter (used by tier2 optimization)
22-
* The remaining bits (12-63) are the actual version tag. */
23-
uint64_t ma_version_tag;
24-
#else
25-
Py_DEPRECATED(3.12) uint64_t ma_version_tag;
26-
#endif
20+
* The remaining bits are not currently used. */
21+
uint64_t _ma_watcher_tag;
2722

2823
PyDictKeysObject *ma_keys;
2924

Include/internal/pycore_dict.h

Lines changed: 2 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -230,31 +230,6 @@ static inline PyDictUnicodeEntry* DK_UNICODE_ENTRIES(PyDictKeysObject *dk) {
230230
#define DICT_WATCHER_MASK ((1 << DICT_MAX_WATCHERS) - 1)
231231
#define DICT_WATCHER_AND_MODIFICATION_MASK ((1 << (DICT_MAX_WATCHERS + DICT_WATCHED_MUTATION_BITS)) - 1)
232232

233-
#ifdef Py_GIL_DISABLED
234-
235-
#define THREAD_LOCAL_DICT_VERSION_COUNT 256
236-
#define THREAD_LOCAL_DICT_VERSION_BATCH THREAD_LOCAL_DICT_VERSION_COUNT * DICT_VERSION_INCREMENT
237-
238-
static inline uint64_t
239-
dict_next_version(PyInterpreterState *interp)
240-
{
241-
PyThreadState *tstate = PyThreadState_GET();
242-
uint64_t cur_progress = (tstate->dict_global_version &
243-
(THREAD_LOCAL_DICT_VERSION_BATCH - 1));
244-
if (cur_progress == 0) {
245-
uint64_t next = _Py_atomic_add_uint64(&interp->dict_state.global_version,
246-
THREAD_LOCAL_DICT_VERSION_BATCH);
247-
tstate->dict_global_version = next;
248-
}
249-
return tstate->dict_global_version += DICT_VERSION_INCREMENT;
250-
}
251-
252-
#define DICT_NEXT_VERSION(INTERP) dict_next_version(INTERP)
253-
254-
#else
255-
#define DICT_NEXT_VERSION(INTERP) \
256-
((INTERP)->dict_state.global_version += DICT_VERSION_INCREMENT)
257-
#endif
258233

259234
PyAPI_FUNC(void)
260235
_PyDict_SendEvent(int watcher_bits,
@@ -263,20 +238,19 @@ _PyDict_SendEvent(int watcher_bits,
263238
PyObject *key,
264239
PyObject *value);
265240

266-
static inline uint64_t
241+
static inline void
267242
_PyDict_NotifyEvent(PyInterpreterState *interp,
268243
PyDict_WatchEvent event,
269244
PyDictObject *mp,
270245
PyObject *key,
271246
PyObject *value)
272247
{
273248
assert(Py_REFCNT((PyObject*)mp) > 0);
274-
int watcher_bits = mp->ma_version_tag & DICT_WATCHER_MASK;
249+
int watcher_bits = mp->_ma_watcher_tag & DICT_WATCHER_MASK;
275250
if (watcher_bits) {
276251
RARE_EVENT_STAT_INC(watched_dict_modification);
277252
_PyDict_SendEvent(watcher_bits, event, mp, key, value);
278253
}
279-
return DICT_NEXT_VERSION(interp) | (mp->ma_version_tag & DICT_WATCHER_AND_MODIFICATION_MASK);
280254
}
281255

282256
extern PyDictObject *_PyObject_MaterializeManagedDict(PyObject *obj);

Include/internal/pycore_dict_state.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,6 @@ extern "C" {
1212
#define DICT_WATCHED_MUTATION_BITS 4
1313

1414
struct _Py_dict_state {
15-
/*Global counter used to set ma_version_tag field of dictionary.
16-
* It is incremented each time that a dictionary is created and each
17-
* time that a dictionary is modified. */
18-
uint64_t global_version;
1915
uint32_t next_keys_version;
2016
PyDict_WatchCallback watchers[DICT_MAX_WATCHERS];
2117
};

Lib/test/test_dict_version.py

Lines changed: 0 additions & 191 deletions
This file was deleted.

Lib/test/test_free_threading/test_dict.py

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -142,41 +142,6 @@ def writer_func(l):
142142
for ref in thread_list:
143143
self.assertIsNone(ref())
144144

145-
@unittest.skipIf(_testcapi is None, 'need _testcapi module')
146-
def test_dict_version(self):
147-
dict_version = _testcapi.dict_version
148-
THREAD_COUNT = 10
149-
DICT_COUNT = 10000
150-
lists = []
151-
writers = []
152-
153-
def writer_func(thread_list):
154-
for i in range(DICT_COUNT):
155-
thread_list.append(dict_version({}))
156-
157-
for x in range(THREAD_COUNT):
158-
thread_list = []
159-
lists.append(thread_list)
160-
writer = Thread(target=partial(writer_func, thread_list))
161-
writers.append(writer)
162-
163-
for writer in writers:
164-
writer.start()
165-
166-
for writer in writers:
167-
writer.join()
168-
169-
total_len = 0
170-
values = set()
171-
for thread_list in lists:
172-
for v in thread_list:
173-
if v in values:
174-
print('dup', v, (v/4096)%256)
175-
values.add(v)
176-
total_len += len(thread_list)
177-
versions = set(dict_version for thread_list in lists for dict_version in thread_list)
178-
self.assertEqual(len(versions), THREAD_COUNT*DICT_COUNT)
179-
180145

181146
if __name__ == "__main__":
182147
unittest.main()
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
:c:type:`PyDictObject` no longer maintains a private version tag field
2+
``ma_version_tag`` per :pep:`699`. This field was originally added in
3+
Python 3.6 (:pep:`509`) and deprecated in Python 3.12.

Modules/_testcapi/dict.c

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -181,19 +181,6 @@ dict_popstring_null(PyObject *self, PyObject *args)
181181
RETURN_INT(PyDict_PopString(dict, key, NULL));
182182
}
183183

184-
static PyObject *
185-
dict_version(PyObject *self, PyObject *dict)
186-
{
187-
if (!PyDict_Check(dict)) {
188-
PyErr_SetString(PyExc_TypeError, "expected dict");
189-
return NULL;
190-
}
191-
_Py_COMP_DIAG_PUSH
192-
_Py_COMP_DIAG_IGNORE_DEPR_DECLS
193-
return PyLong_FromUnsignedLongLong(((PyDictObject *)dict)->ma_version_tag);
194-
_Py_COMP_DIAG_POP
195-
}
196-
197184
static PyMethodDef test_methods[] = {
198185
{"dict_containsstring", dict_containsstring, METH_VARARGS},
199186
{"dict_getitemref", dict_getitemref, METH_VARARGS},
@@ -204,7 +191,6 @@ static PyMethodDef test_methods[] = {
204191
{"dict_pop_null", dict_pop_null, METH_VARARGS},
205192
{"dict_popstring", dict_popstring, METH_VARARGS},
206193
{"dict_popstring_null", dict_popstring_null, METH_VARARGS},
207-
{"dict_version", dict_version, METH_O},
208194
{NULL},
209195
};
210196

Modules/_testcapimodule.c

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1909,25 +1909,6 @@ getitem_with_error(PyObject *self, PyObject *args)
19091909
return PyObject_GetItem(map, key);
19101910
}
19111911

1912-
static PyObject *
1913-
dict_get_version(PyObject *self, PyObject *args)
1914-
{
1915-
PyDictObject *dict;
1916-
uint64_t version;
1917-
1918-
if (!PyArg_ParseTuple(args, "O!", &PyDict_Type, &dict))
1919-
return NULL;
1920-
1921-
_Py_COMP_DIAG_PUSH
1922-
_Py_COMP_DIAG_IGNORE_DEPR_DECLS
1923-
version = dict->ma_version_tag;
1924-
_Py_COMP_DIAG_POP
1925-
1926-
static_assert(sizeof(unsigned long long) >= sizeof(version),
1927-
"version is larger than unsigned long long");
1928-
return PyLong_FromUnsignedLongLong((unsigned long long)version);
1929-
}
1930-
19311912

19321913
static PyObject *
19331914
raise_SIGINT_then_send_None(PyObject *self, PyObject *args)
@@ -3407,7 +3388,6 @@ static PyMethodDef TestMethods[] = {
34073388
{"return_result_with_error", return_result_with_error, METH_NOARGS},
34083389
{"getitem_with_error", getitem_with_error, METH_VARARGS},
34093390
{"Py_CompileString", pycompilestring, METH_O},
3410-
{"dict_get_version", dict_get_version, METH_VARARGS},
34113391
{"raise_SIGINT_then_send_None", raise_SIGINT_then_send_None, METH_VARARGS},
34123392
{"stack_pointer", stack_pointer, METH_NOARGS},
34133393
#ifdef W_STOPCODE

0 commit comments

Comments
 (0)