8000 Merge branch 'gh-112075-lock-split-keys' into nogil-integration · python/cpython@a825875 · GitHub
[go: up one dir, main page]

Skip to content

Commit a825875

Browse files
committed
Merge branch 'gh-112075-lock-split-keys' into nogil-integration
2 parents 74eec36 + 2e5797e commit a825875

File tree

1 file changed

+104
-124
lines changed

1 file changed

+104
-124
lines changed

Objects/dictobject.c

Lines changed: 104 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -1606,31 +1606,6 @@ insertion_resize(PyInterpreterState *interp, PyDictObject *mp, int unicode)
16061606
return dictresize(interp, mp, calculate_log2_keysize(GROWTH_RATE(mp)), unicode);
16071607
}
16081608

1609-
static Py_ssize_t
1610-
insert_into_splitdictkeys(PyDictKeysObject *keys, PyObject *name, Py_hash_t hash)
1611-
{
1612-
assert(PyUnicode_CheckExact(name));
1613-
ASSERT_KEYS_LOCKED(keys);
1614-
1615-
Py_ssize_t ix = unicodekeys_lookup_unicode(keys, name, hash);
1616-
if (ix == DKIX_EMPTY) {
1617-
if (keys->dk_usable <= 0) {
1618-
return DKIX_EMPTY;
1619-
}
1620-
/* Insert into new slot. */
1621-
keys->dk_version = 0;
1622-
Py_ssize_t hashpos = find_empty_slot(keys, hash);
1623-
ix = keys->dk_nentries;
1624-
PyDictUnicodeEntry *ep = &DK_UNICODE_ENTRIES(keys)[ix];
1625-
dictkeys_set_index(keys, hashpos, ix);
1626-
assert(ep->me_key == NULL);
1627-
ep->me_key = Py_NewRef(name);
1628-
split_keys_entry_added(keys);
1629-
}
1630-
assert (ix < SHARED_KEYS_MAX_SIZE);
1631-
return ix;
1632-
}
1633-
16341609
static inline int
16351610
insert_combined_dict(PyInterpreterState *interp, PyDictObject *mp,
16361611
Py_hash_t hash, PyObject *key, PyObject *value)
@@ -1664,39 +1639,56 @@ insert_combined_dict(PyInterpreterState *interp, PyDictObject *mp,
16641639
return 0;
16651640
}
16661641

1667-
static int
1668-
insert_split_dict(PyInterpreterState *interp, PyDictObject *mp,
1669-
Py_hash_t hash, PyObject *key, PyObject *value)
1642+
static Py_ssize_t
1643+
insert_split_key(PyDictKeysObject *keys, PyObject *key, Py_hash_t hash)
16701644
{
1671-
PyDictKeysObject *keys = mp->ma_keys;
1672-
LOCK_KEYS(keys);
1673-
if (keys->dk_usable <= 0) {
1674-
/* Need to resize. */
1675-
UNLOCK_KEYS(keys);
1676-
int ins = insertion_resize(interp, mp, 1);
1677-
if (ins < 0) {
1678-
return -1;
1679-
}
1680-
assert(!_PyDict_HasSplitTable(mp));
1681-
return insert_combined_dict(interp, mp, hash, key, value);
1682-
}
1683-
1684-
Py_ssize_t hashpos = find_empty_slot(keys, hash);
1685-
dictkeys_set_index(keys, hashpos, keys->dk_nentries);
1686-
1687-
PyDictUnicodeEntry *ep;
1688-
ep = &DK_UNICODE_ENTRIES(keys)[keys->dk_nentries];
1689-
STORE_SHARED_KEY(ep->me_key, key);
1645+
assert(PyUnicode_CheckExact(key));
1646+
Py_ssize_t ix;
16901647

1691-
Py_ssize_t index = keys->dk_nentries;
1692-
_PyDictValues_AddToInsertionOrder(mp->ma_values, index);
1693-
assert (mp->ma_values->values[index] == NULL);
1694-
STORE_SPLIT_VALUE(mp, index, value);
1648+
#ifdef Py_GIL_DISABLED
1649+
ix = unicodekeys_lookup_unicode_threadsafe(keys, key, hash);
1650+
if (ix >= 0) {
1651+
return ix;
1652+
}
1653+
#endif
16951654

1696-
split_keys_entry_added(keys);
1697-
assert(keys->dk_usable >= 0);
1655+
LOCK_KEYS(keys);
1656+
ix = unicodekeys_lookup_unicode(keys, key, hash);
1657+
if (ix == DKIX_EMPTY && keys->dk_usable > 0) {
1658+
// Insert into new slot
1659+
keys->dk_version = 0;
1660+
Py_ssize_t hashpos = find_empty_slot(keys, hash);
1661+
ix = keys->dk_nentries;
1662+
dictkeys_set_index(keys, hashpos, ix);
1663+
PyDictUnicodeEntry *ep = &DK_UNICODE_ENTRIES(keys)[ix];
1664+
STORE_SHARED_KEY(ep->me_key, Py_NewRef(key));
1665+
split_keys_entry_added(keys);
1666+
}
1667+
assert (ix < SHARED_KEYS_MAX_SIZE);
16981668
UNLOCK_KEYS(keys);
1699-
return 0;
1669+
return ix;
1670+
}
1671+
1672+
static void
1673+
insert_split_value(PyInterpreterState *interp, PyDictObject *mp, PyObject *key, PyObject *value, Py_ssize_t ix)
1674+
{
1675+
assert(PyUnicode_CheckExact(key));
1676+
MAINTAIN_TRACKING(mp, key, value);
1677+
PyObject *old_value = mp->ma_values->values[ix];
1678+
if (old_value == NULL) {
1679+
uint64_t new_version = _PyDict_NotifyEvent(interp, PyDict_EVENT_ADDED, mp, key, value);
1680+
STORE_SPLIT_VALUE(mp, ix, Py_NewRef(value));
1681+
_PyDictValues_AddToInsertionOrder(mp->ma_values, ix);
1682+
mp->ma_used++;
1683+
mp->ma_version_tag = new_version;
1684+
}
1685+
else {
1686+
uint64_t new_version = _PyDict_NotifyEvent(interp, PyDict_EVENT_MODIFIED, mp, key, value);
1687+
STORE_SPLIT_VALUE(mp, ix, Py_NewRef(value));
1688+
mp->ma_version_tag = new_version;
1689+
Py_DECREF(old_value);
1690+
}
1691+
ASSERT_CONSISTENT(mp);
17001692
}
17011693

