def _InitDBCursor(self): self._CloseDBCursor() db_path = os.path.join(self._db_dir, self._db_filenames['main']) db_just_created = not os.path.exists(db_path) self._db = sqlite3.connect(db_path, isolation_level=None, detect_types=sqlite3.PARSE_DECLTYPES) self._connection_timestamp = HydrusData.GetNow() self._c = self._db.cursor() self._c.execute('PRAGMA temp_store = 2;') self._c.execute('PRAGMA main.cache_size = -10000;') self._c.execute('ATTACH ":memory:" AS mem;') self._AttachExternalDatabases() db_names = [ name for (index, name, path) in self._c.execute('PRAGMA database_list;') if name not in ('mem', 'temp') ] for db_name in db_names: self._c.execute('PRAGMA ' + db_name + '.cache_size = -10000;') if self._no_wal: self._c.execute('PRAGMA ' + db_name + '.journal_mode = TRUNCATE;') self._c.execute('PRAGMA ' + db_name + '.synchronous = 2;') self._c.execute('SELECT * FROM ' + db_name + '.sqlite_master;').fetchone() else: self._c.execute('PRAGMA ' + db_name + '.journal_mode = WAL;') # if this is set to 1, transactions are not immediately synced to the journal and can be undone following a power-loss # if set to 2, all transactions are synced # either way, transactions are atomically consistent, but let's not mess around when power-cut during heavy file import or w/e self._c.execute('PRAGMA ' + db_name + '.synchronous = 2;') try: self._c.execute('SELECT * FROM ' + db_name + '.sqlite_master;').fetchone() except sqlite3.OperationalError: HydrusData.DebugPrint(traceback.format_exc()) def create_no_wal_file(): HG.controller.CreateNoWALFile() self._no_wal = True if db_just_created: del self._c del self._db os.remove(db_path) create_no_wal_file() self._InitDBCursor() else: self._c.execute('PRAGMA ' + db_name + '.journal_mode = TRUNCATE;') self._c.execute('PRAGMA ' + db_name + '.synchronous = 2;') self._c.execute('SELECT * FROM ' + db_name + '.sqlite_master;').fetchone() create_no_wal_file() try: self._BeginImmediate() except Exception as e: raise HydrusExceptions.DBAccessException(HydrusData.ToUnicode(e))
def __init__(self, controller, db_dir, db_name, no_wal=False): self._controller = controller self._db_dir = db_dir self._db_name = db_name self._no_wal = no_wal self._transaction_started = 0 self._in_transaction = False self._transaction_contains_writes = False self._connection_timestamp = 0 main_db_filename = db_name if not main_db_filename.endswith('.db'): main_db_filename += '.db' self._db_filenames = {} self._db_filenames['main'] = main_db_filename self._InitExternalDatabases() if distutils.version.LooseVersion( sqlite3.sqlite_version) < distutils.version.LooseVersion( '3.11.0'): self._fast_big_transaction_wal = False else: self._fast_big_transaction_wal = True self._is_first_start = False self._is_db_updated = False self._local_shutdown = False self._loop_finished = False self._ready_to_serve_requests = False self._could_not_initialise = False self._jobs = Queue.PriorityQueue() self._pubsubs = [] self._currently_doing_job = False self._current_status = '' self._current_job_name = '' self._db = None self._c = None if os.path.exists( os.path.join(self._db_dir, self._db_filenames['main'])): # open and close to clean up in case last session didn't close well self._InitDB() self._CloseDBCursor() self._InitDB() (version, ) = self._c.execute('SELECT version FROM version;').fetchone() if version < HC.SOFTWARE_VERSION - 50: raise Exception('Your current database version of hydrus ' + str(version) + ' is too old for this software version ' + str(HC.SOFTWARE_VERSION) + ' to update. Please try updating with version ' + str(version + 45) + ' or earlier first.') if version < 238: raise Exception( 'Unfortunately, this software cannot update your database. Please try installing version 238 first.' ) while version < HC.SOFTWARE_VERSION: time.sleep(self.UPDATE_WAIT) try: self._BeginImmediate() except Exception as e: raise HydrusExceptions.DBAccessException( HydrusData.ToUnicode(e)) try: self._UpdateDB(version) self._Commit() self._is_db_updated = True except: e = Exception('Updating the ' + self._db_name + ' db to version ' + str(version + 1) + ' caused this error:' + os.linesep + traceback.format_exc()) try: self._Rollback() except Exception as rollback_e: HydrusData.Print( 'When the update failed, attempting to rollback the database failed.' ) HydrusData.PrintException(rollback_e) raise e (version, ) = self._c.execute('SELECT version FROM version;').fetchone() self._RepairDB() self._CloseDBCursor() self._controller.CallToThreadLongRunning(self.MainLoop) while not self._ready_to_serve_requests: time.sleep(0.1) if self._could_not_initialise: raise Exception( 'Could not initialise the db! Error written to the log!')