[Checkins] SVN: relstorage/trunk/ When deleting transactions, do so in batches of 1000 and release the lock in-between.
Martijn Pieters
mj at zopatista.com
Mon May 23 15:50:05 EDT 2011
Log message for revision 121783:
When deleting transactions, do so in batches of 1000 and release the lock in-between.
This way we don't hold on to the commit lock for any longer than we have to and do not block normal operations of the Zope RelStorage cluster.
Changed:
U relstorage/trunk/CHANGES.txt
U relstorage/trunk/relstorage/adapters/packundo.py
-=-
Modified: relstorage/trunk/CHANGES.txt
===================================================================
--- relstorage/trunk/CHANGES.txt 2011-05-23 13:37:32 UTC (rev 121782)
+++ relstorage/trunk/CHANGES.txt 2011-05-23 19:50:03 UTC (rev 121783)
@@ -4,6 +4,10 @@
- Fixed another minor compatibility issue with PostgreSQL 9.0. Packing
raised an error when the client used old an version of libpq.
+- Delete empty transactions in batches of 1000 rows instead of all in one
+ go, to prevent holding the transaction lock for longer than absolutely
+ necessary.
+
1.5.0b2 (2011-03-02)
--------------------
Modified: relstorage/trunk/relstorage/adapters/packundo.py
===================================================================
--- relstorage/trunk/relstorage/adapters/packundo.py 2011-05-23 13:37:32 UTC (rev 121782)
+++ relstorage/trunk/relstorage/adapters/packundo.py 2011-05-23 19:50:03 UTC (rev 121783)
@@ -223,6 +223,18 @@
)
"""
+ # See http://www.postgres.cz/index.php/PostgreSQL_SQL_Tricks#Fast_first_n_rows_removing
+ # for = any(array(...)) rationale.
+ _script_delete_empty_transactions_batch = """
+ DELETE FROM transaction
+ WHERE tid = any(array(
+ SELECT tid FROM transaction
+ WHERE packed = %(TRUE)s
+ AND empty = %(TRUE)s
+ LIMIT 1000
+ ))
+ """
+
def verify_undoable(self, cursor, undo_tid):
"""Raise UndoError if it is not safe to undo the specified txn."""
stmt = """
@@ -690,7 +702,7 @@
packed_func(oid, tid)
packed_list = None
- self._pack_cleanup(conn, cursor)
+ self._pack_cleanup(conn, cursor, sleep)
except:
log.exception("pack: failed")
@@ -760,7 +772,7 @@
tid, state, removed_objects, removed_states)
- def _pack_cleanup(self, conn, cursor):
+ def _pack_cleanup(self, conn, cursor, sleep=None):
"""Remove unneeded table rows after packing"""
# commit the work done so far
conn.commit()
@@ -774,19 +786,20 @@
self.runner.run_script(cursor, stmt)
# We need a commit lock when touching the transaction table though.
- self.locker.hold_commit_lock(cursor)
+ # We'll do it in batches of 1000 rows.
log.debug("pack: removing empty packed transactions")
- stmt = """
- DELETE FROM transaction
- WHERE packed = %(TRUE)s
- AND empty = %(TRUE)s
- """
- self.runner.run_script_stmt(cursor, stmt)
+ while True:
+ self._pause_pack_until_lock(cursor, sleep)
+ stmt = self._script_delete_empty_transactions_batch
+ self.runner.run_script_stmt(cursor, stmt)
+ deleted = cursor.rowcount
+ conn.commit()
+ self.locker.release_commit_lock(cursor)
+ if deleted < 1000:
+ # Last set of deletions complete
+ break
# perform cleanup that does not require the commit lock
- conn.commit()
- self.locker.release_commit_lock(cursor)
-
log.debug("pack: clearing temporary pack state")
for _table in ('pack_object', 'pack_state', 'pack_state_tid'):
stmt = '%(TRUNCATE)s ' + _table
@@ -842,7 +855,14 @@
CREATE UNIQUE INDEX temp_undo_zoid ON temp_undo (zoid)
"""
+ _script_delete_empty_transactions_batch = """
+ DELETE FROM transaction
+ WHERE packed = %(TRUE)s
+ AND empty = %(TRUE)s
+ LIMIT 1000
+ """
+
class OracleHistoryPreservingPackUndo(HistoryPreservingPackUndo):
_script_choose_pack_transaction = """
@@ -868,7 +888,14 @@
WHERE tid = %(tid)s
"""
+ _script_delete_empty_transactions_batch = """
+ DELETE FROM transaction
+ WHERE packed = %(TRUE)s
+ AND empty = %(TRUE)s
+ AND rownum <= 1000
+ """
+
class HistoryFreePackUndo(PackUndo):
implements(IPackUndo)
More information about the checkins
mailing list