Merge lp:~mvo/software-center/per-thread-xapiandb into lp:software-center

Proposed by Michael Vogt
Status: Merged
Merged at revision: 2331
Proposed branch: lp:~mvo/software-center/per-thread-xapiandb
Merge into: lp:software-center
Diff against target: 155 lines (+64/-41)
2 files modified
softwarecenter/db/database.py (+56/-33)
softwarecenter/db/enquire.py (+8/-8)
To merge this branch: bzr merge lp:~mvo/software-center/per-thread-xapiandb
Reviewer Review Type Date Requested Status
Gary Lasker (community) Approve
Michael Vogt Pending
Review via email: mp+75349@code.launchpad.net

Description of the change

Hopefully kills off race condition behind #736116 (and maybe even #638706)

To post a comment you must log in.
2330. By Michael Vogt

softwarecenter/db/enquire.py: make sure we use uniq names

Revision history for this message
Gary Lasker (gary-lasker) wrote :

Hey mvo! This is a nice and very clever approach, and it certainly does appear to have have excellent potential for taking care of those bugs you mention (and as you know the second of the two, the DocNotFound master bug, is our current most evil one of all).

I did a bunch of testing and this does appear to maintain a unique database instance per each thread, exactly as intended. I could not detect a case where a given thread_name was changed to use a different database.

