|
2 | 2 | import sqlite3 |
3 | 3 | import time |
4 | 4 |
|
| 5 | +from filelock import FileLock |
| 6 | + |
5 | 7 | from app.config import settings |
6 | 8 |
|
7 | 9 |
|
@@ -74,53 +76,55 @@ def _iter_entries(): |
74 | 76 |
|
75 | 77 | def ensure_db() -> None: |
76 | 78 | os.makedirs(os.path.dirname(os.path.abspath(settings.sqlite_path)), exist_ok=True) |
77 | | - conn = sqlite3.connect(settings.sqlite_path) |
78 | | - try: |
79 | | - conn.execute("PRAGMA journal_mode=WAL") |
| 79 | + lock_path = settings.sqlite_path + ".lock" |
| 80 | + with FileLock(lock_path, timeout=60): |
| 81 | + conn = sqlite3.connect(settings.sqlite_path) |
80 | 82 | try: |
81 | | - sig = conn.execute( |
82 | | - "SELECT value FROM cache_metadata WHERE key = 'source_signature'" |
83 | | - ).fetchone() |
84 | | - count = conn.execute("SELECT COUNT(*) FROM dictionary").fetchone()[0] |
85 | | - if sig and sig[0] == _sql_signature() and count > 0: |
86 | | - return |
87 | | - except sqlite3.Error: |
88 | | - pass |
| 83 | + conn.execute("PRAGMA journal_mode=WAL") |
| 84 | + try: |
| 85 | + sig = conn.execute( |
| 86 | + "SELECT value FROM cache_metadata WHERE key = 'source_signature'" |
| 87 | + ).fetchone() |
| 88 | + count = conn.execute("SELECT COUNT(*) FROM dictionary").fetchone()[0] |
| 89 | + if sig and sig[0] == _sql_signature() and count > 0: |
| 90 | + return |
| 91 | + except sqlite3.Error: |
| 92 | + pass |
89 | 93 |
|
90 | | - conn.executescript(""" |
91 | | - DROP TABLE IF EXISTS dictionary; |
92 | | - DROP TABLE IF EXISTS cache_metadata; |
93 | | - DROP TABLE IF EXISTS ai_response_cache; |
94 | | - CREATE TABLE dictionary ( |
95 | | - id INTEGER PRIMARY KEY, |
96 | | - word TEXT, |
97 | | - definition TEXT |
98 | | - ); |
99 | | - CREATE TABLE cache_metadata ( |
100 | | - key TEXT PRIMARY KEY, |
101 | | - value TEXT NOT NULL |
102 | | - ); |
103 | | - CREATE TABLE ai_response_cache ( |
104 | | - cache_key TEXT PRIMARY KEY, |
105 | | - response_json TEXT NOT NULL, |
106 | | - created_at INTEGER NOT NULL |
107 | | - ); |
108 | | - """) |
109 | | - conn.executemany( |
110 | | - "INSERT INTO dictionary (id, word, definition) VALUES (?, ?, ?)", |
111 | | - _iter_entries(), |
112 | | - ) |
113 | | - conn.execute("CREATE INDEX idx_word ON dictionary(word)") |
114 | | - conn.execute("CREATE INDEX idx_def ON dictionary(definition)") |
115 | | - count = conn.execute("SELECT COUNT(*) FROM dictionary").fetchone()[0] |
116 | | - conn.executemany( |
117 | | - "INSERT INTO cache_metadata (key, value) VALUES (?, ?)", |
118 | | - { |
119 | | - "source_signature": _sql_signature(), |
120 | | - "row_count": str(count), |
121 | | - "rebuilt_at": str(int(time.time())), |
122 | | - }.items(), |
123 | | - ) |
124 | | - conn.commit() |
125 | | - finally: |
126 | | - conn.close() |
| 94 | + conn.executescript(""" |
| 95 | + DROP TABLE IF EXISTS dictionary; |
| 96 | + DROP TABLE IF EXISTS cache_metadata; |
| 97 | + DROP TABLE IF EXISTS ai_response_cache; |
| 98 | + CREATE TABLE dictionary ( |
| 99 | + id INTEGER PRIMARY KEY, |
| 100 | + word TEXT, |
| 101 | + definition TEXT |
| 102 | + ); |
| 103 | + CREATE TABLE cache_metadata ( |
| 104 | + key TEXT PRIMARY KEY, |
| 105 | + value TEXT NOT NULL |
| 106 | + ); |
| 107 | + CREATE TABLE ai_response_cache ( |
| 108 | + cache_key TEXT PRIMARY KEY, |
| 109 | + response_json TEXT NOT NULL, |
| 110 | + created_at INTEGER NOT NULL |
| 111 | + ); |
| 112 | + """) |
| 113 | + conn.executemany( |
| 114 | + "INSERT INTO dictionary (id, word, definition) VALUES (?, ?, ?)", |
| 115 | + _iter_entries(), |
| 116 | + ) |
| 117 | + conn.execute("CREATE INDEX idx_word ON dictionary(word)") |
| 118 | + conn.execute("CREATE INDEX idx_def ON dictionary(definition)") |
| 119 | + count = conn.execute("SELECT COUNT(*) FROM dictionary").fetchone()[0] |
| 120 | + conn.executemany( |
| 121 | + "INSERT INTO cache_metadata (key, value) VALUES (?, ?)", |
| 122 | + { |
| 123 | + "source_signature": _sql_signature(), |
| 124 | + "row_count": str(count), |
| 125 | + "rebuilt_at": str(int(time.time())), |
| 126 | + }.items(), |
| 127 | + ) |
| 128 | + conn.commit() |
| 129 | + finally: |
| 130 | + conn.close() |
0 commit comments