|
4 | 4 |
|
5 | 5 | import re |
6 | 6 | import shutil |
| 7 | +import sqlite3 |
7 | 8 | import sys |
8 | 9 | import time |
9 | 10 | import unicodedata |
10 | 11 | from collections.abc import Iterable, Iterator, Sequence |
| 12 | +from contextlib import closing |
11 | 13 | from dataclasses import dataclass |
12 | 14 | from datetime import UTC, datetime |
13 | 15 | from os import makedirs |
|
20 | 22 | URL, |
21 | 23 | ColumnExpressionArgument, |
22 | 24 | Engine, |
23 | | - NullPool, |
24 | 25 | ScalarResult, |
25 | 26 | Update, |
26 | 27 | and_, |
@@ -393,29 +394,21 @@ def open_library(self, library_dir: Path, in_memory: bool = False) -> OpenLibrar |
393 | 394 |
|
394 | 395 | @staticmethod |
395 | 396 | def __get_engine(library_dir: Path, in_memory: bool, sql_filename: str): |
| 397 | + db_path = library_dir / TS_FOLDER_NAME / sql_filename |
396 | 398 | connection_string = URL.create( |
397 | 399 | drivername="sqlite", |
398 | | - database=( |
399 | | - ":memory:" if in_memory else str(library_dir / TS_FOLDER_NAME / sql_filename) |
400 | | - ), |
| 400 | + database=":memory:" if in_memory else str(db_path), |
401 | 401 | ) |
402 | | - # NOTE: File-based databases should use NullPool to create new DB connection in order to |
403 | | - # keep connections on separate threads, which prevents the DB files from being locked |
404 | | - # even after a connection has been closed. |
405 | | - # SingletonThreadPool (the default for :memory:) should still be used for in-memory DBs. |
406 | | - # More info can be found on the SQLAlchemy docs: |
407 | | - # https://docs.sqlalchemy.org/en/20/changelog/migration_07.html |
408 | | - # Under -> sqlite-the-sqlite-dialect-now-uses-nullpool-for-file-based-databases |
409 | | - poolclass = None if in_memory else NullPool |
410 | 402 |
|
411 | | - logger.info( |
412 | | - "[Library] Creating SQLAlchemy Engine", |
413 | | - connection_string=connection_string, |
414 | | - poolclass=poolclass, |
415 | | - ) |
416 | | - return create_engine( |
417 | | - connection_string, poolclass=poolclass, connect_args={"autocommit": False} |
418 | | - ) |
| 403 | + if not in_memory: |
| 404 | + try: |
| 405 | + with closing(sqlite3.connect(db_path, autocommit=True)) as conn: |
| 406 | + conn.execute("PRAGMA journal_mode=WAL") |
| 407 | + except sqlite3.OperationalError as e: |
| 408 | + logger.warning("[Library] Could not set journal mode", error=e) |
| 409 | + |
| 410 | + logger.info("[Library] Creating SQLAlchemy Engine", connection_string=connection_string) |
| 411 | + return create_engine(connection_string, connect_args={"autocommit": False}) |
419 | 412 |
|
420 | 413 | def create_sqlite_library( |
421 | 414 | self, library_dir: Path, in_memory: bool, sql_filename: str = SQL_FILENAME |
@@ -1619,17 +1612,18 @@ def save_library_backup_to_disk(library_dir: Path) -> Path: |
1619 | 1612 | makedirs(str(library_dir / TS_FOLDER_NAME / BACKUP_FOLDER_NAME), exist_ok=True) |
1620 | 1613 |
|
1621 | 1614 | filename = f"ts_library_backup_{datetime.now(UTC).strftime('%Y_%m_%d_%H%M%S')}.sqlite" |
| 1615 | + library_backup_path = library_dir / TS_FOLDER_NAME / BACKUP_FOLDER_NAME / filename |
1622 | 1616 |
|
1623 | | - target_path = library_dir / TS_FOLDER_NAME / BACKUP_FOLDER_NAME / filename |
1624 | | - |
1625 | | - shutil.copyfile( |
1626 | | - library_dir / TS_FOLDER_NAME / SQL_FILENAME, |
1627 | | - target_path, |
1628 | | - ) |
| 1617 | + with ( |
| 1618 | + closing(sqlite3.connect(library_dir / TS_FOLDER_NAME / SQL_FILENAME)) as library, |
| 1619 | + closing(sqlite3.connect(library_backup_path)) as library_backup, |
| 1620 | + ): |
| 1621 | + library.backup(library_backup) |
| 1622 | + library_backup.execute("PRAGMA journal_mode=DELETE") # Don't use WAL for backups |
1629 | 1623 |
|
1630 | | - logger.info("Library backup saved to disk.", path=target_path) |
| 1624 | + logger.info("[Library] Library backup saved to disk", path=library_backup_path) |
1631 | 1625 |
|
1632 | | - return target_path |
| 1626 | + return library_backup_path |
1633 | 1627 |
|
1634 | 1628 | def get_tag(self, tag_id: int) -> Tag | None: |
1635 | 1629 | with Session(self.engine) as session: |
|
0 commit comments