Skip to content

Commit a1e73cf

Browse files
authored
Merge pull request #95 from jagerman/query-optimizations
Query optimizations
2 parents 16ff18c + e5b9ce1 commit a1e73cf

18 files changed

+322
-73
lines changed

contrib/upgrade-tests/common.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,4 +101,7 @@ do_upgrades() {
101101
# This should exit cleanly to indicate no needed migrations (if it doesn't, i.e. we still
102102
# require migrations after doing a migration then Something Getting Wrong in migrations).
103103
python3 -msogs --check-upgrades
104+
105+
# Run the cleanup job to make sure we have the proper rooms.active_users values
106+
python3 -c 'from sogs.cleanup import cleanup; cleanup()'
104107
}

contrib/upgrade-tests/v0.1.10-expected.txt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
rooms:
2-
+----+------------+-------------------+-------------+-------+--------------+------------------+------+------------+-------+--------+
3-
| id | token | name | description | image | info_updates | message_sequence | read | accessible | write | upload |
4-
+----+------------+-------------------+-------------+-------+--------------+------------------+------+------------+-------+--------+
5-
| 1 | round-room | A spherical room! | NULL | NULL | 1 | 0 | 1 | 1 | 1 | 1 |
6-
| 2 | sudoku | Sudoku lovers | NULL | 3 | 2 | 1 | 1 | 1 | 1 | 1 |
7-
+----+------------+-------------------+-------------+-------+--------------+------------------+------+------------+-------+--------+
2+
+----+------------+-------------------+-------------+-------+--------------+--------------+------------------+------+------------+-------+--------+
3+
| id | token | name | description | image | active_users | info_updates | message_sequence | read | accessible | write | upload |
4+
+----+------------+-------------------+-------------+-------+--------------+--------------+------------------+------+------------+-------+--------+
5+
| 1 | round-room | A spherical room! | NULL | NULL | 0 | 1 | 0 | 1 | 1 | 1 | 1 |
6+
| 2 | sudoku | Sudoku lovers | NULL | 3 | 0 | 2 | 1 | 1 | 1 | 1 | 1 |
7+
+----+------------+-------------------+-------------+-------+--------------+--------------+------------------+------+------------+-------+--------+
88

99
room_import_hacks:
1010
+------+-------------------+--------------------+

contrib/upgrade-tests/v0.2.0-expected.txt

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
rooms:
2-
+----+------------+--------------+----------------------------------------------------------------+-------+--------------+------------------+------+------------+-------+--------+
3-
| id | token | name | description | image | info_updates | message_sequence | read | accessible | write | upload |
4-
+----+------------+--------------+----------------------------------------------------------------+-------+--------------+------------------+------+------------+-------+--------+
5-
| 1 | gibberish | Gibberish 🥄 | Delivering your daily dose of gibberish. | 3 | 3 | 7 | 1 | 1 | 1 | 1 |
6-
| 2 | sudoku | Sudoku | Delivering your daily dose of gib... sudoku. | 1 | 3 | 5 | 1 | 1 | 1 | 1 |
7-
| 3 | cool-room | Private room | If you're reading these posts then you're too cool for school. | NULL | 1 | 4 | 0 | 1 | 0 | 0 |
8-
| 4 | empty-room | Empty | We don't go there anymore. | NULL | 1 | 0 | 1 | 1 | 1 | 1 |
9-
+----+------------+--------------+----------------------------------------------------------------+-------+--------------+------------------+------+------------+-------+--------+
2+
+----+------------+--------------+----------------------------------------------------------------+-------+--------------+--------------+------------------+------+------------+-------+--------+
3+
| id | token | name | description | image | active_users | info_updates | message_sequence | read | accessible | write | upload |
4+
+----+------------+--------------+----------------------------------------------------------------+-------+--------------+--------------+------------------+------+------------+-------+--------+
5+
| 1 | gibberish | Gibberish 🥄 | Delivering your daily dose of gibberish. | 3 | 0 | 3 | 7 | 1 | 1 | 1 | 1 |
6+
| 2 | sudoku | Sudoku | Delivering your daily dose of gib... sudoku. | 1 | 0 | 3 | 5 | 1 | 1 | 1 | 1 |
7+
| 3 | cool-room | Private room | If you're reading these posts then you're too cool for school. | NULL | 0 | 1 | 4 | 0 | 1 | 0 | 0 |
8+
| 4 | empty-room | Empty | We don't go there anymore. | NULL | 0 | 1 | 0 | 1 | 1 | 1 | 1 |
9+
+----+------------+--------------+----------------------------------------------------------------+-------+--------------+--------------+------------------+------+------------+-------+--------+
1010

