Merge lp:~stub/launchpad/pending-db-changes into lp:launchpad/db-devel

Proposed by Stuart Bishop
Status: Merged
Approved by: Stuart Bishop
Approved revision: no longer in the source branch.
Merged at revision: 9997
Proposed branch: lp:~stub/launchpad/pending-db-changes
Merge into: lp:launchpad/db-devel
Diff against target: 84 lines (+56/-0)
2 files modified
database/schema/patch-2208-01-1.sql (+10/-0)
database/schema/upgrade.py (+46/-0)
To merge this branch: bzr merge lp:~stub/launchpad/pending-db-changes
Reviewer Review Type Date Requested Status
Jelmer Vernooij (community) Approve
Review via email: mp+41691@code.launchpad.net

Commit message

[r=jelmer][ui=none][bug=368600,678289] Report database patch application times.

Description of the change

Store and report database patch application times.

The reported times are the time spent running the actual SQL. There are also overheads involved, but this should be constant. Given a total of these times for a rollout, the actual time will be "num_nodes * db_time + x * num_patches + y", where x and y are as yet unknown constants representing overhead per patch and extra overhead (trusted.sql, comments.sql, merging new table replication set into main replication set etc.)

To post a comment you must log in.
Revision history for this message
Jelmer Vernooij (jelmer) :
review: Approve
Revision history for this message
Robert Collins (lifeless) wrote :

When we have 2 slaves, do they apply patches in parallel with each
other, or serially?

Revision history for this message
Stuart Bishop (stub) wrote :

On Thu, Nov 25, 2010 at 2:26 AM, Robert Collins
<email address hidden> wrote:
> When we have 2 slaves, do they apply patches in parallel with each
> other, or serially?

Hmm... yeah. That formula is bogus. I think this is what happens: we
apply all the patches in a transaction on the master, so if it fails
on the master things roll back. Then slony sends off DDL as events
which propagate to the slaves and they run the DDL. Because our slaves
all connect directly to the master at the moment, they end up running
the DDL in parallel. So time would be 2 * db_time + x * num_slaves *
num_patches + y. In reality, we can get away with 2 * db_time + 5
minutes.

--
Stuart Bishop <email address hidden>
http://www.stuartbishop.net/

Revision history for this message
Robert Collins (lifeless) wrote :

On Thu, Nov 25, 2010 at 3:17 PM, Stuart Bishop
<email address hidden> wrote:
> the DDL in parallel. So time would be 2 * db_time + x * num_slaves *
> num_patches + y. In reality, we can get away with 2 * db_time + 5
> minutes.

Excellent - thanks. Could you perhaps put that in the release manager
notes on the wiki? We need to write up how to get these things and
have a place to record the total time for devs doing qa on db-devel
too, but thats a slightly separate problem :)

-Rob

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'database/schema/patch-2208-01-1.sql'
2--- database/schema/patch-2208-01-1.sql 1970-01-01 00:00:00 +0000
3+++ database/schema/patch-2208-01-1.sql 2010-11-24 10:19:33 +0000
4@@ -0,0 +1,10 @@
5+SET client_min_messages=ERROR;
6+
7+ALTER TABLE LaunchpadDatabaseRevision
8+ ADD start_time timestamp without time zone DEFAULT (
9+ transaction_timestamp() AT TIME ZONE 'UTC'),
10+ ADD end_time timestamp without time zone DEFAULT (
11+ statement_timestamp() AT TIME ZONE 'UTC');
12+
13+INSERT INTO LaunchpadDatabaseRevision VALUES (2208, 01, 1);
14+
15
16=== modified file 'database/schema/upgrade.py'
17--- database/schema/upgrade.py 2010-05-19 18:07:56 +0000
18+++ database/schema/upgrade.py 2010-11-24 10:19:33 +0000
19@@ -32,19 +32,65 @@
20
21 def main():
22 con = connect(options.dbuser)
23+ patches = get_patchlist(con)
24+
25 if replication.helpers.slony_installed(con):
26 con.close()
27 if options.commit is False:
28 parser.error("--dry-run does not make sense with replicated db")
29 log.info("Applying patches to Slony-I environment.")
30 apply_patches_replicated()
31+ con = connect(options.dbuser)
32 else:
33 log.info("Applying patches to unreplicated environment.")
34 apply_patches_normal(con)
35
36+ report_patch_times(con, patches)
37+
38 return 0
39
40
41+def to_seconds(td):
42+ """Convert a timedelta to seconds."""
43+ return td.days * (24*60*60) + td.seconds + td.microseconds/1000000.0
44+
45+
46+def report_patch_times(con, todays_patches):
47+ """Report how long it took to apply the given patches."""
48+ cur = con.cursor()
49+
50+ todays_patches = [patch_tuple for patch_tuple, patch_file
51+ in todays_patches]
52+
53+ cur.execute("""
54+ SELECT
55+ major, minor, patch, start_time, end_time - start_time AS db_time
56+ FROM LaunchpadDatabaseRevision
57+ WHERE start_time > CURRENT_TIMESTAMP AT TIME ZONE 'UTC'
58+ - CAST('1 month' AS interval)
59+ ORDER BY major, minor, patch
60+ """)
61+ for major, minor, patch, start_time, db_time in cur.fetchall():
62+ if (major, minor, patch) in todays_patches:
63+ continue
64+ db_time = to_seconds(db_time)
65+ start_time = start_time.strftime('%Y-%m-%d')
66+ log.info(
67+ "%d-%02d-%d applied %s in %0.1f seconds"
68+ % (major, minor, patch, start_time, db_time))
69+
70+ for major, minor, patch in todays_patches:
71+ cur.execute("""
72+ SELECT end_time - start_time AS db_time
73+ FROM LaunchpadDatabaseRevision
74+ WHERE major = %s AND minor = %s AND patch = %s
75+ """, (major, minor, patch))
76+ db_time = cur.fetchone()[0]
77+ log.info(
78+ "%d-%02d-%d applied just now in %0.1f seconds",
79+ major, minor, patch, to_seconds(db_time))
80+
81+
82 def apply_patches_normal(con):
83 """Update a non replicated database."""
84 # trusted.sql contains all our stored procedures, which may

Subscribers

People subscribed via source and target branches

to status/vote changes: