mirror of
https://github.com/Comfy-Org/ComfyUI.git
synced 2026-09-21 13:38:08 -05:00
fix(db): copy the legacy database inside the process lock
This commit is contained in:
+4
-7
@@ -115,8 +115,6 @@ def prepare_file_db_path(db_path):
|
||||
if db_dir:
|
||||
os.makedirs(db_dir, exist_ok=True)
|
||||
|
||||
copy_legacy_default_db(db_path)
|
||||
|
||||
|
||||
_db_lock = None
|
||||
|
||||
@@ -183,14 +181,13 @@ def _init_file_db(db_url):
|
||||
"""Initialize a file-backed SQLite database using Alembic migrations."""
|
||||
db_path = get_db_path()
|
||||
prepare_file_db_path(db_path)
|
||||
db_exists = os.path.exists(db_path)
|
||||
|
||||
# Lock BEFORE any migration work — deliberately diverging from upstream master, whose
|
||||
# "it would block Alembic" rationale is false (the lock guards a separate `<db>.lock`
|
||||
# file). Only this order makes revision inspection, backup, upgrade and the failure-path
|
||||
# restore mutually exclusive between processes.
|
||||
# The lock lives beside the database, so its parent directory must exist first.
|
||||
# All database reads and writes, including the legacy import, run under the lock.
|
||||
_acquire_file_lock(db_path)
|
||||
try:
|
||||
copy_legacy_default_db(db_path)
|
||||
db_exists = os.path.exists(db_path)
|
||||
_migrate_and_bind(db_url, db_path, db_exists)
|
||||
except Exception:
|
||||
_db_lock.release()
|
||||
|
||||
@@ -97,6 +97,43 @@ def test_held_lock_blocks_before_any_migration_work(stale_db):
|
||||
holder.release()
|
||||
|
||||
|
||||
def test_legacy_database_copy_runs_under_file_lock(tmp_path, monkeypatch):
|
||||
legacy_db = tmp_path / "legacy" / "comfyui.db"
|
||||
target_db = tmp_path / "current" / "comfyui.db"
|
||||
legacy_db.parent.mkdir()
|
||||
legacy_db.write_bytes(b"legacy database")
|
||||
copied: list[tuple[str, str]] = []
|
||||
real_copy = db_module.shutil.copy
|
||||
|
||||
def _copy_while_locked(source: str, destination: str):
|
||||
contender = FileLock(str(target_db) + ".lock")
|
||||
try:
|
||||
with pytest.raises(Timeout):
|
||||
contender.acquire(timeout=0)
|
||||
finally:
|
||||
if contender.is_locked:
|
||||
contender.release()
|
||||
copied.append((source, destination))
|
||||
return real_copy(source, destination)
|
||||
|
||||
monkeypatch.setattr(db_module.args, "database_url", None)
|
||||
monkeypatch.setattr(db_module, "get_db_path", lambda: str(target_db))
|
||||
monkeypatch.setattr(
|
||||
db_module, "get_legacy_default_db_path", lambda: str(legacy_db)
|
||||
)
|
||||
monkeypatch.setattr(db_module, "_migrate_and_bind", lambda *_args: None)
|
||||
monkeypatch.setattr(db_module.shutil, "copy", _copy_while_locked)
|
||||
monkeypatch.setattr(db_module, "_db_lock", None)
|
||||
|
||||
try:
|
||||
db_module._init_file_db(f"sqlite:///{target_db}")
|
||||
finally:
|
||||
if db_module._db_lock is not None:
|
||||
db_module._db_lock.release(force=True)
|
||||
|
||||
assert copied == [(str(legacy_db) + ".bak", str(target_db))]
|
||||
|
||||
|
||||
def test_setup_database_routes_file_lock_to_lock_guidance(monkeypatch, caplog):
|
||||
monkeypatch.setattr(main, "dependencies_available", lambda: True)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user