1111
room_import_hacks:
1212
message_metadata:

contrib/upgrade-tests/v0.3.0-pg-expected.txt

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
rooms:
2-
+----+------------+--------------+----------------------------------------------------------------+-------+--------------+------------------+------+------------+-------+--------+
3-
| id | token | name | description | image | info_updates | message_sequence | read | accessible | write | upload |
4-
+----+------------+--------------+----------------------------------------------------------------+-------+--------------+------------------+------+------------+-------+--------+
5-
| 1 | gibberish | Gibberish 🥄 | Delivering your daily dose of gibberish. | 2 | 3 | 10 | 1 | 1 | 1 | 1 |
6-
| 2 | sudoku | Sudoku | Delivering your daily dose of gib... sudoku. | 1 | 2 | 4 | 1 | 1 | 1 | 1 |
7-
| 3 | cool-room | Private room | If you're reading these posts then you're too cool for school. | NULL | 1 | 4 | 1 | 1 | 1 | 1 |
8-
| 4 | empty-room | Empty | We don't go there anymore. | NULL | 1 | 0 | 1 | 1 | 1 | 1 |
9-
+----+------------+--------------+----------------------------------------------------------------+-------+--------------+------------------+------+------------+-------+--------+
2+
+----+------------+--------------+----------------------------------------------------------------+-------+--------------+--------------+------------------+------+------------+-------+--------+
3+
| id | token | name | description | image | active_users | info_updates | message_sequence | read | accessible | write | upload |
4+
+----+------------+--------------+----------------------------------------------------------------+-------+--------------+--------------+------------------+------+------------+-------+--------+
5+
| 1 | gibberish | Gibberish 🥄 | Delivering your daily dose of gibberish. | 2 | 0 | 3 | 10 | 1 | 1 | 1 | 1 |
6+
| 2 | sudoku | Sudoku | Delivering your daily dose of gib... sudoku. | 1 | 0 | 2 | 4 | 1 | 1 | 1 | 1 |
7+
| 3 | cool-room | Private room | If you're reading these posts then you're too cool for school. | NULL | 0 | 1 | 4 | 1 | 1 | 1 | 1 |
8+
| 4 | empty-room | Empty | We don't go there anymore. | NULL | 0 | 1 | 0 | 1 | 1 | 1 | 1 |
9+
+----+------------+--------------+----------------------------------------------------------------+-------+--------------+--------------+------------------+------+------------+-------+--------+
1010

1111
room_import_hacks:
1212
message_metadata:

sogs/__main__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ def print_room(room: Room):
169169
msgs_size /= 1_000_000
170170
files_size /= 1_000_000
171171

172-
active = [room.active_users(x * 86400) for x in (7, 14, 30)]
172+
active = [room.active_users_last(x * 86400) for x in (7, 14, 30)]
173173
m, a, hm, ha = room.get_all_moderators()
174174
admins = len(a) + len(ha)
175175
mods = len(m) + len(hm)

sogs/cleanup.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,15 @@ def prune_room_activity():
8484

