From 71e499bb7864acf9ca381a02ed923aa9535d62bb Mon Sep 17 00:00:00 2001 From: mvdbeek Date: Tue, 5 Nov 2024 11:34:42 +0100 Subject: [PATCH] Optimize/fix sqlite hid update statement `./run_tests.sh --skip-common-startup -api lib/galaxy_test/api -- -s -k cache` would fail on sqlite with database locked. Not using a separate connection means that we expire loaded attributes in the sqlite case, but I don't think we need to be concerned about performance if you're using sqlite. --- lib/galaxy/model/__init__.py | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/lib/galaxy/model/__init__.py b/lib/galaxy/model/__init__.py index 582da171d315..12d2a554512d 100644 --- a/lib/galaxy/model/__init__.py +++ b/lib/galaxy/model/__init__.py @@ -91,7 +91,10 @@ update, VARCHAR, ) -from sqlalchemy.exc import OperationalError +from sqlalchemy.exc import ( + CompileError, + OperationalError, +) from sqlalchemy.ext import hybrid from sqlalchemy.ext.associationproxy import association_proxy from sqlalchemy.ext.orderinglist import ordering_list @@ -3120,16 +3123,21 @@ def _next_hid(self, n=1): table = self.__table__ history_id = cached_id(self) update_stmt = update(table).where(table.c.id == history_id).values(hid_counter=table.c.hid_counter + n) + update_returning_stmnt = update_stmt.returning(table.c.hid_counter) - with engine.begin() as conn: - if engine.name in ["postgres", "postgresql"]: - stmt = update_stmt.returning(table.c.hid_counter) - updated_hid = conn.execute(stmt).scalar() - hid = updated_hid - n - else: - select_stmt = select(table.c.hid_counter).where(table.c.id == history_id).with_for_update() - hid = conn.execute(select_stmt).scalar() - conn.execute(update_stmt) + if engine.name != "sqlite": + with engine.begin() as conn: + hid = conn.execute(update_returning_stmnt).scalar() - n + else: + try: + hid = session.execute(update_returning_stmnt).scalar() - n + except (CompileError, OperationalError): + # The RETURNING clause was added to SQLite in version 3.35.0. + # Not using FOR UPDATE either, since that was added in 3.45.0, + # and anyway does a whole-table lock + select_stmt = select(table.c.hid_counter).where(table.c.id == history_id) + hid = session.execute(select_stmt).scalar() + session.execute(update_stmt) session.expire(self, ["hid_counter"]) return hid