Skip to content

Commit 218f5a3

Browse files
authored
perf: drop unused ORDER BY in old-user-record pruning queries (#2302)
* rmv order_by in queries * convert to set so that positional order is not relevant * update to uid comparison so order no longer relevant
1 parent 0397f43 commit 218f5a3

3 files changed

Lines changed: 17 additions & 10 deletions

File tree

tools/tokenserver/database.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@
8686
""")
8787

8888

89+
# No ORDER BY: pruning is destructive and `purge_old_records.py` uses a random
90+
# offset for sharding, so stable pagination is not required. Avoiding the sort
91+
# lets this stop after LIMIT+OFFSET qualifying rows instead of
92+
# sorting the entire matching set.
8993
_GET_OLD_USER_RECORDS_FOR_SERVICE = sqltext("""\
9094
select
9195
uid, email, generation, keys_changed_at, client_state,
@@ -96,14 +100,14 @@
96100
users.service = :service
97101
and
98102
replaced_at is not null and replaced_at < :timestamp
99-
order by
100-
replaced_at desc, uid desc
101103
limit
102104
:limit
103105
offset
104106
:offset
105107
""")
106108

109+
# See note on _GET_OLD_USER_RECORDS_FOR_SERVICE for why this query intentionally
110+
# has no ORDER BY.
107111
_GET_OLD_USER_RECORDS_FOR_SERVICE_RANGE = """\
108112
select
109113
uid, email, generation, keys_changed_at, client_state,
@@ -116,8 +120,6 @@
116120
::RANGE::
117121
and
118122
replaced_at is not null and replaced_at < :timestamp
119-
order by
120-
replaced_at desc, uid desc
121123
limit
122124
:limit
123125
offset

tools/tokenserver/purge_old_records.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ def purge_old_records(
6464
logger.info("Purging old user records")
6565
try:
6666
database = Database()
67-
previous_list = []
67+
previous_uids = set()
6868
# Process batches of <max_per_loop> items, until we run out.
6969
while True:
7070
offset = random.randint(0, max_offset)
@@ -78,9 +78,10 @@ def purge_old_records(
7878
if not rows:
7979
logger.info("No more data")
8080
break
81-
if rows == previous_list:
81+
current_uids = {row.uid for row in rows}
82+
if current_uids == previous_uids:
8283
raise Exception("Loop detected")
83-
previous_list = rows
84+
previous_uids = current_uids
8485
range_msg = ""
8586
if uid_range:
8687
range_msg = (

tools/tokenserver/test_purge_old_records.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,11 @@ def test_purging_of_old_user_records(purge_db, mock_service_server):
135135
assert len(service_requests) == 2
136136

137137
# Check that the proper delete requests were made to the service.
138-
expected_kids = ["0000000000450-uw", "0000000000123-qg"]
139-
for i, environ in enumerate(service_requests):
138+
# Order is not asserted: the underlying query intentionally has no ORDER BY
139+
# (see _GET_OLD_USER_RECORDS_FOR_SERVICE), so kids are compared as a set.
140+
expected_kids = {"0000000000450-uw", "0000000000123-qg"}
141+
actual_kids = set()
142+
for environ in service_requests:
140143
# They must be to the correct path.
141144
assert environ["REQUEST_METHOD"] == "DELETE"
142145
assert re.match("/1.5/[0-9]+", environ["PATH_INFO"])
@@ -148,7 +151,8 @@ def test_purging_of_old_user_records(purge_db, mock_service_server):
148151
assert "uid" in userdata
149152
assert "node" in userdata
150153
assert userdata["fxa_uid"] == "test"
151-
assert userdata["fxa_kid"] == expected_kids[i]
154+
actual_kids.add(userdata["fxa_kid"])
155+
assert actual_kids == expected_kids
152156

153157
# Check that the user's current state is unaffected
154158
user = database.get_user(email)

0 commit comments

Comments
 (0)