8585
if count > 0:
8686
app.logger.info("Prune {} old room activity records".format(count))
87+
88+
query(
89+
"""
90+
UPDATE rooms SET active_users = (
91+
SELECT COUNT(*) FROM room_users WHERE room = rooms.id AND last_active >= :since)
92+
""",
93+
since=time.time() - config.ROOM_DEFAULT_ACTIVE_THRESHOLD,
94+
)
95+
8796
return count
8897

8998

sogs/migrations/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
new_columns,
1212
new_tables,
1313
room_accessible,
14+
room_moderators,
1415
seqno_etc,
1516
user_permissions,
1617
user_perm_futures,
@@ -42,6 +43,7 @@ def migrate(conn, *, check_only=False):
4243
message_views,
4344
user_perm_futures,
4445
room_accessible,
46+
room_moderators,
4547
user_permissions,
4648
file_message,
4749
import_hacks,

sogs/migrations/new_columns.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ def migrate(conn, *, check_only):
1515
'whisper': 'INTEGER REFERENCES users(id)',
1616
'whisper_mods': 'BOOLEAN NOT NULL DEFAULT FALSE',
1717
'filtered': 'BOOLEAN NOT NULL DEFAULT FALSE',
18-
}
18+
},
19+
'rooms': {'active_users': 'BIGINT NOT NULL DEFAULT 0'},
1920
}
2021

2122
added = False

sogs/migrations/room_moderators.py

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import logging
2+
from .exc import DatabaseUpgradeRequired
3+
4+
5+
def migrate(conn, *, check_only):
6+
"""
7+
Adds the room_moderators view, along with a couple other optimizations that came at the same
8+
time:
9+
- we drop the user_permissions view (to be recreated in the user_permissions migration code)
10+
- we drop the user_permission_overrides_public_mods index and recreate a tighter index
11+
"""
12+
13+
from .. import db
14+
15+
if 'room_moderators' in db.metadata.tables:
16+
return False
17+
18+
logging.warning("DB migration: create room_moderators view")
19+
if check_only:
20+
raise DatabaseUpgradeRequired("Create room_moderators view")
21+
22+
if db.engine.name == "sqlite":
23+
conn.execute(
24+
"""
25+
CREATE VIEW room_moderators AS
26+
SELECT session_id, mods.* FROM (
27+
SELECT
28+
room,
29+
"user",
30+
MAX(visible_mod) & 1 AS visible_mod,
31+
MAX(admin) AS admin,
32+
MAX(room_moderator) AS room_moderator,
33+
MAX(global_moderator) AS global_moderator
34+
FROM (
35+
SELECT
36+
room,
37+
"user",
38+
CASE WHEN visible_mod THEN 3 ELSE 2 END AS visible_mod,
39+
admin,
40+
TRUE AS room_moderator,
41+
FALSE AS global_moderator
42+
FROM user_permission_overrides WHERE moderator
43+
44+
UNION ALL
45+
46+
SELECT
47+
rooms.id AS room,
48+
users.id as "user",
49+
CASE WHEN visible_mod THEN 1 ELSE 0 END AS visible_mod,
50+
admin,
51+
FALSE as room_moderator,
52+
TRUE as global_moderator
53+
FROM users CROSS JOIN rooms WHERE moderator
54+
) m GROUP BY "user", room
55+
) mods JOIN users on "user" = users.id
56+
"""
57+
)
58+
else: # postgres
59+
conn.execute(
60+
"""
61+
CREATE VIEW room_moderators AS
62+
SELECT session_id, mods.* FROM (
63+
SELECT
64+
room,
65+
"user",
66+
CAST(MAX(visible_mod) & 1 AS BOOLEAN) AS visible_mod,
67+
bool_or(admin) AS admin,
68+
bool_or(room_moderator) AS room_moderator,
69+
bool_or(global_moderator) AS global_moderator
70+
FROM (
71+
SELECT
72+
room,
73+
"user",
74+
CASE WHEN visible_mod THEN 3 ELSE 2 END AS visible_mod,
75+
admin,
76+
TRUE AS room_moderator,
77+
FALSE AS global_moderator
78+
FROM user_permission_overrides WHERE moderator
79+
80+
UNION ALL
81+
82+
SELECT
83+
rooms.id AS room,
84+
users.id as "user",
85+
CASE WHEN visible_mod THEN 1 ELSE 0 END AS visible_mod,
86+
admin,
87+
FALSE as room_moderator,
88+
TRUE as global_moderator
89+
FROM users CROSS JOIN rooms WHERE moderator
90+
) m GROUP BY "user", room
91+
) mods JOIN users on "user" = users.id
92+
"""
93+
)
94+
95+
conn.execute("DROP VIEW IF EXISTS user_permissions")
96+
conn.execute("DROP INDEX IF EXISTS user_permission_overrides_public_mods")
97+
conn.execute(
98+
"CREATE INDEX IF NOT EXISTS user_permission_overrides_mods "
99+
"ON user_permission_overrides(room) WHERE moderator"
100+
)
101+
102+
return True

