| 103 | |
| 104 | |
| 105 | class SQLiteCacheBackend(AbstractCacheBackend): |
| 106 | __slots__ = ("connection", "cursor", "database", "lock", "zstd_enabled") |
| 107 | |
| 108 | def __init__(self, database: str, zstd_enabled: bool = False): |
| 109 | self.database = database |
| 110 | self.connection = None |
| 111 | self.cursor = None |
| 112 | self.lock = threading.Lock() |
| 113 | self.zstd_enabled = zstd_enabled |
| 114 | self.connect() |
| 115 | |
| 116 | def connect(self): |
| 117 | self.connection = sqlite3.connect(self.database, timeout=10.0) |
| 118 | self.connection.enable_load_extension(True) |
| 119 | self.connection.execute("PRAGMA foreign_keys = ON;") |
| 120 | self.connection.execute("PRAGMA journal_mode=WAL;") |
| 121 | self.connection.execute("PRAGMA auto_vacuum=full;") |
| 122 | self.cursor = self.connection.cursor() |
| 123 | |
| 124 | if self.zstd_enabled: |
| 125 | if sqlite_zstd is None: |
| 126 | raise ValueError("sqlite_zstd library not found.") |
| 127 | |
| 128 | sqlite_zstd.load(self.connection) |
| 129 | self.enable_zstd() |
| 130 | |
| 131 | def ensure_connection(self): |
| 132 | if self.connection is None or self.cursor is None: |
| 133 | self.connect() |
| 134 | |
| 135 | def all(self): |
| 136 | self.ensure_connection() |
| 137 | with self.connection: |
| 138 | return self.cursor.execute("SELECT * FROM cache").fetchall() |
| 139 | |
| 140 | def all_length(self) -> int: |
| 141 | self.ensure_connection() |
| 142 | with self.connection: |
| 143 | return self.cursor.execute("SELECT COUNT(*) FROM cache").fetchone()[0] |
| 144 | |
| 145 | def random(self, size: int) -> list[CacheResponse]: |
| 146 | self.ensure_connection() |
| 147 | with self.connection: |
| 148 | self.cursor.execute( |
| 149 | "SELECT key, value FROM cache ORDER BY RANDOM() LIMIT ?", (size,) |
| 150 | ) |
| 151 | return [CacheResponse(key, value) for key, value in self.cursor] |
| 152 | |
| 153 | def enable_zstd(self): |
| 154 | self.ensure_connection() |
| 155 | with self.connection: |
| 156 | try: |
| 157 | self.cursor.execute( |
| 158 | 'SELECT zstd_enable_transparent(\'{"table": "cache", "column": "value", "compression_level": 9, "dict_chooser": "\'\'a\'\'"}\')' |
| 159 | ) |
| 160 | except Exception as error: |
| 161 | logger.error(f"Error enabling ZSTD compression: {error}") |
| 162 | logger.exception(error) |
no outgoing calls