From 88627828b7d932e7f7d480220a57fad574f8aa6a Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 13 Sep 2011 20:07:44 -0600 Subject: [PATCH] Fix a memory leak in the Copy to library operation --- src/calibre/gui2/actions/copy_to_library.py | 4 ++- src/calibre/library/database2.py | 6 ++-- src/calibre/utils/search_query_parser.py | 40 ++++++++++++++------- 3 files changed, 34 insertions(+), 16 deletions(-) diff --git a/src/calibre/gui2/actions/copy_to_library.py b/src/calibre/gui2/actions/copy_to_library.py index ff95ca06a5..fdcce87342 100644 --- a/src/calibre/gui2/actions/copy_to_library.py +++ b/src/calibre/gui2/actions/copy_to_library.py @@ -53,9 +53,11 @@ class Worker(Thread): # {{{ def doit(self): from calibre.library.database2 import LibraryDatabase2 - newdb = LibraryDatabase2(self.loc) + newdb = LibraryDatabase2(self.loc, is_second_db=True) with closing(newdb): self._doit(newdb) + newdb.break_cycles() + del newdb def _doit(self, newdb): for i, x in enumerate(self.ids): diff --git a/src/calibre/library/database2.py b/src/calibre/library/database2.py index c65484ff56..d6c2ddd659 100644 --- a/src/calibre/library/database2.py +++ b/src/calibre/library/database2.py @@ -161,7 +161,8 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): return path and os.path.exists(os.path.join(path, 'metadata.db')) def __init__(self, library_path, row_factory=False, default_prefs=None, - read_only=False): + read_only=False, is_second_db=False): + self.is_second_db = is_second_db try: if isbytestring(library_path): library_path = library_path.decode(filesystem_encoding) @@ -263,7 +264,8 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): migrate_preference('user_categories', {}) migrate_preference('saved_searches', {}) - set_saved_searches(self, 'saved_searches') + if not self.is_second_db: + set_saved_searches(self, 'saved_searches') # migrate grouped_search_terms if self.prefs.get('grouped_search_terms', None) is None: diff --git a/src/calibre/utils/search_query_parser.py b/src/calibre/utils/search_query_parser.py index 3c41498107..a937e055ac 100644 --- a/src/calibre/utils/search_query_parser.py +++ b/src/calibre/utils/search_query_parser.py @@ -16,11 +16,11 @@ methods :method:`SearchQueryParser.universal_set` and If this module is run, it will perform a series of unit tests. ''' -import sys, operator +import sys, operator, weakref -from calibre.utils.pyparsing import CaselessKeyword, Group, Forward, \ - CharsNotIn, Suppress, OneOrMore, MatchFirst, CaselessLiteral, \ - Optional, NoMatch, ParseException, QuotedString +from calibre.utils.pyparsing import (CaselessKeyword, Group, Forward, + CharsNotIn, Suppress, OneOrMore, MatchFirst, CaselessLiteral, + Optional, NoMatch, ParseException, QuotedString) from calibre.constants import preferred_encoding from calibre.utils.icu import sort_key from calibre import prints @@ -37,11 +37,19 @@ class SavedSearchQueries(object): def __init__(self, db, _opt_name): self.opt_name = _opt_name; - self.db = db if db is not None: self.queries = db.prefs.get(self.opt_name, {}) else: self.queries = {} + try: + self._db = weakref.ref(db) + except: + # db could be None + self._db = lambda : None + + @property + def db(self): + return self._db() def force_unicode(self, x): if not isinstance(x, unicode): @@ -49,21 +57,27 @@ class SavedSearchQueries(object): return x def add(self, name, value): - self.queries[self.force_unicode(name)] = self.force_unicode(value).strip() - self.db.prefs[self.opt_name] = self.queries + db = self.db + if db is not None: + self.queries[self.force_unicode(name)] = self.force_unicode(value).strip() + db.prefs[self.opt_name] = self.queries def lookup(self, name): return self.queries.get(self.force_unicode(name), None) def delete(self, name): - self.queries.pop(self.force_unicode(name), False) - self.db.prefs[self.opt_name] = self.queries + db = self.db + if db is not None: + self.queries.pop(self.force_unicode(name), False) + db.prefs[self.opt_name] = self.queries def rename(self, old_name, new_name): - self.queries[self.force_unicode(new_name)] = \ - self.queries.get(self.force_unicode(old_name), None) - self.queries.pop(self.force_unicode(old_name), False) - self.db.prefs[self.opt_name] = self.queries + db = self.db + if db is not None: + self.queries[self.force_unicode(new_name)] = \ + self.queries.get(self.force_unicode(old_name), None) + self.queries.pop(self.force_unicode(old_name), False) + db.prefs[self.opt_name] = self.queries def names(self): return sorted(self.queries.keys(),key=sort_key)