| 177 | |
| 178 | |
| 179 | class SqliteMetadataStore(MetadataStore): |
| 180 | def __init__( |
| 181 | self, cache_dir_prefix: str, set_journal_mode: bool = False, num_shards: int = 1 |
| 182 | ) -> None: |
| 183 | # We check startswith instead of equality because the version |
| 184 | # will have already been appended by the time the cache dir is |
| 185 | # passed here. |
| 186 | self.dbs: list[sqlite3.Connection] = [] |
| 187 | self.num_shards = num_shards |
| 188 | self.dirty_shards: set[int] = set() |
| 189 | if cache_dir_prefix.startswith(os.devnull): |
| 190 | return |
| 191 | |
| 192 | os.makedirs(cache_dir_prefix, exist_ok=True) |
| 193 | if num_shards <= 1: |
| 194 | self.dbs.append( |
| 195 | connect_db(os_path_join(cache_dir_prefix, "cache.db"), set_journal_mode) |
| 196 | ) |
| 197 | else: |
| 198 | for i in range(num_shards): |
| 199 | self.dbs.append( |
| 200 | connect_db(os_path_join(cache_dir_prefix, f"cache.{i}.db"), set_journal_mode) |
| 201 | ) |
| 202 | |
| 203 | def _shard_index(self, name: str) -> int: |
| 204 | if self.num_shards <= 1: |
| 205 | return 0 |
| 206 | return hash_path_stem(name) % self.num_shards |
| 207 | |
| 208 | def _db_for(self, name: str) -> sqlite3.Connection: |
| 209 | if not self.dbs: |
| 210 | raise FileNotFoundError() |
| 211 | return self.dbs[self._shard_index(name)] |
| 212 | |
| 213 | def _query(self, name: str, field: str) -> Any: |
| 214 | # Raises FileNotFound for consistency with the file system version |
| 215 | db = self._db_for(name) |
| 216 | cur = db.execute(f"SELECT {field} FROM files2 WHERE path = ?", (name,)) |
| 217 | results = cur.fetchall() |
| 218 | if not results: |
| 219 | raise FileNotFoundError() |
| 220 | assert len(results) == 1 |
| 221 | return results[0][0] |
| 222 | |
| 223 | def getmtime(self, name: str) -> float: |
| 224 | mtime = self._query(name, "mtime") |
| 225 | assert isinstance(mtime, float) |
| 226 | return mtime |
| 227 | |
| 228 | def read(self, name: str) -> bytes: |
| 229 | data = self._query(name, "data") |
| 230 | assert isinstance(data, bytes) |
| 231 | return data |
| 232 | |
| 233 | def write(self, name: str, data: bytes, mtime: float | None = None) -> bool: |
| 234 | import sqlite3 |
| 235 | |
| 236 | if not self.dbs: |
no outgoing calls
searching dependent graphs…