summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan McGee <dan@archlinux.org>2012-12-28 21:41:18 +0100
committerDan McGee <dan@archlinux.org>2012-12-28 21:48:29 +0100
commit20b64e42672d185821cc584dfa4b133ee259a144 (patch)
treee4ac17f704cc73eaeb1c806f09cb40b05da1de92
parent29be1e06032ad8a0a38921b9e04be888141881b1 (diff)
downloadarchweb-20b64e42672d185821cc584dfa4b133ee259a144.tar.gz
archweb-20b64e42672d185821cc584dfa4b133ee259a144.tar.xz
Reduce query count when retrieving satisfiers and providers
Django doesn't attach the parent object to the child objects, even when queried through the related manager. This causes up to 3 extra queries: one to retrieve the package again, and one each for arch and repo retrieval. For a package like archboot, this drops the number of necessary queries for the package page from 805 to 222 (yes, this is still too high) and cuts the time spent waiting on the database from 505ms to 262ms. Signed-off-by: Dan McGee <dan@archlinux.org>
-rw-r--r--main/models.py4
-rw-r--r--packages/models.py20
2 files changed, 14 insertions, 10 deletions
diff --git a/main/models.py b/main/models.py
index b3cc97e..ba24645 100644
--- a/main/models.py
+++ b/main/models.py
@@ -271,10 +271,10 @@ class Package(models.Model):
arches = None
# TODO: we can use list comprehension and an 'in' query to make this more effective
for dep in self.depends.all():
- pkg = dep.get_best_satisfier()
+ pkg = dep.get_best_satisfier(self)
providers = None
if not pkg:
- providers = dep.get_providers()
+ providers = dep.get_providers(self)
deps.append({'dep': dep, 'pkg': pkg, 'providers': providers})
# sort the list; deptype sorting makes this tricker than expected
sort_order = {'D': 0, 'O': 1, 'M': 2, 'C': 3}
diff --git a/packages/models.py b/packages/models.py
index a4095f5..18d57c5 100644
--- a/packages/models.py
+++ b/packages/models.py
@@ -349,14 +349,16 @@ class RelatedToBase(models.Model):
name = models.CharField(max_length=255, db_index=True)
version = models.CharField(max_length=255, default='')
- def get_best_satisfier(self):
+ def get_best_satisfier(self, main_pkg=None):
'''Find a satisfier for this related package that best matches the
given criteria. It will not search provisions, but will find packages
named and matching repo characteristics if possible.'''
+ if main_pkg is None:
+ main_pkg = self.pkg
pkgs = Package.objects.normal().filter(pkgname=self.name)
- if not self.pkg.arch.agnostic:
+ if not main_pkg.arch.agnostic:
# make sure we match architectures if possible
- arches = self.pkg.applicable_arches()
+ arches = main_pkg.applicable_arches()
pkgs = pkgs.filter(arch__in=arches)
# if we have a comparison operation, make sure the packages we grab
# actually satisfy the requirements
@@ -376,25 +378,27 @@ class RelatedToBase(models.Model):
pkg = pkgs[0]
# prevents yet more DB queries, these lists should be short;
# after each grab the best available in case we remove all entries
- pkgs = [p for p in pkgs if p.repo.staging == self.pkg.repo.staging]
+ pkgs = [p for p in pkgs if p.repo.staging == main_pkg.repo.staging]
if len(pkgs) > 0:
pkg = pkgs[0]
- pkgs = [p for p in pkgs if p.repo.testing == self.pkg.repo.testing]
+ pkgs = [p for p in pkgs if p.repo.testing == main_pkg.repo.testing]
if len(pkgs) > 0:
pkg = pkgs[0]
return pkg
- def get_providers(self):
+ def get_providers(self, main_pkg=None):
'''Return providers of this related package. Does *not* include exact
matches as it checks the Provision names only, use get_best_satisfier()
instead for exact matches.'''
+ if main_pkg is None:
+ main_pkg = self.pkg
pkgs = Package.objects.normal().filter(
provides__name=self.name).order_by().distinct()
- if not self.pkg.arch.agnostic:
+ if not main_pkg.arch.agnostic:
# make sure we match architectures if possible
- arches = self.pkg.applicable_arches()
+ arches = main_pkg.applicable_arches()
pkgs = pkgs.filter(arch__in=arches)
# If we have a comparison operation, make sure the packages we grab