sogs/migrations/user_permissions.py

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,12 @@ def migrate(conn, *, check_only):
1717
if check_only:
1818
raise DatabaseUpgradeRequired("Recreate user_permissions view")
1919

20-
sqlite = db.engine.name == "sqlite"
2120
conn.execute(
22-
f"""
21+
"""
2322
CREATE VIEW user_permissions AS
2423
SELECT
2524
rooms.id AS room,
26-
users.id AS {'user' if sqlite else '"user"'},
25+
users.id AS "user",
2726
users.session_id,
2827
CASE WHEN users.banned THEN TRUE ELSE COALESCE(user_permission_overrides.banned, FALSE) END AS banned,
2928
CASE WHEN users.moderator THEN TRUE ELSE COALESCE(user_permission_overrides.read, rooms.read) END AS read,
@@ -33,19 +32,19 @@ def migrate(conn, *, check_only):
3332
CASE WHEN users.moderator THEN TRUE ELSE COALESCE(user_permission_overrides.moderator, FALSE) END AS moderator,
3433
CASE WHEN users.admin THEN TRUE ELSE COALESCE(user_permission_overrides.admin, FALSE) END AS admin,
3534
-- room_moderator will be TRUE if the user is specifically listed as a moderator of the room
36-
COALESCE(user_permission_overrides.moderator OR user_permission_overrides.admin, FALSE) AS room_moderator,
35+
COALESCE(user_permission_overrides.moderator, FALSE) AS room_moderator,
3736
-- global_moderator will be TRUE if the user is a global moderator/admin (note that this is
3837
-- *not* exclusive of room_moderator: a moderator/admin could be listed in both).
39-
COALESCE(users.moderator OR users.admin, FALSE) as global_moderator,
38+
users.moderator as global_moderator,
4039
-- visible_mod will be TRUE if this mod is a publicly viewable moderator of the room
4140
CASE
42-
WHEN user_permission_overrides.moderator OR user_permission_overrides.admin THEN user_permission_overrides.visible_mod
43-
WHEN users.moderator OR users.admin THEN users.visible_mod
41+
WHEN user_permission_overrides.moderator THEN user_permission_overrides.visible_mod
42+
WHEN users.moderator THEN users.visible_mod
4443
ELSE FALSE
4544
END AS visible_mod
4645
FROM
47-
users {'JOIN' if sqlite else 'CROSS JOIN'} rooms LEFT OUTER JOIN user_permission_overrides ON
48-
(users.id = user_permission_overrides.{'user' if sqlite else '"user"'} AND rooms.id = user_permission_overrides.room)
46+
users CROSS JOIN rooms LEFT OUTER JOIN user_permission_overrides ON
47+
(users.id = user_permission_overrides."user" AND rooms.id = user_permission_overrides.room)
4948
""" # noqa E501
5049
)
5150

0 commit comments

Comments
 (0)