webapp: close database cursors
authorHelmut Grohne <helmut@subdivi.de>
Tue, 10 Sep 2013 07:39:40 +0000 (09:39 +0200)
committerHelmut Grohne <helmut@subdivi.de>
Tue, 10 Sep 2013 07:39:40 +0000 (09:39 +0200)
Leaking them can result in running out of available filedescriptors.

webapp.py

index d5f076e..4478ba0 100755 (executable)
--- a/webapp.py
+++ b/webapp.py
@@ -1,5 +1,6 @@
 #!/usr/bin/python
 
+import contextlib
 import datetime
 import optparse
 import sqlite3
@@ -98,42 +99,43 @@ class Application(object):
             return e
 
     def get_details(self, package):
-        cur = self.db.cursor()
-        cur.execute("SELECT id, version, architecture FROM package WHERE name = ?;",
-                    (package,))
-        row = cur.fetchone()
-        if not row:
-            raise NotFound()
-        pid, version, architecture = row
-        details = dict(pid=pid,
-                       package=package,
-                       version=version,
-                       architecture=architecture)
-        cur.execute("SELECT count(filename), sum(size) FROM content WHERE pid = ?;",
-                    (pid,))
-        num_files, total_size = cur.fetchone()
+        with contextlib.closing(self.db.cursor()) as cur:
+            cur.execute("SELECT id, version, architecture FROM package WHERE name = ?;",
+                        (package,))
+            row = cur.fetchone()
+            if not row:
+                raise NotFound()
+            pid, version, architecture = row
+            details = dict(pid=pid,
+                           package=package,
+                           version=version,
+                           architecture=architecture)
+            cur.execute("SELECT count(filename), sum(size) FROM content WHERE pid = ?;",
+                        (pid,))
+            num_files, total_size = cur.fetchone()
         if total_size is None:
             total_size = 0
         details.update(dict(num_files=num_files, total_size=total_size))
         return details
 
     def get_dependencies(self, pid):
-        cur = self.db.cursor()
-        cur.execute("SELECT required FROM dependency WHERE pid = ?;",
-                    (pid,))
-        return set(row[0] for row in fetchiter(cur))
+        with contextlib.closing(self.db.cursor()) as cur:
+            cur.execute("SELECT required FROM dependency WHERE pid = ?;",
+                        (pid,))
+            return set(row[0] for row in fetchiter(cur))
 
     def cached_sharedstats(self, pid):
-        cur = self.db.cursor()
         sharedstats = {}
-        cur.execute("SELECT pid2, package.name, f1.name, f2.name, files, size FROM sharing JOIN package ON sharing.pid2 = package.id JOIN function AS f1 ON sharing.fid1 = f1.id JOIN function AS f2 ON sharing.fid2 = f2.id WHERE pid1 = ? AND f1.eqclass = f2.eqclass;",
-                    (pid,))
-        for pid2, package2, func1, func2, files, size in fetchiter(cur):
-            curstats = sharedstats.setdefault(
-                    function_combination(func1, func2), list())
-            if pid2 == pid:
-                package2 = None
-            curstats.append(dict(package=package2, duplicate=files, savable=size))
+        with contextlib.closing(self.db.cursor()) as cur:
+            cur.execute("SELECT pid2, package.name, f1.name, f2.name, files, size FROM sharing JOIN package ON sharing.pid2 = package.id JOIN function AS f1 ON sharing.fid1 = f1.id JOIN function AS f2 ON sharing.fid2 = f2.id WHERE pid1 = ? AND f1.eqclass = f2.eqclass;",
+                        (pid,))
+            for pid2, package2, func1, func2, files, size in fetchiter(cur):
+                curstats = sharedstats.setdefault(
+                        function_combination(func1, func2), list())
+                if pid2 == pid:
+                    package2 = None
+                curstats.append(dict(package=package2, duplicate=files,
+                                     savable=size))
         return sharedstats
 
     def show_package(self, package):
@@ -206,12 +208,12 @@ class Application(object):
         return html_response(detail_template.stream(params))
 
     def show_hash(self, function, hashvalue):
-        cur = self.db.cursor()
-        cur.execute("SELECT package.name, content.filename, content.size, f2.name FROM hash JOIN content ON hash.cid = content.id JOIN package ON content.pid = package.id JOIN function AS f2 ON hash.fid = f2.id JOIN function AS f1 ON f2.eqclass = f1.eqclass WHERE f1.name = ? AND hash = ?;",
-                    (function, hashvalue,))
-        entries = [dict(package=package, filename=filename, size=size,
-                        function=otherfunc)
-                   for package, filename, size, otherfunc in fetchiter(cur)]
+        with contextlib.closing(self.db.cursor()) as cur:
+            cur.execute("SELECT package.name, content.filename, content.size, f2.name FROM hash JOIN content ON hash.cid = content.id JOIN package ON content.pid = package.id JOIN function AS f2 ON hash.fid = f2.id JOIN function AS f1 ON f2.eqclass = f1.eqclass WHERE f1.name = ? AND hash = ?;",
+                        (function, hashvalue,))
+            entries = [dict(package=package, filename=filename, size=size,
+                            function=otherfunc)
+                       for package, filename, size, otherfunc in fetchiter(cur)]
         if not entries:
             raise NotFound()
         params = dict(function=function, hashvalue=hashvalue, entries=entries,
@@ -219,21 +221,21 @@ class Application(object):
         return html_response(hash_template.render(params))
 
     def show_source(self, package):
-        cur = self.db.cursor()
-        cur.execute("SELECT name FROM package WHERE source = ?;",
-                    (package,))
-        binpkgs = dict.fromkeys(pkg for pkg, in fetchiter(cur))
-        if not binpkgs:
-            raise NotFound
-        cur.execute("SELECT p1.name, p2.name, f1.name, f2.name, sharing.files, sharing.size FROM sharing JOIN package AS p1 ON sharing.pid1 = p1.id JOIN package AS p2 ON sharing.pid2 = p2.id JOIN function AS f1 ON sharing.fid1 = f1.id JOIN function AS f2 ON sharing.fid2 = f2.id WHERE p1.source = ?;",
-                    (package,))
-        for binary, otherbin, func1, func2, files, size in fetchiter(cur):
-            entry = dict(package=otherbin,
-                         funccomb=function_combination(func1, func2),
-                         duplicate=files, savable=size)
-            oldentry = binpkgs.get(binary)
-            if not (oldentry and oldentry["savable"] >= size):
-                binpkgs[binary] = entry
+        with contextlib.closing(self.db.cursor()) as cur:
+            cur.execute("SELECT name FROM package WHERE source = ?;",
+                        (package,))
+            binpkgs = dict.fromkeys(pkg for pkg, in fetchiter(cur))
+            if not binpkgs:
+                raise NotFound
+            cur.execute("SELECT p1.name, p2.name, f1.name, f2.name, sharing.files, sharing.size FROM sharing JOIN package AS p1 ON sharing.pid1 = p1.id JOIN package AS p2 ON sharing.pid2 = p2.id JOIN function AS f1 ON sharing.fid1 = f1.id JOIN function AS f2 ON sharing.fid2 = f2.id WHERE p1.source = ?;",
+                        (package,))
+            for binary, otherbin, func1, func2, files, size in fetchiter(cur):
+                entry = dict(package=otherbin,
+                             funccomb=function_combination(func1, func2),
+                             duplicate=files, savable=size)
+                oldentry = binpkgs.get(binary)
+                if not (oldentry and oldentry["savable"] >= size):
+                    binpkgs[binary] = entry
         params = dict(source=package, packages=binpkgs, urlroot="..")
         return html_response(source_template.render(params))