17021694
/*
@@ -1719,6 +1711,21 @@ insertdict(PyInterpreterState *interp, PyDictObject *mp,
17191711
assert(mp->ma_keys->dk_kind == DICT_KEYS_GENERAL);
17201712
}
17211713

1714+
if (mp->ma_keys->dk_kind == DICT_KEYS_SPLIT) {
1715+
Py_ssize_t ix = insert_split_key(mp->ma_keys, key, hash);
1716+
if (ix != DKIX_EMPTY) {
1717+
insert_split_value(interp, mp, key, value, ix);
1718+
Py_DECREF(key);
1719+
Py_DECREF(value);
1720+
return 0;
1721+
}
1722+
1723+
/* No space in shared keys. Resize and continue below. */
1724+
if (insertion_resize(interp, mp, 1) < 0) {
1725+
goto Fail;
1726+
}
1727+
}
1728+
17221729
Py_ssize_t ix = _Py_dict_lookup(mp, key, hash, &old_value);
17231730
if (ix == DKIX_ERROR)
17241731
goto Fail;
@@ -1731,17 +1738,9 @@ insertdict(PyInterpreterState *interp, PyDictObject *mp,
17311738
/* Insert into new slot. */
17321739
mp->ma_keys->dk_version = 0;
17331740
assert(old_value == NULL);
1734-
1735-
if (!_PyDict_HasSplitTable(mp)) {
1736-
if (insert_combined_dict(interp, mp, hash, key, value) < 0) {
1737-
goto Fail;
1738-
}
1739-
}
1740-
else {
1741-
if (insert_split_dict(interp, mp, hash, key, value) < 0)
1742-
goto Fail;
1741+
if (insert_combined_dict(interp, mp, hash, key, value) < 0) {
1742+
goto Fail;
17431743
}
1744-
17451744
mp->ma_used++;
17461745
mp->ma_version_tag = new_version;
17471746
ASSERT_CONSISTENT(mp);
@@ -1751,21 +1750,12 @@ insertdict(PyInterpreterState *interp, PyDictObject *mp,
17511750
if (old_value != value) {
17521751
uint64_t new_version = _PyDict_NotifyEvent(
17531752
interp, PyDict_EVENT_MODIFIED, mp, key, value);
1754-
if (_PyDict_HasSplitTable(mp)) {
1755-
STORE_SPLIT_VALUE(mp, ix, value);
1756-
if (old_value == NULL) {
1757-
_PyDictValues_AddToInsertionOrder(mp->ma_values, ix);
1758-
mp->ma_used++;
1759-
}
1753+
assert(old_value != NULL);
1754+
if (DK_IS_UNICODE(mp->ma_keys)) {
1755+
DK_UNICODE_ENTRIES(mp->ma_keys)[ix].me_value = value;
17601756
}
17611757
else {
1762-
assert(old_value != NULL);
1763-
if (DK_IS_UNICODE(mp->ma_keys)) {
1764-
DK_UNICODE_ENTRIES(mp->ma_keys)[ix].me_value = value;
1765-
}
1766-
else {
1767-
DK_ENTRIES(mp->ma_keys)[ix].me_value = value;
1768-
}
1758+
DK_ENTRIES(mp->ma_keys)[ix].me_value = value;
17691759
}
17701760
mp->ma_version_tag = new_version;
17711761
}
@@ -4174,6 +4164,29 @@ dict_setdefault_ref_lock_held(PyObject *d, PyObject *key, PyObject *default_valu
41744164
}
41754165
}
41764166

4167+
if (mp->ma_keys->dk_kind == DICT_KEYS_SPLIT) {
4168+
Py_ssize_t ix = insert_split_key(mp->ma_keys, key, hash);
4169+
if (ix != DKIX_EMPTY) {
4170+
PyObject *value = mp->ma_values->values[ix];
4171+
int already_present = value != NULL;
4172+
if (!already_present) {
4173+
insert_split_value(interp, mp, key, default_value, ix);
4174+
value = default_value;
4175+
}
4176+
if (result) {
4177+
*result = incref_result ? Py_NewRef(value) : value;
4178+
}
4179+
return already_present;
4180+
}
4181+
4182+
/* No space in shared keys. Resize and continue below. */
4183+
if (insertion_resize(interp, mp, 1) < 0) {
4184+
goto error;
4185+
}
4186+
}
4187+
4188+
assert(!_PyDict_HasSplitTable(mp));
4189+
41774190
Py_ssize_t ix = _Py_dict_lookup(mp, key, hash, &value);
41784191
if (ix == DKIX_ERROR) {
41794192
if (result) {
@@ -4188,25 +4201,13 @@ dict_setdefault_ref_lock_held(PyObject *d, PyObject *key, PyObject *default_valu
41884201
mp->ma_keys->dk_version = 0;
41894202
value = default_value;
41904203

4191-
if (!_PyDict_HasSplitTable(mp)) {
4192-
if (insert_combined_dict(interp, mp, hash, Py_NewRef(key), Py_NewRef(value)) < 0) {
4193-
Py_DECREF(key);
4194-
Py_DECREF(value);
4195-
if (result) {
4196-
*result = NULL;
4197-
}
4198-
return -1;
4199-
}
4200-
}
4201-
else {
4202-
if (insert_split_dict(interp, mp, hash, Py_NewRef(key), Py_NewRef(value)) < 0) {
4203-
Py_DECREF(key);
4204-
Py_DECREF(value);
4205-
if (result) {
4206-
*result = NULL;
4207-
}
4208-
return -1;
4204+
if (insert_combined_dict(interp, mp, hash, Py_NewRef(key), Py_NewRef(value)) < 0) {
4205+
Py_DECREF(key);
4206+
Py_DECREF(value);
4207+
if (result) {
4208+
*result = NULL;
42094209
}
4210+
return -1;
42104211
}
42114212

42124213
MAINTAIN_TRACKING(mp, key, value);
@@ -4219,29 +4220,19 @@ dict_setdefault_ref_lock_held(PyObject *d, PyObject *key, PyObject *default_valu
42194220
}
42204221
return 0;
42214222
}
4222-
else if (value == NULL) {
4223-
uint64_t new_version = _PyDict_NotifyEvent(
4224-
interp, PyDict_EVENT_ADDED, mp, key, default_value);
4225-
value = default_value;
4226-
assert(_PyDict_HasSplitTable(mp));
4227-
assert(mp->ma_values->values[ix] == NULL);
4228-
MAINTAIN_TRACKING(mp, key, value);
4229-
STORE_SPLIT_VALUE(mp, ix, Py_NewRef(value));
4230-
_PyDictValues_AddToInsertionOrder(mp->ma_values, ix);
4231-
mp->ma_used++;
4232-
mp->ma_version_tag = new_version;
4233-
ASSERT_CONSISTENT(mp);
4234-
if (result) {
4235-
*result = incref_result ? Py_NewRef(value) : value;
4236-
}
4237-
return 0;
4238-
}
42394223

4224+
assert(value != NULL);
42404225
ASSERT_CONSISTENT(mp);
42414226
if (result) {
42424227
*result = incref_result ? Py_NewRef(value) : value;
42434228
}
42444229
return 1;
4230+
4231+
error:
4232+
if (result) {
4233+
*result = NULL;
4234+
}
4235+
return -1;
42454236
}
42464237

42474238
int
@@ -6696,18 +6687,7 @@ store_instance_attr_lock_held(PyObject *obj, PyDictValues *values,
66966687
assert(hash != -1);
66976688
}
66986689

6699-
#ifdef Py_GIL_DISABLED
6700-
// Try a thread-safe lookup to see if the index is already allocated
6701-
ix = unicodekeys_lookup_unicode_threadsafe(keys, name, hash);
6702-
if (ix == DKIX_EMPTY || ix == DKIX_KEY_CHANGED) {
6703-
// Lock keys and do insert
6704-
LOCK_KEYS(keys);
6705-
ix = insert_into_splitdictkeys(keys, name, hash);
6706-
UNLOCK_KEYS(keys);
6707-
}
6708-
#else
6709-
ix = insert_into_splitdictkeys(keys, name, hash);
6710-
#endif
6690+
ix = insert_split_key(keys, name, hash);
67116691

67126692
#ifdef Py_STATS
67136693
if (ix == DKIX_EMPTY) {

0 commit comments

Comments
 (0)
0