[LNT] r248789 - Fix postgres unit tests by closing db connections.
Adam Nemet via llvm-commits
llvm-commits at lists.llvm.org
Wed Oct 7 23:27:44 PDT 2015
> On Sep 29, 2015, at 4:49 AM, Kristof Beyls via llvm-commits <llvm-commits at lists.llvm.org> wrote:
>
> Author: kbeyls
> Date: Tue Sep 29 06:49:15 2015
> New Revision: 248789
>
> URL: http://llvm.org/viewvc/llvm-project?rev=248789&view=rev
> Log:
> Fix postgres unit tests by closing db connections.
>
> When running the unit tests on a postgres database, the following error shows:
>
> sqlalchemy.exc.TimeoutError: QueuePool limit of size 5 overflow 10 reached, connection timed out, timeout 30
>
> We've also seen this error from time to time on the instance running at
> llvm.org/perf, and it was unclear what the exact reason was for this. Now that
> we can run the unit tests on postgres, this shows that not closing the db
> connection at the end of a request is at least one of the reasons this error
> can be produced.
>
> Differential Revision: http://reviews.llvm.org/D13164
>
>
> Modified:
> lnt/trunk/lnt/lnttool/import_data.py
> lnt/trunk/lnt/lnttool/main.py
> lnt/trunk/lnt/lnttool/updatedb.py
> lnt/trunk/lnt/lnttool/viewcomparison.py
> lnt/trunk/lnt/server/db/v4db.py
> lnt/trunk/lnt/server/ui/app.py
> lnt/trunk/lnt/util/ImportData.py
> lnt/trunk/lnt/util/ServerUtil.py
>
> Modified: lnt/trunk/lnt/lnttool/import_data.py
> URL: http://llvm.org/viewvc/llvm-project/lnt/trunk/lnt/lnttool/import_data.py?rev=248789&r1=248788&r2=248789&view=diff
> ==============================================================================
> --- lnt/trunk/lnt/lnttool/import_data.py (original)
> +++ lnt/trunk/lnt/lnttool/import_data.py Tue Sep 29 06:49:15 2015
> @@ -3,6 +3,8 @@ import os, pprint, sys, time
> import lnt.formats
> import lnt.util.ImportData
> import lnt.server.instance
> +import contextlib
> +
>
> def action_import(name, args):
> """import test data into a database"""
> @@ -45,27 +47,26 @@ def action_import(name, args):
> config = instance.config
>
> # Get the database.
> - db = config.get_database(opts.database, echo=opts.show_sql)
> -
> - # Load the database.
> - success = True
> - for file in args:
> - result = lnt.util.ImportData.import_and_report(
> - config, opts.database, db, file,
> - opts.format, opts.commit, opts.show_sample_count,
> - opts.no_email, opts.no_report)
> -
> - success &= result.get('success', False)
> - if opts.quiet:
> - continue
> -
> - if opts.show_raw_result:
> - pprint.pprint(result)
> - else:
> - lnt.util.ImportData.print_report_result(result, sys.stdout,
> - sys.stderr,
> - opts.verbose)
> -
> - if not success:
> - raise SystemExit, 1
> + with contextlib.closing(config.get_database(opts.database,
> + echo=opts.show_sql)) as db:
> + # Load the database.
> + success = True
> + for file in args:
> + result = lnt.util.ImportData.import_and_report(
> + config, opts.database, db, file,
> + opts.format, opts.commit, opts.show_sample_count,
> + opts.no_email, opts.no_report)
> +
> + success &= result.get('success', False)
> + if opts.quiet:
> + continue
> +
> + if opts.show_raw_result:
> + pprint.pprint(result)
> + else:
> + lnt.util.ImportData.print_report_result(result, sys.stdout,
> + sys.stderr,
> + opts.verbose)
>
> + if not success:
> + raise SystemExit, 1
>
> Modified: lnt/trunk/lnt/lnttool/main.py
> URL: http://llvm.org/viewvc/llvm-project/lnt/trunk/lnt/lnttool/main.py?rev=248789&r1=248788&r2=248789&view=diff
> ==============================================================================
> --- lnt/trunk/lnt/lnttool/main.py (original)
> +++ lnt/trunk/lnt/lnttool/main.py Tue Sep 29 06:49:15 2015
> @@ -5,6 +5,7 @@ import os
> import sys
> import tempfile
> from optparse import OptionParser, OptionGroup
> +import contextlib
>
> import werkzeug.contrib.profiler
>
> @@ -293,57 +294,59 @@ def action_send_daily_report(name, args)
> config = instance.config
>
> # Get the database.
> - db = config.get_database(opts.database)
> + with contextlib.closing(config.get_database(opts.database)) as db:
>
> - # Get the testsuite.
> - ts = db.testsuite[opts.testsuite]
> + # Get the testsuite.
> + ts = db.testsuite[opts.testsuite]
>
> - if opts.today:
> - date = datetime.datetime.utcnow()
> - else:
> - # Get a timestamp to use to derive the daily report to generate.
> - latest = ts.query(ts.Run).\
> - order_by(ts.Run.start_time.desc()).limit(1).first()
> -
> - # If we found a run, use it's start time (rounded up to the next hour,
> - # so we make sure it gets included).
> - if latest:
> - date = latest.start_time + datetime.timedelta(hours=1)
> - else:
> - # Otherwise, just use now.
> + if opts.today:
> date = datetime.datetime.utcnow()
> + else:
> + # Get a timestamp to use to derive the daily report to generate.
> + latest = ts.query(ts.Run).\
> + order_by(ts.Run.start_time.desc()).limit(1).first()
> +
> + # If we found a run, use it's start time (rounded up to the next
> + # hour, so we make sure it gets included).
> + if latest:
> + date = latest.start_time + datetime.timedelta(hours=1)
> + else:
> + # Otherwise, just use now.
> + date = datetime.datetime.utcnow()
> +
> + # Generate the daily report.
> + note("building report data...")
> + report = lnt.server.reporting.dailyreport.DailyReport(
> + ts, year=date.year, month=date.month, day=date.day,
> + day_start_offset_hours=date.hour, for_mail=True,
> + num_prior_days_to_include=opts.days,
> + filter_machine_regex=opts.filter_machine_regex)
> + report.build()
> +
> + note("generating HTML report...")
> + ts_url = "%s/db_%s/v4/%s" \
> + % (config.zorgURL, opts.database, opts.testsuite)
> + subject = "Daily Report: %04d-%02d-%02d" % (
> + report.year, report.month, report.day)
> + html_report = report.render(ts_url, only_html_body=False)
> +
> + if opts.subject_prefix is not None:
> + subject = "%s %s" % (opts.subject_prefix, subject)
> +
> + # Form the multipart email message.
> + msg = email.mime.multipart.MIMEMultipart('alternative')
> + msg['Subject'] = subject
> + msg['From'] = opts.from_address
> + msg['To'] = to_address
> + msg.attach(email.mime.text.MIMEText(html_report, "html"))
> +
> + # Send the report.
> + if not opts.dry_run:
> + s = smtplib.SMTP(opts.host)
> + s.sendmail(opts.from_address, [to_address],
> + msg.as_string())
> + s.quit()
>
> - # Generate the daily report.
> - note("building report data...")
> - report = lnt.server.reporting.dailyreport.DailyReport(
> - ts, year=date.year, month=date.month, day=date.day,
> - day_start_offset_hours=date.hour, for_mail=True,
> - num_prior_days_to_include=opts.days,
> - filter_machine_regex=opts.filter_machine_regex)
> - report.build()
> -
> - note("generating HTML report...")
> - ts_url = "%s/db_%s/v4/%s" % (config.zorgURL, opts.database, opts.testsuite)
> - subject = "Daily Report: %04d-%02d-%02d" % (
> - report.year, report.month, report.day)
> - html_report = report.render(ts_url, only_html_body=False)
> -
> - if opts.subject_prefix is not None:
> - subject = "%s %s" % (opts.subject_prefix, subject)
> -
> - # Form the multipart email message.
> - msg = email.mime.multipart.MIMEMultipart('alternative')
> - msg['Subject'] = subject
> - msg['From'] = opts.from_address
> - msg['To'] = to_address
> - msg.attach(email.mime.text.MIMEText(html_report, "html"))
> -
> - # Send the report.
> - if not opts.dry_run:
> - s = smtplib.SMTP(opts.host)
> - s.sendmail(opts.from_address, [to_address],
> - msg.as_string())
> - s.quit()
>
> def action_send_run_comparison(name, args):
> """send a run-vs-run comparison email"""
> @@ -397,47 +400,47 @@ def action_send_run_comparison(name, arg
> config = instance.config
>
> # Get the database.
> - db = config.get_database(opts.database)
> + with contextlib.closing(config.get_database(opts.database)) as db:
>
> - # Get the testsuite.
> - ts = db.testsuite[opts.testsuite]
> + # Get the testsuite.
> + ts = db.testsuite[opts.testsuite]
>
> - # Lookup the two runs.
> - run_a_id = int(run_a_id)
> - run_b_id = int(run_b_id)
> - run_a = ts.query(ts.Run).\
> - filter_by(id=run_a_id).first()
> - run_b = ts.query(ts.Run).\
> - filter_by(id=run_b_id).first()
> - if run_a is None:
> - parser.error("invalid run ID %r (not in database)" % (run_a_id,))
> - if run_b is None:
> - parser.error("invalid run ID %r (not in database)" % (run_b_id,))
> -
> - # Generate the report.
> - reports = lnt.server.reporting.runs.generate_run_report(
> - run_b, baseurl=config.zorgURL, only_html_body=False, result=None,
> - compare_to=run_a, baseline=None,
> - aggregation_fn=min)
> - subject, text_report, html_report, _ = reports
> -
> - if opts.subject_prefix is not None:
> - subject = "%s %s" % (opts.subject_prefix, subject)
> -
> - # Form the multipart email message.
> - msg = email.mime.multipart.MIMEMultipart('alternative')
> - msg['Subject'] = subject
> - msg['From'] = opts.from_address
> - msg['To'] = opts.to_address
> - msg.attach(email.mime.text.MIMEText(text_report, 'plain'))
> - msg.attach(email.mime.text.MIMEText(html_report, 'html'))
> -
> - # Send the report.
> - if not opts.dry_run:
> - s = smtplib.SMTP(opts.host)
> - s.sendmail(opts.from_address, [opts.to_address],
> - msg.as_string())
> - s.quit()
> + # Lookup the two runs.
> + run_a_id = int(run_a_id)
> + run_b_id = int(run_b_id)
> + run_a = ts.query(ts.Run).\
> + filter_by(id=run_a_id).first()
> + run_b = ts.query(ts.Run).\
> + filter_by(id=run_b_id).first()
> + if run_a is None:
> + parser.error("invalid run ID %r (not in database)" % (run_a_id,))
> + if run_b is None:
> + parser.error("invalid run ID %r (not in database)" % (run_b_id,))
> +
> + # Generate the report.
> + reports = lnt.server.reporting.runs.generate_run_report(
> + run_b, baseurl=config.zorgURL, only_html_body=False, result=None,
> + compare_to=run_a, baseline=None,
> + aggregation_fn=min)
> + subject, text_report, html_report, _ = reports
> +
> + if opts.subject_prefix is not None:
> + subject = "%s %s" % (opts.subject_prefix, subject)
> +
> + # Form the multipart email message.
> + msg = email.mime.multipart.MIMEMultipart('alternative')
> + msg['Subject'] = subject
> + msg['From'] = opts.from_address
> + msg['To'] = opts.to_address
> + msg.attach(email.mime.text.MIMEText(text_report, 'plain'))
> + msg.attach(email.mime.text.MIMEText(html_report, 'html'))
> +
> + # Send the report.
> + if not opts.dry_run:
> + s = smtplib.SMTP(opts.host)
> + s.sendmail(opts.from_address, [opts.to_address],
> + msg.as_string())
> + s.quit()
>
> ###
>
>
> Modified: lnt/trunk/lnt/lnttool/updatedb.py
> URL: http://llvm.org/viewvc/llvm-project/lnt/trunk/lnt/lnttool/updatedb.py?rev=248789&r1=248788&r2=248789&view=diff
> ==============================================================================
> --- lnt/trunk/lnt/lnttool/updatedb.py (original)
> +++ lnt/trunk/lnt/lnttool/updatedb.py Tue Sep 29 06:49:15 2015
> @@ -1,5 +1,6 @@
> import os
> from optparse import OptionParser, OptionGroup
> +import contextlib
>
> import lnt.server.instance
> from lnt.testing.util.commands import note, warning, error, fatal
> @@ -29,48 +30,50 @@ def action_updatedb(name, args):
>
> if opts.testsuite is None:
> parser.error("--testsuite is required")
> -
> +
> path, = args
>
> # Load the instance.
> instance = lnt.server.instance.Instance.frompath(path)
>
> # Get the database and test suite.
> - db = instance.get_database(opts.database, echo=opts.show_sql)
> - ts = db.testsuite[opts.testsuite]
> -
> - # Compute a list of all the runs to delete.
> - runs_to_delete = list(opts.delete_runs)
> - if opts.delete_machines:
> - runs_to_delete.extend(
> - id
> - for id, in ts.query(ts.Run.id).\
> - join(ts.Machine).\
> - filter(ts.Machine.name.in_(opts.delete_machines)))
> -
> - # Delete all samples associated with those runs.
> - ts.query(ts.Sample).\
> - filter(ts.Sample.run_id.in_(runs_to_delete)).\
> - delete(synchronize_session=False)
> -
> - # Delete all those runs.
> - ts.query(ts.Run).\
> - filter(ts.Run.id.in_(runs_to_delete)).\
> - delete(synchronize_session=False)
> -
> - # Delete the machines.
> - for name in opts.delete_machines:
> - # Delete all FieldChanges associated with this machine.
> - ids = ts.query(ts.FieldChange.id).\
> - join(ts.Machine).filter(ts.Machine.name == name).all()
> - for i in ids:
> - ts.query(ts.FieldChange).filter(ts.FieldChange.id == i[0]).delete()
> -
> - num_deletes = ts.query(ts.Machine).filter_by(name=name).delete()
> - if num_deletes == 0:
> - warning("unable to find machine named: %r" % name)
> -
> - if opts.commit:
> - db.commit()
> - else:
> - db.rollback()
> + with contextlib.closing(instance.get_database(opts.database,
> + echo=opts.show_sql)) as db:
> + ts = db.testsuite[opts.testsuite]
> +
> + # Compute a list of all the runs to delete.
> + runs_to_delete = list(opts.delete_runs)
> + if opts.delete_machines:
> + runs_to_delete.extend(
> + id
> + for id, in ts.query(ts.Run.id).\
> + join(ts.Machine).\
> + filter(ts.Machine.name.in_(opts.delete_machines)))
> +
> + # Delete all samples associated with those runs.
> + ts.query(ts.Sample).\
> + filter(ts.Sample.run_id.in_(runs_to_delete)).\
> + delete(synchronize_session=False)
> +
> + # Delete all those runs.
> + ts.query(ts.Run).\
> + filter(ts.Run.id.in_(runs_to_delete)).\
> + delete(synchronize_session=False)
> +
> + # Delete the machines.
> + for name in opts.delete_machines:
> + # Delete all FieldChanges associated with this machine.
> + ids = ts.query(ts.FieldChange.id).\
> + join(ts.Machine).filter(ts.Machine.name == name).all()
> + for i in ids:
> + ts.query(ts.FieldChange).filter(ts.FieldChange.id == i[0]).\
> + delete()
> +
> + num_deletes = ts.query(ts.Machine).filter_by(name=name).delete()
> + if num_deletes == 0:
> + warning("unable to find machine named: %r" % name)
> +
> + if opts.commit:
> + db.commit()
> + else:
> + db.rollback()
>
> Modified: lnt/trunk/lnt/lnttool/viewcomparison.py
> URL: http://llvm.org/viewvc/llvm-project/lnt/trunk/lnt/lnttool/viewcomparison.py?rev=248789&r1=248788&r2=248789&view=diff
> ==============================================================================
> --- lnt/trunk/lnt/lnttool/viewcomparison.py (original)
> +++ lnt/trunk/lnt/lnttool/viewcomparison.py Tue Sep 29 06:49:15 2015
> @@ -8,6 +8,7 @@ import time
> import urllib
> import webbrowser
> from optparse import OptionParser, OptionGroup
> +import contextlib
>
> import lnt.util.ImportData
> from lnt.testing.util.commands import note, warning, error, fatal
> @@ -86,22 +87,22 @@ def action_view_comparison(name, args):
> lnt.server.db.migrate.update_path(db_path)
>
> # Import the two reports.
> - db = config.get_database('default')
> - result = lnt.util.ImportData.import_and_report(
> - config, 'default', db, report_a_path,
> - '<auto>', commit=True)
> - result = lnt.util.ImportData.import_and_report(
> - config, 'default', db, report_b_path,
> - '<auto>', commit=True)
> -
> - # Dispatch another thread to start the webbrowser.
> - comparison_url = '%s/v4/nts/2?compare_to=1' % (url,)
> - note("opening comparison view: %s" % (comparison_url,))
> - thread.start_new_thread(start_browser, (comparison_url,True))
> -
> - # Run the webserver.
> - app = lnt.server.ui.app.App.create_with_instance(instance)
> - app.debug = True
> - app.run(opts.hostname, opts.port, use_reloader=False)
> + with contextlib.closing(config.get_database('default')) as db:
> + result = lnt.util.ImportData.import_and_report(
> + config, 'default', db, report_a_path,
> + '<auto>', commit=True)
> + result = lnt.util.ImportData.import_and_report(
> + config, 'default', db, report_b_path,
> + '<auto>', commit=True)
> +
> + # Dispatch another thread to start the webbrowser.
> + comparison_url = '%s/v4/nts/2?compare_to=1' % (url,)
> + note("opening comparison view: %s" % (comparison_url,))
> + thread.start_new_thread(start_browser, (comparison_url, True))
> +
> + # Run the webserver.
> + app = lnt.server.ui.app.App.create_with_instance(instance)
> + app.debug = True
> + app.run(opts.hostname, opts.port, use_reloader=False)
> finally:
> shutil.rmtree(tmpdir)
>
> Modified: lnt/trunk/lnt/server/db/v4db.py
> URL: http://llvm.org/viewvc/llvm-project/lnt/trunk/lnt/server/db/v4db.py?rev=248789&r1=248788&r2=248789&view=diff
> ==============================================================================
> --- lnt/trunk/lnt/server/db/v4db.py (original)
> +++ lnt/trunk/lnt/server/db/v4db.py Tue Sep 29 06:49:15 2015
> @@ -124,6 +124,10 @@ class V4DB(object):
> assert (self.real_sample_type and self.status_sample_type), \
> "sample types not initialized!"
>
> + def close(self):
> + if self.session is not None:
> + self.session.close()
> +
> @property
> def testsuite(self):
> # This is the start of "magic" part of V4DB, which allows us to get
>
> Modified: lnt/trunk/lnt/server/ui/app.py
> URL: http://llvm.org/viewvc/llvm-project/lnt/trunk/lnt/server/ui/app.py?rev=248789&r1=248788&r2=248789&view=diff
> ==============================================================================
> --- lnt/trunk/lnt/server/ui/app.py (original)
> +++ lnt/trunk/lnt/server/ui/app.py Tue Sep 29 06:49:15 2015
> @@ -85,6 +85,13 @@ class Request(flask.Request):
>
> return self.testsuite
>
> + def close(self):
> + db = getattr(self, 'db', None)
> + if db is not None:
> + db.close()
> + return super(Request, self).close()
> +
> +
> class App(flask.Flask):
> @staticmethod
> def create_with_instance(instance):
>
> Modified: lnt/trunk/lnt/util/ImportData.py
> URL: http://llvm.org/viewvc/llvm-project/lnt/trunk/lnt/util/ImportData.py?rev=248789&r1=248788&r2=248789&view=diff
> ==============================================================================
> --- lnt/trunk/lnt/util/ImportData.py (original)
> +++ lnt/trunk/lnt/util/ImportData.py Tue Sep 29 06:49:15 2015
> @@ -122,19 +122,19 @@ def import_and_report(config, db_name, d
> # Load the shadow database to import into.
> db_config = config.databases[db_name]
> shadow_name = db_config.shadow_import
> - shadow_db = config.get_database(shadow_name)
> - if shadow_db is None:
> - raise ValueError,("invalid configuration, shadow import "
> - "database %r does not exist") % shadow_name
> + with closing(config.get_database(shadow_name)) as shadow_db:
> + if shadow_db is None:
> + raise ValueError, ("invalid configuration, shadow import "
> + "database %r does not exist") % shadow_name
>
> - # Perform the shadow import.
> - shadow_result = import_and_report(config, shadow_name,
> - shadow_db, file, format, commit,
> - show_sample_count, disable_email,
> - disable_report)
> + # Perform the shadow import.
> + shadow_result = import_and_report(config, shadow_name,
> + shadow_db, file, format, commit,
> + show_sample_count, disable_email,
> + disable_report)
>
> - # Append the shadow result to the result.
> - result['shadow_result'] = shadow_result
> + # Append the shadow result to the result.
> + result['shadow_result'] = shadow_result
>
> result['success'] = True
> return result
>
> Modified: lnt/trunk/lnt/util/ServerUtil.py
> URL: http://llvm.org/viewvc/llvm-project/lnt/trunk/lnt/util/ServerUtil.py?rev=248789&r1=248788&r2=248789&view=diff
> ==============================================================================
> --- lnt/trunk/lnt/util/ServerUtil.py (original)
> +++ lnt/trunk/lnt/util/ServerUtil.py Tue Sep 29 06:49:15 2015
> @@ -45,11 +45,12 @@ def submitFileToInstance(path, file, com
> instance = lnt.server.instance.Instance.frompath(path)
> config = instance.config
> db_name = 'default'
> - db = config.get_database(db_name)
> - if db is None:
> - raise ValueError("no default database in instance: %r" % (path,))
> - return lnt.util.ImportData.import_and_report(
> - config, db_name, db, file, format='<auto>', commit=commit)
> + with closing(config.get_database(db_name)) as db:
> + if db is None:
> + raise ValueError("no default database in instance: %r" % (path,))
> + return lnt.util.ImportData.import_and_report(
> + config, db_name, db, file, format='<auto>', commit=commit)
> +
Hi Kristof,
Isn’t this missing “import contextlib” and contextlib.closing later?
Adam
>
> def submitFile(url, file, commit, verbose):
> # If this is a real url, submit it using urllib.
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
More information about the llvm-commits
mailing list