So, this one seems good to me! If this takes care of the DocNotFound errors, man, that will call for a serious celebration!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'softwarecenter/db/database.py'
--- softwarecenter/db/database.py 2011-08-17 12:24:39 +0000
+++ softwarecenter/db/database.py 2011-09-14 16:21:29 +0000
@@ -140,18 +140,63 @@
140 # the xapian values as read from /var/lib/apt-xapian-index/values140 # the xapian values as read from /var/lib/apt-xapian-index/values
141 self._axi_values = {}141 self._axi_values = {}
142 self._logger = logging.getLogger("softwarecenter.db")142 self._logger = logging.getLogger("softwarecenter.db")
143143 # we open one db per thread, thread names are reused eventually
144 def acquire_search_lock(self):144 # so no memory leak
145 self._search_lock.acquire()145 self._db_per_thread = {}
146146 self._parser_per_thread = {}
147 def release_search_lock(self):147
148 self._search_lock.release()148 @property
149149 def xapiandb(self):
150 """ returns a per thread db """
151 thread_name = threading.current_thread().name
152 if not thread_name in self._db_per_thread:
153 self._db_per_thread[thread_name] = self._get_new_xapiandb()
154 return self._db_per_thread[thread_name]
155
156 @property
157 def xapian_parser(self):
158 """ returns a per thread query parser """
159 thread_name = threading.current_thread().name
160 if not thread_name in self._parser_per_thread:
161 self._parser_per_thread[thread_name] = self._get_new_xapian_parser()
162 return self._parser_per_thread[thread_name]
163
164 def _get_new_xapiandb(self):
165 xapiandb = xapian.Database(self._db_pathname)
166 if self._use_axi:
167 try:
168 axi = xapian.Database("/var/lib/apt-xapian-index/index")
169 xapiandb.add_database(axi)
170 except:
171 self._logger.exception("failed to add apt-xapian-index")
172 if (self._use_agent and
173 os.path.exists(XAPIAN_BASE_PATH_SOFTWARE_CENTER_AGENT)):
174 try:
175 sca = xapian.Database(XAPIAN_BASE_PATH_SOFTWARE_CENTER_AGENT)
176 xapiandb.add_database(sca)
177 except Exception as e:
178 logging.warn("failed to add sca db %s" % e)
179 for db in self._additional_databases:
180 xapiandb.add_database(db)
181 return xapiandb
182
183 def _get_new_xapian_parser(self):
184 xapian_parser = xapian.QueryParser()
185 xapian_parser.set_database(self.xapiandb)
186 xapian_parser.add_boolean_prefix("pkg", "XP")
187 xapian_parser.add_boolean_prefix("pkg", "AP")
188 xapian_parser.add_boolean_prefix("mime", "AM")
189 xapian_parser.add_boolean_prefix("section", "XS")
190 xapian_parser.add_boolean_prefix("origin", "XOC")
191 xapian_parser.add_prefix("pkg_wildcard", "XP")
192 xapian_parser.add_prefix("pkg_wildcard", "AP")
193 xapian_parser.set_default_op(xapian.Query.OP_AND)
194 return xapian_parser
195
150 def open(self, pathname=None, use_axi=True, use_agent=True):196 def open(self, pathname=None, use_axi=True, use_agent=True):
151 """ open the database """197 """ open the database """
152 if pathname:198 if pathname:
153 self._db_pathname = pathname199 self._db_pathname = pathname
154 self.xapiandb = xapian.Database(self._db_pathname)
155 # add the apt-xapian-database for here (we don't do this200 # add the apt-xapian-database for here (we don't do this
156 # for now as we do not have a good way to integrate non-apps201 # for now as we do not have a good way to integrate non-apps
157 # with the UI)202 # with the UI)
@@ -159,35 +204,13 @@
159 self._use_axi = use_axi204 self._use_axi = use_axi
160 self._use_agent = use_agent205 self._use_agent = use_agent
161 if use_axi:206 if use_axi:
162 try:207 self._axi_values = parse_axi_values_file()
163 axi = xapian.Database("/var/lib/apt-xapian-index/index")208 self.nr_databases += 1
164 self.xapiandb.add_database(axi)
165 self._axi_values = parse_axi_values_file()
166 self.nr_databases += 1
167 except:
168 self._logger.exception("failed to add apt-xapian-index")
169 if use_agent:209 if use_agent:
170 try:210 self.nr_databases += 1
171 sca = xapian.Database(XAPIAN_BASE_PATH_SOFTWARE_CENTER_AGENT)
172 self.xapiandb.add_database(sca)
173 self.nr_databases += 1
174 except Exception as e:
175 logging.warn("failed to add sca db %s" % e)
176 # additional dbs211 # additional dbs
177 for db in self._additional_databases:212 for db in self._additional_databases:
178 self.xapiandb.add_database(db)
179 self.nr_databases += 1213 self.nr_databases += 1
180 # parser etc
181 self.xapian_parser = xapian.QueryParser()
182 self.xapian_parser.set_database(self.xapiandb)
183 self.xapian_parser.add_boolean_prefix("pkg", "XP")
184 self.xapian_parser.add_boolean_prefix("pkg", "AP")
185 self.xapian_parser.add_boolean_prefix("mime", "AM")
186 self.xapian_parser.add_boolean_prefix("section", "XS")
187 self.xapian_parser.add_boolean_prefix("origin", "XOC")
188 self.xapian_parser.add_prefix("pkg_wildcard", "XP")
189 self.xapian_parser.add_prefix("pkg_wildcard", "AP")
190 self.xapian_parser.set_default_op(xapian.Query.OP_AND)
191 self.emit("open", self._db_pathname)214 self.emit("open", self._db_pathname)
192215
193 def add_database(self, database):216 def add_database(self, database):
194217
=== modified file 'softwarecenter/db/enquire.py'
--- softwarecenter/db/enquire.py 2011-08-25 18:51:39 +0000
+++ softwarecenter/db/enquire.py 2011-09-14 16:21:29 +0000
@@ -85,7 +85,14 @@
8585
86 def _threaded_perform_search(self):86 def _threaded_perform_search(self):
87 self._perform_search_complete = False87 self._perform_search_complete = False
88 thread_name = 'ThreadedQuery-%s' % (threading.active_count()+1)88 # generate a name and ensure we never have two threads
89 # with the same name
90 names = [thread.name for thread in threading.enumerate()]
91 for i in range(threading.active_count()+1, 0, -1):
92 thread_name = 'ThreadedQuery-%s' % i
93 if not thread_name in names:
94 break
95 # create and start it
89 t = threading.Thread(96 t = threading.Thread(
90 target=self._blocking_perform_search, name=thread_name)97 target=self._blocking_perform_search, name=thread_name)
91 t.start()98 t.start()
@@ -128,9 +135,6 @@
128 # use a unique instance of both enquire and xapian database135 # use a unique instance of both enquire and xapian database
129 # so concurrent queries dont result in an inconsistent database136 # so concurrent queries dont result in an inconsistent database
130137
131 # get lock
132 self.db.acquire_search_lock()
133
134 # an alternative would be to serialise queries138 # an alternative would be to serialise queries
135 enquire = xapian.Enquire(self.db.xapiandb)139 enquire = xapian.Enquire(self.db.xapiandb)
136140
@@ -223,10 +227,6 @@
223 _matches.append(match)227 _matches.append(match)
224 match_docids.add(match.docid)228 match_docids.add(match.docid)
225229
226 # release the lock here because the following check may trigger
227 # calling this function again (and we would deadlock otherwise)
228 self.db.release_search_lock()
229
230 # if we have no results, try forcing pkgs to be displayed230 # if we have no results, try forcing pkgs to be displayed
231 # if not NonAppVisibility.NEVER_VISIBLE is set231 # if not NonAppVisibility.NEVER_VISIBLE is set
232 if (not _matches and232 if (not _matches and

Subscribers

People subscribed via source and target branches