|  | """ | 
|  | This is a database cache. Its a kind of proxy object for Python sqlite3 connection | 
|  | which operates on a memory copy of the database. | 
|  |  | 
|  | Upon object creation the database is "backed up" to memory. All subsequent | 
|  | operations are then pefromed on this copy which yields in performance increase. | 
|  | """ | 
|  | import sqlite3 | 
|  | from lib.progressbar_utils import ProgressBar | 
|  |  | 
|  | # ============================================================================= | 
|  |  | 
|  |  | 
|  | class DatabaseCache(object): | 
|  | def __init__(self, file_name, read_only=False): | 
|  |  | 
|  | self.file_name = file_name | 
|  | self.read_only = read_only | 
|  | self.bar = None | 
|  |  | 
|  | def __enter__(self): | 
|  | """ | 
|  | Opens the database file and makes its copy in memory | 
|  | """ | 
|  |  | 
|  | # File URI | 
|  | if self.read_only: | 
|  | uri = "file:%s?mode=ro" % self.file_name | 
|  | else: | 
|  | uri = "file:%s?mode=rwc" % self.file_name | 
|  |  | 
|  | # Open connections | 
|  | self.memory_connection = sqlite3.connect(":memory:") | 
|  | self.file_connection = sqlite3.connect(uri, uri=True) | 
|  |  | 
|  | # Load the database | 
|  | print("Loading database from '{}'".format(self.file_name)) | 
|  | self.file_connection.backup( | 
|  | self.memory_connection, pages=100, progress=self._progress | 
|  | ) | 
|  |  | 
|  | self.bar.finish() | 
|  | self.bar = None | 
|  |  | 
|  | # Return the connection | 
|  | return self.memory_connection | 
|  |  | 
|  | def __exit__(self, exc_type, exc_value, traceback): | 
|  | """ | 
|  | Writes back the database to file if the database was open as not read-only | 
|  | """ | 
|  |  | 
|  | # Write back only if not read-only | 
|  | if not self.read_only: | 
|  | if self.memory_connection.in_transaction: | 
|  | assert exc_type is not None, "Outstanding transaction, but no exception?" | 
|  | self.memory_connection.rollback() | 
|  |  | 
|  | print("Dumping database to '{}'".format(self.file_name)) | 
|  | self.memory_connection.backup( | 
|  | self.file_connection, pages=100, progress=self._progress | 
|  | ) | 
|  |  | 
|  | self.bar.finish() | 
|  | self.bar = None | 
|  |  | 
|  | # Close connections | 
|  | self.memory_connection.close() | 
|  | self.file_connection.close() | 
|  |  | 
|  | def _progress(self, status, remaining, total): | 
|  | """ | 
|  | Prints database copy progress. | 
|  | """ | 
|  | if self.bar is None: | 
|  | self.bar = ProgressBar(max_value=total) | 
|  | else: | 
|  | self.bar.update(total - remaining) |