Beispiel #1
0
    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))
Beispiel #2
0
    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!')