diff --git a/src/calibre/gui2/ui.py b/src/calibre/gui2/ui.py index 88a8c68572..6b04f6fa1f 100644 --- a/src/calibre/gui2/ui.py +++ b/src/calibre/gui2/ui.py @@ -533,6 +533,7 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, # {{{ # Save the current field_metadata for applications like calibre2opds # Goes here, because if cf is valid, db is valid. db.prefs['field_metadata'] = db.field_metadata.all_metadata() + db.commit_dirty_cache() if DEBUG and db.gm_count > 0: print 'get_metadata cache: {0:d} calls, {1:4.2f}% misses'.format( db.gm_count, (db.gm_missed*100.0)/db.gm_count) diff --git a/src/calibre/library/database2.py b/src/calibre/library/database2.py index 4775e13818..c4d2666dd1 100644 --- a/src/calibre/library/database2.py +++ b/src/calibre/library/database2.py @@ -340,6 +340,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): setattr(self, 'title_sort', functools.partial(self.get_property, loc=self.FIELD_MAP['sort'])) + self.dirtied_cache = set() d = self.conn.get('SELECT book FROM metadata_dirtied', all=True) for x in d: self.dirtied_queue.put(x[0]) @@ -585,12 +586,20 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): if remove_from_dirtied: self.conn.execute('DELETE FROM metadata_dirtied WHERE book=?', (book_id,)) + # if a later exception prevents the commit, then the dirtied + # table will still have the book. No big deal, because the OPF + # is there and correct. We will simply do it again on next + # start + self.dirtied_cache.discard(book_id) if commit: self.conn.commit() return True def dirtied(self, book_ids, commit=True): for book in book_ids: + if book in self.dirtied_cache: + print 'in dirty cache', book + continue try: self.conn.execute( 'INSERT INTO metadata_dirtied (book) VALUES (?)', @@ -598,10 +607,30 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): self.dirtied_queue.put(book) except IntegrityError: # Already in table - continue + pass + # If the commit doesn't happen, then our cache will be wrong. This + # could lead to a problem because we won't put the book back into + # the dirtied table. We deal with this by writing the dirty cache + # back to the table on GUI exit. Not perfect, but probably OK + self.dirtied_cache.add(book) + print 'added book', book if commit: self.conn.commit() + def commit_dirty_cache(self): + ''' + Set the dirty indication for every book in the cache. The vast majority + of the time, the indication will already be set. However, sometimes + exceptions may have prevented a commit, which may remove some dirty + indications from the DB. This call will put them back. Note that there + is no problem with setting a dirty indication for a book that isn't in + fact dirty. Just wastes a few cycles. + ''' + print 'commit cache' + book_ids = list(self.dirtied_cache) + self.dirtied_cache = set() + self.dirtied(book_ids) + def get_metadata(self, idx, index_is_id=False, get_cover=False): ''' Convenience method to return metadata as a :class:`Metadata` object.