#12953 closed defect (fixed)
Deadlock on MySQL when purging old anonymous sessions in Session.save()
Reported by: | Jun Omae | Owned by: | Jun Omae |
---|---|---|---|
Priority: | normal | Milestone: | 1.0.17 |
Component: | general | Version: | 1.0.15 |
Severity: | normal | Keywords: | mysql |
Cc: | Branch: | ||
Release Notes: |
Add |
||
API Changes: | |||
Internal Changes: |
Description
I've got deadlocks with MySQL under production environment.
Traceback (most recent call last): File "/venv/lib/python2.6/site-packages/trac/web/main.py", line 567, in _dispatch_request dispatcher.dispatch(req) File "/venv/lib/python2.6/site-packages/trac/web/main.py", line 270, in dispatch req.send(output, content_type or 'text/html') File "/venv/lib/python2.6/site-packages/trac/web/api.py", line 550, in send self.send_response(status) File "/venv/lib/python2.6/site-packages/trac/web/main.py", line 102, in send_response self.session.save() File "/venv/lib/python2.6/site-packages/trac/web/session.py", line 187, in save """, (mintime,)) File "/venv/lib/python2.6/site-packages/trac/db/util.py", line 128, in execute cursor.execute(query, params if params is not None else []) File "/venv/lib/python2.6/site-packages/trac/db/util.py", line 72, in execute return self.cursor.execute(sql_escape_percent(sql), args) File "/venv/lib/python2.6/site-packages/MySQLdb/cursors.py", line 205, in execute self.errorhandler(self, exc, value) File "/venv/lib/python2.6/site-packages/MySQLdb/connections.py", line 36, in defaulterrorhandler raise errorclass, errorvalue OperationalError: (1213, 'Deadlock found when trying to get lock; try restarting transaction')
Deleting old anonymous sessions between 2 transactions in the same time leads the deadlock.
*** (1) TRANSACTION: TRANSACTION 0 813950056, ACTIVE 0 sec, process no 9791, OS thread id 139812286813952 starting index read mysql tables in use 2, locked 2 LOCK WAIT 6 lock struct(s), heap size 1216, 4 row lock(s), undo log entries 3 MySQL thread id 15761050, query id 1582491217 10.0.1.30 tracuser updating DELETE FROM session_attribute WHERE authenticated=0 AND sid IN ( SELECT sid FROM session WHERE authenticated=0 AND last_visit < 1502759550 ) *** (2) TRANSACTION: TRANSACTION 0 813950055, ACTIVE 0 sec, process no 9791, OS thread id 139812289476352 fetching rows, thread declared inside InnoDB 80 mysql tables in use 2, locked 2 50 lock struct(s), heap size 6752, 3474 row lock(s), undo log entries 3 MySQL thread id 15761048, query id 1582491213 10.0.1.30 tracuser updating DELETE FROM session_attribute WHERE authenticated=0 AND sid IN ( SELECT sid FROM session WHERE authenticated=0 AND last_visit < 1502759550 )
The delete query is full scan on session_attribute table.
mysql> EXPLAIN DELETE FROM session_attribute -> WHERE authenticated=0 AND sid IN ( -> SELECT sid FROM session -> WHERE authenticated=0 -> AND last_visit < 1502759550); +----+--------------------+-------------------+-----------------+----------------------------------------------------------+---------+---------+------------+--------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+--------------------+-------------------+-----------------+----------------------------------------------------------+---------+---------+------------+--------+-------------+ | 1 | PRIMARY | session_attribute | ALL | NULL | NULL | NULL | NULL | 232569 | Using where | | 2 | DEPENDENT SUBQUERY | session | unique_subquery | PRIMARY,session_last_visit_idx,session_authenticated_idx | PRIMARY | 506 | func,const | 1 | Using where | +----+--------------------+-------------------+-----------------+----------------------------------------------------------+---------+---------+------------+--------+-------------+ 2 rows in set (0.00 sec)
Attachments (0)
Change History (6)
comment:1 by , 7 years ago
comment:2 by , 7 years ago
Looks reasonable to me.
It looks like PURGE_AGE
is also used for the cookie lifetime. The PURGE_AGE comment could be revised after your change: Purge session Expire cookie after 90 days.
comment:3 by , 7 years ago
Milestone: | next-stable-1.2.x → 1.0.17 |
---|---|
Owner: | set to |
Status: | new → assigned |
Thanks for the reviewing.
Proposed changes with suggestions and unit tests in [524dadd9a/jomae.git] (jomae.git@t12953). Also, I'd like to push the changes to 1.0-stable. I need the option for 1.0-stable on my production environment.
comment:5 by , 7 years ago
Release Notes: | modified (diff) |
---|---|
Resolution: | → fixed |
Status: | assigned → closed |
Thanks for the reviewing. Committed in [16415] and merged in [16416-16417].
comment:6 by , 5 years ago
Workaround is to create an index on session_attribute (authenticated)
.
CREATE INDEX idx_session_attribute_authenticated ON session_attribute (authenticated)
I consider that we shouldn't automatically purge expired anonymous sessions in web request for public Trac site which many users access because the delete query is full scan, long and possibly concurrent.
How about adding option to configure lifetime of the anonymous session (0 to disable the purging)?
trac/env.py
trac/web/session.py