Hodfa71 commited on
Commit
2a51199
·
verified ·
1 Parent(s): 872f495

Fix: db_sync.py - smart restore + WAL-aware backup

Browse files
Files changed (1) hide show
  1. db_sync.py +29 -6
db_sync.py CHANGED
@@ -10,7 +10,9 @@ Usage:
10
 
11
  import os
12
  import shutil
 
13
  import sys
 
14
  import time
15
 
16
  HF_TOKEN = os.environ.get("HF_TOKEN", "")
@@ -27,6 +29,13 @@ def _api():
27
  return HfApi(token=HF_TOKEN)
28
 
29
 
 
 
 
 
 
 
 
30
  def restore():
31
  """Download DB from HF backup repo if it exists. Returns True if restored."""
32
  try:
@@ -59,26 +68,40 @@ def restore():
59
 
60
 
61
  def backup():
62
- """Upload current DB to HF backup repo."""
63
  if not os.path.exists(DB_PATH):
64
  print(f"[db_sync] No DB at {DB_PATH} — skipping backup.", flush=True)
65
  return False
 
66
  try:
67
  api = _api()
68
- size = os.path.getsize(DB_PATH)
69
- print(f"[db_sync] Backing up DB ({size:,} bytes) {BACKUP_REPO}...", flush=True)
 
 
 
 
 
 
 
70
  api.upload_file(
71
- path_or_fileobj=DB_PATH,
72
  path_in_repo=REMOTE_FILE,
73
  repo_id=BACKUP_REPO,
74
  repo_type="dataset",
75
- commit_message="Auto-backup from HF Space",
76
  )
77
- print(f"[db_sync] Backup complete.", flush=True)
78
  return True
79
  except Exception as e:
80
  print(f"[db_sync] Backup failed: {e}", flush=True)
81
  return False
 
 
 
 
 
 
82
 
83
 
84
  def watch():
 
10
 
11
  import os
12
  import shutil
13
+ import sqlite3
14
  import sys
15
+ import tempfile
16
  import time
17
 
18
  HF_TOKEN = os.environ.get("HF_TOKEN", "")
 
29
  return HfApi(token=HF_TOKEN)
30
 
31
 
32
+ def _safe_copy(src, dst):
33
+ """Copy a SQLite DB using the backup API so WAL data is included."""
34
+ with sqlite3.connect(src) as src_conn:
35
+ with sqlite3.connect(dst) as dst_conn:
36
+ src_conn.backup(dst_conn)
37
+
38
+
39
  def restore():
40
  """Download DB from HF backup repo if it exists. Returns True if restored."""
41
  try:
 
68
 
69
 
70
  def backup():
71
+ """Upload current DB to HF backup repo using SQLite backup API (handles WAL)."""
72
  if not os.path.exists(DB_PATH):
73
  print(f"[db_sync] No DB at {DB_PATH} — skipping backup.", flush=True)
74
  return False
75
+ tmp = None
76
  try:
77
  api = _api()
78
+ # Use SQLite backup API to create a consistent snapshot that includes WAL data.
79
+ # Uploading the raw .sqlite3 file misses uncommitted WAL transactions.
80
+ tmp = DB_PATH + ".upload_tmp"
81
+ _safe_copy(DB_PATH, tmp)
82
+ size = os.path.getsize(tmp)
83
+ # Verify the copy has data
84
+ with sqlite3.connect(tmp) as check:
85
+ n = check.execute("SELECT COUNT(*) FROM htx_user").fetchone()[0]
86
+ print(f"[db_sync] Backing up DB ({size:,} bytes, {n} users) → {BACKUP_REPO}...", flush=True)
87
  api.upload_file(
88
+ path_or_fileobj=tmp,
89
  path_in_repo=REMOTE_FILE,
90
  repo_id=BACKUP_REPO,
91
  repo_type="dataset",
92
+ commit_message=f"Auto-backup from HF Space ({n} users)",
93
  )
94
+ print(f"[db_sync] Backup complete ({n} users).", flush=True)
95
  return True
96
  except Exception as e:
97
  print(f"[db_sync] Backup failed: {e}", flush=True)
98
  return False
99
+ finally:
100
+ if tmp and os.path.exists(tmp):
101
+ try:
102
+ os.unlink(tmp)
103
+ except Exception:
104
+ pass
105
 
106
 
107
  def watch():