Merge lp:~stub/launchpad/replication into lp:launchpad

Proposed by Stuart Bishop
Status: Merged
Approved by: Tim Penhey
Approved revision: not available
Merged at revision: not available
Proposed branch: lp:~stub/launchpad/replication
Merge into: lp:launchpad
Diff against target: 143 lines (+48/-26)
2 files modified
database/replication/Makefile (+7/-4)
database/replication/repair-restored-db.py (+41/-22)
To merge this branch: bzr merge lp:~stub/launchpad/replication
Reviewer Review Type Date Requested Status
Tim Penhey (community) Approve
Review via email: mp+14980@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Stuart Bishop (stub) wrote :

Fix staging & dogfood rebuilds again. Now tested with dumps containing genuine Slony-I cruft.

Also made repair-restored-db.py a little more robust (I was wondering if the Slony UNINSTALL NODE command is just too fragile to bother with, but decided to keep trying to use it anyway as it has likely been improved in more modern versions of Slony-I and will succeed more often once the authdb replication set is somewhere else).

Revision history for this message
Tim Penhey (thumper) wrote :

Looks fine to me.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'database/replication/Makefile'
--- database/replication/Makefile 2009-11-13 10:41:58 +0000
+++ database/replication/Makefile 2009-11-18 04:00:30 +0000
@@ -36,6 +36,8 @@
36STAGING_CONFIG=staging # For swapping fresh db into place.36STAGING_CONFIG=staging # For swapping fresh db into place.
37STAGING_DUMP=launchpad.dump # Dumpfile to build new staging from.37STAGING_DUMP=launchpad.dump # Dumpfile to build new staging from.
38STAGING_TABLESPACE=pg_default # 'pg_default' for default38STAGING_TABLESPACE=pg_default # 'pg_default' for default
39DOGFOOD_DBNAME=launchpad_dogfood
40DOGFOOD_DUMP=launchpad.dump
3941
40_CONFIG=overridden-on-command-line42_CONFIG=overridden-on-command-line
41_SLAVE_TABLESPACE=pg_default43_SLAVE_TABLESPACE=pg_default
@@ -98,12 +100,13 @@
98 psql -q -d lpmain_staging_new -f authdb_drop.sql100 psql -q -d lpmain_staging_new -f authdb_drop.sql
99 psql -q -d lpmain_staging_new -f authdb_create.sql \101 psql -q -d lpmain_staging_new -f authdb_create.sql \
100 2>&1 | grep -v _sl || true102 2>&1 | grep -v _sl || true
103 # Restore the data
104 pg_restore --dbname=lpmain_staging_new \
105 --no-acl --no-owner --disable-triggers --data-only \
106 --exit-on-error ${STAGING_DUMP}
101 # Uninstall Slony-I if it is installed - a pg_dump of a DB with107 # Uninstall Slony-I if it is installed - a pg_dump of a DB with
102 # Slony-I installed isn't usable without this step.108 # Slony-I installed isn't usable without this step.
103 LPCONFIG=${NEW_STAGING_CONFIG} ./repair-restored-db.py109 LPCONFIG=${NEW_STAGING_CONFIG} ./repair-restored-db.py
104 pg_restore --dbname=lpmain_staging_new \
105 --no-acl --no-owner --disable-triggers --data-only \
106 --exit-on-error ${STAGING_DUMP}
107 # Setup replication110 # Setup replication
108 make _replicate LPCONFIG=${NEW_STAGING_CONFIG} LAG="0 seconds" \111 make _replicate LPCONFIG=${NEW_STAGING_CONFIG} LAG="0 seconds" \
109 _MASTER=lpmain_staging_new _SLAVE=lpmain_staging_slave_new \112 _MASTER=lpmain_staging_new _SLAVE=lpmain_staging_slave_new \
@@ -138,10 +141,10 @@
138 psql -q -d ${DOGFOOD_DBNAME} -f authdb_drop.sql141 psql -q -d ${DOGFOOD_DBNAME} -f authdb_drop.sql
139 psql -q -d ${DOGFOOD_DBNAME} -f authdb_create.sql \142 psql -q -d ${DOGFOOD_DBNAME} -f authdb_create.sql \
140 2>&1 | grep -v _sl || true143 2>&1 | grep -v _sl || true
141 ./repair-restored-db.py -d ${DOGFOOD_DBNAME}
142 pg_restore --dbname=${DOGFOOD_DBNAME} --no-acl --no-owner \144 pg_restore --dbname=${DOGFOOD_DBNAME} --no-acl --no-owner \
143 --disable-triggers --data-only \145 --disable-triggers --data-only \
144 --exit-on-error ${DOGFOOD_DUMP}146 --exit-on-error ${DOGFOOD_DUMP}
147 ./repair-restored-db.py -d ${DOGFOOD_DBNAME}
145 ../schema/upgrade.py -d ${DOGFOOD_DBNAME}148 ../schema/upgrade.py -d ${DOGFOOD_DBNAME}
146 ../schema/fti.py -d ${DOGFOOD_DBNAME}149 ../schema/fti.py -d ${DOGFOOD_DBNAME}
147 ../schema/security.py -d ${DOGFOOD_DBNAME}150 ../schema/security.py -d ${DOGFOOD_DBNAME}
148151
=== modified file 'database/replication/repair-restored-db.py'
--- database/replication/repair-restored-db.py 2009-10-17 14:06:03 +0000
+++ database/replication/repair-restored-db.py 2009-11-18 04:00:30 +0000
@@ -27,7 +27,8 @@
2727
28from canonical.config import config28from canonical.config import config
29from canonical.database.postgresql import ConnectionString29from canonical.database.postgresql import ConnectionString
30from canonical.database.sqlbase import connect, quote30from canonical.database.sqlbase import (
31 connect, quote, ISOLATION_LEVEL_AUTOCOMMIT)
31from canonical.launchpad.scripts import db_options, logger_options, logger32from canonical.launchpad.scripts import db_options, logger_options, logger
3233
33import replication.helpers34import replication.helpers
@@ -44,12 +45,23 @@
4445
45 log = logger(options)46 log = logger(options)
4647
47 con = connect(options.dbuser)48 con = connect(options.dbuser, isolation=ISOLATION_LEVEL_AUTOCOMMIT)
4849
49 if not replication.helpers.slony_installed(con):50 if not replication.helpers.slony_installed(con):
50 log.info("Slony-I not installed. Nothing to do.")51 log.info("Slony-I not installed. Nothing to do.")
51 return 052 return 0
5253
54 if not repair_with_slonik(log, options, con):
55 repair_with_drop_schema(log, con)
56
57 return 0
58
59
60def repair_with_slonik(log, options, con):
61 """Attempt to uninstall Slony-I via 'UNINSTALL NODE' per best practice.
62
63 Returns True on success, False if unable to do so for any reason.
64 """
53 cur = con.cursor()65 cur = con.cursor()
5466
55 # Determine the node id the database thinks it is.67 # Determine the node id the database thinks it is.
@@ -60,27 +72,19 @@
60 cur.execute(cmd)72 cur.execute(cmd)
61 node_id = cur.fetchone()[0]73 node_id = cur.fetchone()[0]
62 log.debug("Node Id is %d" % node_id)74 log.debug("Node Id is %d" % node_id)
75
76 # Get a list of set ids in the database.
77 cur.execute(
78 "SELECT DISTINCT set_id FROM %s.sl_set"
79 % replication.helpers.CLUSTER_NAMESPACE)
80 set_ids = set(row[0] for row in cur.fetchall())
81 log.debug("Set Ids are %s" % repr(set_ids))
82
63 except psycopg2.InternalError:83 except psycopg2.InternalError:
64 # Not enough information to determine node id. Possibly84 # Not enough information to determine node id. Possibly
65 # this is an empty database. Just drop the _sl schema as85 # this is an empty database.
66 # it is 'good enough' with Slony-I 1.2 - this mechanism86 log.debug('Broken or no Slony-I install.')
67 # fails with Slony added primary keys, but we don't do that.87 return False
68 con.rollback()
69 cur = con.cursor()
70 cur.execute("DROP SCHEMA _sl CASCADE")
71 con.commit()
72 return 0
73
74 # Get a list of set ids in the database.
75 cur.execute(
76 "SELECT DISTINCT set_id FROM %s.sl_set"
77 % replication.helpers.CLUSTER_NAMESPACE)
78 set_ids = set(row[0] for row in cur.fetchall())
79 log.debug("Set Ids are %s" % repr(set_ids))
80
81 # Close so we don't block slonik(1)
82 del cur
83 con.close()
8488
85 connection_string = ConnectionString(config.database.main_master)89 connection_string = ConnectionString(config.database.main_master)
86 if options.dbname:90 if options.dbname:
@@ -103,7 +107,22 @@
103 log.debug(line)107 log.debug(line)
104 script = '\n'.join(script)108 script = '\n'.join(script)
105109
106 replication.helpers.execute_slonik(script, auto_preamble=False)110 return replication.helpers.execute_slonik(
111 script, auto_preamble=False, exit_on_fail=False)
112
113
114def repair_with_drop_schema(log, con):
115 """
116 Just drop the _sl schema as it is 'good enough' with Slony-I 1.2.
117
118 This mechanism fails with Slony added primary keys, but we don't
119 do that.
120 """
121 log.info('Fallback mode - dropping _sl schema.')
122 cur = con.cursor()
123 cur.execute("DROP SCHEMA _sl CASCADE")
124 return True
125
107126
108if __name__ == '__main__':127if __name__ == '__main__':
109 sys.exit(main())128 sys.exit(main())