Merge ~cjwatson/launchpad:rename-master-slave-flavors into launchpad:master

Proposed by Colin Watson
Status: Merged
Approved by: Colin Watson
Approved revision: e3abd7078ce5ff79b9a69bc4064ac0eab9ed983a
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~cjwatson/launchpad:rename-master-slave-flavors
Merge into: launchpad:master
Diff against target: 885 lines (+155/-153)
11 files modified
lib/lp/services/database/doc/db-policy.txt (+1/-1)
lib/lp/services/database/interfaces.py (+16/-16)
lib/lp/services/database/policy.py (+36/-36)
lib/lp/services/oauth/tests/test_oauth.py (+6/-5)
lib/lp/services/verification/model/logintoken.py (+2/-2)
lib/lp/services/webapp/adapter.py (+8/-8)
lib/lp/services/webapp/doc/test_adapter.txt (+4/-4)
lib/lp/services/webapp/doc/test_adapter_permissions.txt (+16/-15)
lib/lp/services/webapp/doc/test_adapter_timeout.txt.disabled (+3/-3)
lib/lp/services/webapp/publication.py (+5/-5)
lib/lp/services/webapp/tests/test_dbpolicy.py (+58/-58)
Reviewer Review Type Date Requested Status
Jürgen Gmach Approve
Review via email: mp+411554@code.launchpad.net

Commit message

Rename master/slave DB flavors to primary/standby

Description of the change

The corresponding `I*Store` interfaces are still called master/slave, so there's still some mixed terminology, but we're getting closer.

To post a comment you must log in.
Revision history for this message
Jürgen Gmach (jugmac00) wrote :

LGTM, with one suggestion

review: Approve
Revision history for this message
Colin Watson (cjwatson) :

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/lib/lp/services/database/doc/db-policy.txt b/lib/lp/services/database/doc/db-policy.txt
2index 17dc147..8a1cce2 100644
3--- a/lib/lp/services/database/doc/db-policy.txt
4+++ b/lib/lp/services/database/doc/db-policy.txt
5@@ -83,7 +83,7 @@ resources.
6 ... Person, Person.name == 'janitor').one()
7 Traceback (most recent call last):
8 ...
9- lp.services.database.interfaces.DisallowedStore: master
10+ lp.services.database.interfaces.DisallowedStore: primary
11
12 We can even ensure no database activity occurs at all, for instance
13 if we need to guarantee a potentially long running call doesn't access
14diff --git a/lib/lp/services/database/interfaces.py b/lib/lp/services/database/interfaces.py
15index c9709ef..14407be 100644
16--- a/lib/lp/services/database/interfaces.py
17+++ b/lib/lp/services/database/interfaces.py
18@@ -14,8 +14,8 @@ __all__ = [
19 'IStore',
20 'IStoreSelector',
21 'MAIN_STORE',
22- 'MASTER_FLAVOR',
23- 'SLAVE_FLAVOR',
24+ 'PRIMARY_FLAVOR',
25+ 'STANDBY_FLAVOR',
26 ]
27
28
29@@ -46,8 +46,8 @@ MAIN_STORE = 'main' # The main database.
30 ALL_STORES = frozenset([MAIN_STORE])
31
32 DEFAULT_FLAVOR = 'default' # Default flavor for current state.
33-MASTER_FLAVOR = 'master' # The master database.
34-SLAVE_FLAVOR = 'slave' # A slave database.
35+PRIMARY_FLAVOR = 'primary' # The primary database.
36+STANDBY_FLAVOR = 'standby' # A standby database.
37
38
39 class IDatabasePolicy(Interface):
40@@ -75,7 +75,7 @@ class IDatabasePolicy(Interface):
41
42 :param name: one of ALL_STORES.
43
44- :param flavor: MASTER_FLAVOR, SLAVE_FLAVOR, or DEFAULT_FLAVOR.
45+ :param flavor: PRIMARY_FLAVOR, STANDBY_FLAVOR, or DEFAULT_FLAVOR.
46 """
47
48 def install():
49@@ -94,15 +94,15 @@ class DisallowedStore(Exception):
50 class IStoreSelector(Interface):
51 """Get a Storm store with a desired flavor.
52
53- Stores come in two flavors - MASTER_FLAVOR and SLAVE_FLAVOR.
54+ Stores come in two flavors - PRIMARY_FLAVOR and STANDBY_FLAVOR.
55
56- The master is writable and up to date, but we should not use it
57- whenever possible because there is only one master and we don't want
58+ The primary is writable and up to date, but we should not use it
59+ whenever possible because there is only one primary and we don't want
60 it to be overloaded.
61
62- The slave is read only replica of the master and may lag behind the
63- master. For many purposes such as serving unauthenticated web requests
64- and generating reports this is fine. We can also have as many slave
65+ The standby is a read-only replica of the primary and may lag behind the
66+ primary. For many purposes such as serving unauthenticated web requests
67+ and generating reports this is fine. We can also have as many standby
68 databases as we are prepared to pay for, so they will perform better
69 because they are less loaded.
70 """
71@@ -126,16 +126,16 @@ class IStoreSelector(Interface):
72 returned for a given name or flavor can depend on thread state
73 (eg. the HTTP request currently being handled).
74
75- If a SLAVE_FLAVOR is requested, the MASTER_FLAVOR may be returned
76+ If a STANDBY_FLAVOR is requested, the PRIMARY_FLAVOR may be returned
77 anyway.
78
79- The DEFAULT_FLAVOR flavor may return either a master or slave
80+ The DEFAULT_FLAVOR flavor may return either a primary or standby
81 depending on process state. Application code using the
82- DEFAULT_FLAVOR flavor should assume they have a MASTER and that
83+ DEFAULT_FLAVOR flavor should assume they have a PRIMARY and that
84 a higher level will catch the exception raised if an attempt is
85- made to write changes to a read only store. DEFAULT_FLAVOR exists
86+ made to write changes to a read-only store. DEFAULT_FLAVOR exists
87 for backwards compatibility, and new code should explicitly state
88- if they want a master or a slave.
89+ if they want a primary or a standby.
90
91 :raises DisconnectionError:
92
93diff --git a/lib/lp/services/database/policy.py b/lib/lp/services/database/policy.py
94index a347060..838df09 100644
95--- a/lib/lp/services/database/policy.py
96+++ b/lib/lp/services/database/policy.py
97@@ -47,8 +47,8 @@ from lp.services.database.interfaces import (
98 ISlaveStore,
99 IStoreSelector,
100 MAIN_STORE,
101- MASTER_FLAVOR,
102- SLAVE_FLAVOR,
103+ PRIMARY_FLAVOR,
104+ STANDBY_FLAVOR,
105 )
106 from lp.services.database.sqlbase import StupidCache
107
108@@ -107,7 +107,7 @@ class BaseDatabasePolicy:
109 """Base class for database policies."""
110
111 # The default flavor to use.
112- default_flavor = MASTER_FLAVOR
113+ default_flavor = PRIMARY_FLAVOR
114
115 def __init__(self, request=None):
116 pass
117@@ -121,21 +121,21 @@ class BaseDatabasePolicy:
118 store = get_connected_store(name, flavor)
119 except DisconnectionError:
120
121- # A request for a master database connection was made
122+ # A request for a primary database connection was made
123 # and failed. Nothing we can do so reraise the exception.
124- if flavor != SLAVE_FLAVOR:
125+ if flavor != STANDBY_FLAVOR:
126 raise
127
128- # A request for a slave database connection was made
129- # and failed. Try to return a master connection, this
130+ # A request for a standby database connection was made
131+ # and failed. Try to return a primary connection, this
132 # will be good enough. Note we don't call self.getStore()
133 # recursively because we want to make this attempt even if
134- # the DatabasePolicy normally disallows master database
135+ # the DatabasePolicy normally disallows primary database
136 # connections. All this behaviour allows read-only requests
137- # to keep working when slave databases are being rebuilt or
138+ # to keep working when standby databases are being rebuilt or
139 # updated.
140 try:
141- flavor = MASTER_FLAVOR
142+ flavor = PRIMARY_FLAVOR
143 store = get_connected_store(name, flavor)
144 except DisconnectionError:
145 store = None
146@@ -155,7 +155,7 @@ class BaseDatabasePolicy:
147 store._cache = storm_cache_factory()
148
149 # Attach our marker interfaces so our adapters don't lie.
150- if flavor == MASTER_FLAVOR:
151+ if flavor == PRIMARY_FLAVOR:
152 alsoProvides(store, IMasterStore)
153 else:
154 alsoProvides(store, ISlaveStore)
155@@ -193,7 +193,7 @@ class DatabaseBlockedPolicy(BaseDatabasePolicy):
156
157
158 class PrimaryDatabasePolicy(BaseDatabasePolicy):
159- """`IDatabasePolicy` that selects the MASTER_FLAVOR by default.
160+ """`IDatabasePolicy` that selects the PRIMARY_FLAVOR by default.
161
162 Standby databases can still be accessed if requested explicitly.
163
164@@ -201,29 +201,29 @@ class PrimaryDatabasePolicy(BaseDatabasePolicy):
165 support session cookies. It is also used when no policy has been
166 installed.
167 """
168- default_flavor = MASTER_FLAVOR
169+ default_flavor = PRIMARY_FLAVOR
170
171
172 class StandbyDatabasePolicy(BaseDatabasePolicy):
173- """`IDatabasePolicy` that selects the SLAVE_FLAVOR by default.
174+ """`IDatabasePolicy` that selects the STANDBY_FLAVOR by default.
175
176 Access to the primary can still be made if requested explicitly.
177 """
178- default_flavor = SLAVE_FLAVOR
179+ default_flavor = STANDBY_FLAVOR
180
181
182 class StandbyOnlyDatabasePolicy(BaseDatabasePolicy):
183- """`IDatabasePolicy` that only allows access to SLAVE_FLAVOR stores.
184+ """`IDatabasePolicy` that only allows access to STANDBY_FLAVOR stores.
185
186 This policy is used for Feeds requests and other always-read only request.
187 """
188- default_flavor = SLAVE_FLAVOR
189+ default_flavor = STANDBY_FLAVOR
190
191 def getStore(self, name, flavor):
192 """See `IDatabasePolicy`."""
193- if flavor == MASTER_FLAVOR:
194+ if flavor == PRIMARY_FLAVOR:
195 raise DisallowedStore(flavor)
196- return super().getStore(name, SLAVE_FLAVOR)
197+ return super().getStore(name, STANDBY_FLAVOR)
198
199
200 def LaunchpadDatabasePolicyFactory(request):
201@@ -263,25 +263,25 @@ class LaunchpadDatabasePolicy(BaseDatabasePolicy):
202 """See `IDatabasePolicy`."""
203 default_flavor = None
204
205- # If this is a Retry attempt, force use of the master database.
206+ # If this is a Retry attempt, force use of the primary database.
207 if getattr(self.request, '_retry_count', 0) > 0:
208- default_flavor = MASTER_FLAVOR
209+ default_flavor = PRIMARY_FLAVOR
210
211- # Select if the DEFAULT_FLAVOR Store will be the master or a
212- # slave. We select slave if this is a readonly request, and
213+ # Select if the DEFAULT_FLAVOR Store will be the primary or a
214+ # standby. We select standby if this is a readonly request, and
215 # only readonly requests have been made by this user recently.
216 # This ensures that a user will see any changes they just made
217- # on the master, despite the fact it might take a while for
218- # those changes to propagate to the slave databases.
219+ # on the primary, despite the fact it might take a while for
220+ # those changes to propagate to the standby databases.
221 elif self.read_only:
222 lag = self.getReplicationLag()
223 if (lag is not None
224 and lag > timedelta(seconds=config.database.max_usable_lag)):
225- # Don't use the slave at all if lag is greater than the
226+ # Don't use the standby at all if lag is greater than the
227 # configured threshold. This reduces replication oddities
228 # noticed by users, as well as reducing load on the
229- # slave allowing it to catch up quicker.
230- default_flavor = MASTER_FLAVOR
231+ # standby allowing it to catch up quicker.
232+ default_flavor = PRIMARY_FLAVOR
233 else:
234 # We don't want to even make a DB query to read the session
235 # if we can tell that it is not around. This can be
236@@ -300,11 +300,11 @@ class LaunchpadDatabasePolicy(BaseDatabasePolicy):
237 else:
238 recently = timedelta(minutes=2) + lag
239 if last_write is None or last_write < now - recently:
240- default_flavor = SLAVE_FLAVOR
241+ default_flavor = STANDBY_FLAVOR
242 else:
243- default_flavor = MASTER_FLAVOR
244+ default_flavor = PRIMARY_FLAVOR
245 else:
246- default_flavor = MASTER_FLAVOR
247+ default_flavor = PRIMARY_FLAVOR
248
249 assert default_flavor is not None, 'default_flavor not set!'
250
251@@ -315,7 +315,7 @@ class LaunchpadDatabasePolicy(BaseDatabasePolicy):
252
253 If the request just handled was not read_only, we need to store
254 this fact and the timestamp in the session. Subsequent requests
255- can then keep using the master until they are sure any changes
256+ can then keep using the primary until they are sure any changes
257 made have been propagated.
258 """
259 if not self.read_only:
260@@ -352,15 +352,15 @@ class LaunchpadDatabasePolicy(BaseDatabasePolicy):
261 return _test_lag
262
263 # Attempt to retrieve PostgreSQL streaming replication lag
264- # from the slave.
265- slave_store = self.getStore(MAIN_STORE, SLAVE_FLAVOR)
266- hot_standby, streaming_lag = slave_store.execute("""
267+ # from the standby.
268+ standby_store = self.getStore(MAIN_STORE, STANDBY_FLAVOR)
269+ hot_standby, streaming_lag = standby_store.execute("""
270 SELECT
271 pg_is_in_recovery(),
272 now() - pg_last_xact_replay_timestamp()
273 """).get_one()
274 if hot_standby and streaming_lag is not None:
275- # Slave is a PG 9.1 streaming replication hot standby.
276+ # standby is a PG 9.1 streaming replication hot standby.
277 # Return the lag.
278 return streaming_lag
279
280diff --git a/lib/lp/services/oauth/tests/test_oauth.py b/lib/lp/services/oauth/tests/test_oauth.py
281index 1d95ccc..20c192c 100644
282--- a/lib/lp/services/oauth/tests/test_oauth.py
283+++ b/lib/lp/services/oauth/tests/test_oauth.py
284@@ -12,7 +12,7 @@ from zope.component import getUtility
285
286 from lp.services.database.interfaces import (
287 MAIN_STORE,
288- MASTER_FLAVOR,
289+ PRIMARY_FLAVOR,
290 )
291 from lp.services.oauth.model import (
292 OAuthAccessToken,
293@@ -26,14 +26,15 @@ class BaseOAuthTestCase(unittest.TestCase):
294 """Base tests for the OAuth database classes."""
295 layer = DatabaseFunctionalLayer
296
297- def test__getStore_should_return_the_main_master_store(self):
298- """We want all OAuth classes to use the master store.
299+ def test__getStore_should_return_the_main_primary_store(self):
300+ """We want all OAuth classes to use the primary store.
301 Otherwise, the OAuth exchanges will fail because the authorize
302- screen won't probably find the new request token on the slave store.
303+ screen won't probably find the new request token on the standby
304+ store.
305 """
306 zstorm = getUtility(IZStorm)
307 self.assertEqual(
308- '%s-%s' % (MAIN_STORE, MASTER_FLAVOR),
309+ '%s-%s' % (MAIN_STORE, PRIMARY_FLAVOR),
310 zstorm.get_name(self.class_._getStore()))
311
312
313diff --git a/lib/lp/services/verification/model/logintoken.py b/lib/lp/services/verification/model/logintoken.py
314index ca24bf8..9243471 100644
315--- a/lib/lp/services/verification/model/logintoken.py
316+++ b/lib/lp/services/verification/model/logintoken.py
317@@ -279,7 +279,7 @@ class LoginTokenSet:
318 "consumed should be one of {True, False, None}. Got '%s'."
319 % consumed)
320
321- # It's important to always use the MASTER_FLAVOR store here
322+ # It's important to always use the PRIMARY_FLAVOR store here
323 # because we don't want replication lag to cause a 404 error.
324 return IMasterStore(LoginToken).find(LoginToken, conditions)
325
326@@ -306,7 +306,7 @@ class LoginTokenSet:
327 "consumed should be one of {True, False, None}. Got '%s'."
328 % consumed)
329
330- # It's important to always use the MASTER_FLAVOR store here
331+ # It's important to always use the PRIMARY_FLAVOR store here
332 # because we don't want replication lag to cause a 404 error.
333 return IMasterStore(LoginToken).find(LoginToken, conditions)
334
335diff --git a/lib/lp/services/webapp/adapter.py b/lib/lp/services/webapp/adapter.py
336index 816f206..653983d 100644
337--- a/lib/lp/services/webapp/adapter.py
338+++ b/lib/lp/services/webapp/adapter.py
339@@ -57,8 +57,8 @@ from lp.services.database.interfaces import (
340 IRequestExpired,
341 IStoreSelector,
342 MAIN_STORE,
343- MASTER_FLAVOR,
344- SLAVE_FLAVOR,
345+ PRIMARY_FLAVOR,
346+ STANDBY_FLAVOR,
347 )
348 from lp.services.database.policy import PrimaryDatabasePolicy
349 from lp.services.database.postgresql import ConnectionString
350@@ -467,7 +467,7 @@ class LaunchpadDatabase(Postgres):
351 % repr(self._uri.database))
352
353 assert realm == 'main', 'Unknown realm %s' % realm
354- assert flavor in ('master', 'slave'), 'Unknown flavor %s' % flavor
355+ assert flavor in ('primary', 'standby'), 'Unknown flavor %s' % flavor
356
357 # We set self._dsn here rather than in __init__ so when the Store
358 # is reconnected it pays attention to any config changes.
359@@ -496,13 +496,13 @@ class LaunchpadDatabase(Postgres):
360 # An alternative would be to use the _ro users generated by
361 # security.py, but this would needlessly double the number
362 # of database users we need to maintain ACLs for on production.
363- if flavor == SLAVE_FLAVOR:
364+ if flavor == STANDBY_FLAVOR:
365 raw_connection.cursor().execute(
366 'SET DEFAULT_TRANSACTION_READ_ONLY TO TRUE')
367 # Make the altered session setting stick.
368 raw_connection.commit()
369- else:
370- assert config_entry.endswith('_master'), (
371+ elif not config_entry.endswith(('_master', '_primary')):
372+ raise AssertionError(
373 'DB connection URL %s does not meet naming convention.')
374
375 _reset_dirty_commit_flags(*flags)
376@@ -769,12 +769,12 @@ def get_store(storm_class, flavor=DEFAULT_FLAVOR):
377
378 def get_master_store(storm_class):
379 """Return the master Store for the given database class."""
380- return get_store(storm_class, MASTER_FLAVOR)
381+ return get_store(storm_class, PRIMARY_FLAVOR)
382
383
384 def get_slave_store(storm_class):
385 """Return the master Store for the given database class."""
386- return get_store(storm_class, SLAVE_FLAVOR)
387+ return get_store(storm_class, STANDBY_FLAVOR)
388
389
390 def get_object_from_master_store(obj):
391diff --git a/lib/lp/services/webapp/doc/test_adapter.txt b/lib/lp/services/webapp/doc/test_adapter.txt
392index 0b6712c..abe5036 100644
393--- a/lib/lp/services/webapp/doc/test_adapter.txt
394+++ b/lib/lp/services/webapp/doc/test_adapter.txt
395@@ -12,7 +12,7 @@ Imports and test setup:
396 >>> from lazr.restful.utils import get_current_browser_request
397 >>> from storm.zope.interfaces import IZStorm
398 >>> from lp.services.database.interfaces import (
399- ... IStoreSelector, MAIN_STORE, MASTER_FLAVOR)
400+ ... IStoreSelector, MAIN_STORE, PRIMARY_FLAVOR)
401 >>> from lp.services.config import config
402 >>> import lp.services.webapp.adapter
403 >>> from lp.services.webapp.adapter import (
404@@ -24,7 +24,7 @@ Imports and test setup:
405 There are several possible database connections available via the
406 IStoreSelector utility.
407
408- >>> store = getUtility(IStoreSelector).get(MAIN_STORE, MASTER_FLAVOR)
409+ >>> store = getUtility(IStoreSelector).get(MAIN_STORE, PRIMARY_FLAVOR)
410 >>> dbname = DatabaseLayer._db_fixture.dbname
411 >>> active_name = store.execute("SELECT current_database()").get_one()[0]
412 >>> if active_name != dbname: print('%s != %s' % (active_name, dbname))
413@@ -190,7 +190,7 @@ the Postgres statement timeout (a value of zero means no timeout):
414 ... zstorm.remove(store)
415 ... transaction.abort()
416 ... store.close()
417- ... store = getUtility(IStoreSelector).get(MAIN_STORE, MASTER_FLAVOR)
418+ ... store = getUtility(IStoreSelector).get(MAIN_STORE, PRIMARY_FLAVOR)
419
420 >>> set_request_started()
421 >>> print(current_statement_timeout(store))
422@@ -357,7 +357,7 @@ The request time limit was exceeded before the statement was issued to
423 the database.
424
425 >>> print(pretty(get_request_statements()))
426- [(0, ..., 'SQL-main-master', 'SELECT 2', ...)]
427+ [(0, ..., 'SQL-main-primary', 'SELECT 2', ...)]
428
429
430 When a RequestExpired exception is raised, the current
431diff --git a/lib/lp/services/webapp/doc/test_adapter_permissions.txt b/lib/lp/services/webapp/doc/test_adapter_permissions.txt
432index 8cf15f6..2ae057f 100644
433--- a/lib/lp/services/webapp/doc/test_adapter_permissions.txt
434+++ b/lib/lp/services/webapp/doc/test_adapter_permissions.txt
435@@ -1,24 +1,25 @@
436-Our database adapters need to trap writes to tables in slave replication
437-sets. These tables may be reached directly using a SLAVE_FLAVOR store, or
438-traversed to from a MASTER_FLAVOR store.
439+Our database adapters need to trap writes to tables in standby replication
440+sets. These tables may be reached directly using a STANDBY_FLAVOR store, or
441+traversed to from a PRIMARY_FLAVOR store.
442
443 Because our development environment is not replicated, we use database
444-permissions to ensure that tables we should not be writing too cannot
445+permissions to ensure that tables we should not be writing to cannot
446 be written to. The same permissions structure is also used on production,
447-so the Slony-I triggers blocking writes to slaved tables will never
448+so the Slony-I triggers blocking writes to some tables will never
449 actually be invoked.
450
451 >>> from lp.registry.model.person import Person
452 >>> from lp.services.database.interfaces import (
453- ... IStoreSelector, MAIN_STORE, MASTER_FLAVOR, SLAVE_FLAVOR)
454+ ... IStoreSelector, MAIN_STORE, PRIMARY_FLAVOR, STANDBY_FLAVOR)
455 >>> import transaction
456 >>> from zope.component import getUtility
457
458-If a SLAVE_FLAVOR store is requested, it should trap all writes.
459+If a STANDBY_FLAVOR store is requested, it should trap all writes.
460
461 >>> t = transaction.begin()
462- >>> main_slave = getUtility(IStoreSelector).get(MAIN_STORE, SLAVE_FLAVOR)
463- >>> janitor = main_slave.find(Person, name='janitor').one()
464+ >>> main_standby = getUtility(IStoreSelector).get(
465+ ... MAIN_STORE, STANDBY_FLAVOR)
466+ >>> janitor = main_standby.find(Person, name='janitor').one()
467 >>> janitor.display_name = 'Ben Dover'
468 >>> transaction.commit()
469 Traceback (most recent call last):
470@@ -29,21 +30,21 @@ Test this once more to ensure the settings stick across transactions.
471
472 >>> transaction.abort()
473 >>> t = transaction.begin()
474- >>> main_slave.find(Person, name='janitor').one().display_name = 'BenD'
475+ >>> main_standby.find(Person, name='janitor').one().display_name = 'BenD'
476 >>> transaction.commit()
477 Traceback (most recent call last):
478 ...
479 storm.database.InternalError: ...
480
481-If a MASTER_FLAVOR is requested, it should allow writes to table in that
482+If a PRIMARY_FLAVOR is requested, it should allow writes to table in that
483 Store's replication set.
484
485 >>> t = transaction.begin()
486- >>> main_master = getUtility(IStoreSelector).get(
487- ... MAIN_STORE, MASTER_FLAVOR)
488- >>> main_master.find(Person, name='janitor').one().display_name = 'BenD'
489+ >>> main_primary = getUtility(IStoreSelector).get(
490+ ... MAIN_STORE, PRIMARY_FLAVOR)
491+ >>> main_primary.find(Person, name='janitor').one().display_name = 'BenD'
492 >>> transaction.commit()
493 >>> t = transaction.begin()
494- >>> print(main_master.find(Person, name='janitor').one().display_name)
495+ >>> print(main_primary.find(Person, name='janitor').one().display_name)
496 BenD
497 >>> transaction.abort()
498diff --git a/lib/lp/services/webapp/doc/test_adapter_timeout.txt.disabled b/lib/lp/services/webapp/doc/test_adapter_timeout.txt.disabled
499index dbf7a36..9585e0a 100644
500--- a/lib/lp/services/webapp/doc/test_adapter_timeout.txt.disabled
501+++ b/lib/lp/services/webapp/doc/test_adapter_timeout.txt.disabled
502@@ -29,7 +29,7 @@ exception, and a time machine.
503 >>> from lp.services.config import config
504 >>> import lp.services.webapp.adapter
505 >>> from lp.services.webapp.interfaces import (
506- ... IStoreSelector, MAIN_STORE, MASTER_FLAVOR)
507+ ... IStoreSelector, MAIN_STORE, PRIMARY_FLAVOR)
508 >>> from lp.testing.pages import setupBrowser
509
510 >>> config.push('set_timeout', dedent('''
511@@ -53,7 +53,7 @@ exception, and a time machine.
512 ... return self, None
513 ... def __call__(self):
514 ... store = zope.component.getUtility(IStoreSelector).get(
515- ... MAIN_STORE, MASTER_FLAVOR)
516+ ... MAIN_STORE, PRIMARY_FLAVOR)
517 ... time_travel(config.database.db_statement_timeout +
518 ... config.database.db_statement_timeout_precision)
519 ... store.execute('SELECT TRUE', noresult=True)
520@@ -63,7 +63,7 @@ exception, and a time machine.
521 ... def __call__(self):
522 ... global timeout_in_exception_view
523 ... store = zope.component.getUtility(IStoreSelector).get(
524- ... MAIN_STORE, MASTER_FLAVOR)
525+ ... MAIN_STORE, PRIMARY_FLAVOR)
526 ... try:
527 ... store.execute('SELECT TRUE', noresult=True)
528 ... except TimeoutError:
529diff --git a/lib/lp/services/webapp/publication.py b/lib/lp/services/webapp/publication.py
530index 717cc65..27c29d4 100644
531--- a/lib/lp/services/webapp/publication.py
532+++ b/lib/lp/services/webapp/publication.py
533@@ -75,7 +75,7 @@ from lp.services.config import config
534 from lp.services.database.interfaces import (
535 IDatabasePolicy,
536 IStoreSelector,
537- MASTER_FLAVOR,
538+ PRIMARY_FLAVOR,
539 )
540 from lp.services.database.policy import LaunchpadDatabasePolicy
541 from lp.services.features.flags import NullFeatureController
542@@ -707,10 +707,10 @@ class LaunchpadBrowserPublication(
543 # used is a replica, raise a Retry exception instead of
544 # returning the 404 error page. We do this in case the
545 # LookupError is caused by replication lag. Our database
546- # policy forces the use of the master database for retries.
547+ # policy forces the use of the primary database for retries.
548 if (isinstance(exc_info[1], LookupError)
549 and isinstance(db_policy, LaunchpadDatabasePolicy)):
550- if db_policy.default_flavor == MASTER_FLAVOR:
551+ if db_policy.default_flavor == PRIMARY_FLAVOR:
552 return False
553 else:
554 return True
555@@ -861,9 +861,9 @@ class LaunchpadBrowserPublication(
556 # Reset all Storm stores when not running the test suite.
557 # We could reset them when running the test suite but
558 # that'd make writing tests a much more painful task. We
559- # still reset the slave stores though to minimize stale
560+ # still reset the standby stores though to minimize stale
561 # cache issues.
562- if thread_name != 'MainThread' or name.endswith('-slave'):
563+ if thread_name != 'MainThread' or name.endswith('-standby'):
564 store.reset()
565
566
567diff --git a/lib/lp/services/webapp/tests/test_dbpolicy.py b/lib/lp/services/webapp/tests/test_dbpolicy.py
568index a8eac12..b47c3ba 100644
569--- a/lib/lp/services/webapp/tests/test_dbpolicy.py
570+++ b/lib/lp/services/webapp/tests/test_dbpolicy.py
571@@ -39,8 +39,8 @@ from lp.services.database.interfaces import (
572 ISlaveStore,
573 IStoreSelector,
574 MAIN_STORE,
575- MASTER_FLAVOR,
576- SLAVE_FLAVOR,
577+ PRIMARY_FLAVOR,
578+ STANDBY_FLAVOR,
579 )
580 from lp.services.database.policy import (
581 BaseDatabasePolicy,
582@@ -112,10 +112,10 @@ class StandbyDatabasePolicyTestCase(BaseDatabasePolicyTestCase):
583 getUtility(IStoreSelector).get(store, DEFAULT_FLAVOR),
584 ISlaveStore)
585
586- def test_master_allowed(self):
587+ def test_primary_allowed(self):
588 for store in ALL_STORES:
589 self.assertProvides(
590- getUtility(IStoreSelector).get(store, MASTER_FLAVOR),
591+ getUtility(IStoreSelector).get(store, PRIMARY_FLAVOR),
592 IMasterStore)
593
594
595@@ -126,11 +126,11 @@ class StandbyOnlyDatabasePolicyTestCase(StandbyDatabasePolicyTestCase):
596 self.policy = StandbyOnlyDatabasePolicy()
597 super().setUp()
598
599- def test_master_allowed(self):
600+ def test_primary_allowed(self):
601 for store in ALL_STORES:
602 self.assertRaises(
603 DisallowedStore,
604- getUtility(IStoreSelector).get, store, MASTER_FLAVOR)
605+ getUtility(IStoreSelector).get, store, PRIMARY_FLAVOR)
606
607
608 class PrimaryDatabasePolicyTestCase(BaseDatabasePolicyTestCase):
609@@ -156,7 +156,7 @@ class PrimaryDatabasePolicyTestCase(BaseDatabasePolicyTestCase):
610 # We get the primary store even if the standby was requested.
611 for store in ALL_STORES:
612 self.assertProvides(
613- getUtility(IStoreSelector).get(store, SLAVE_FLAVOR),
614+ getUtility(IStoreSelector).get(store, STANDBY_FLAVOR),
615 ISlaveStore)
616
617
618@@ -235,11 +235,11 @@ class LayerDatabasePolicyTestCase(TestCase):
619 self.assertIsInstance(policy, LaunchpadDatabasePolicy)
620
621
622-class MasterFallbackTestCase(TestCase):
623+class PrimaryFallbackTestCase(TestCase):
624 layer = DatabaseFunctionalLayer
625
626 def setUp(self):
627- super(MasterFallbackTestCase, self).setUp()
628+ super().setUp()
629
630 self.pgbouncer_fixture = PGBouncerFixture()
631
632@@ -264,7 +264,7 @@ class MasterFallbackTestCase(TestCase):
633
634 self.useFixture(self.pgbouncer_fixture)
635
636- def test_can_shutdown_slave_only(self):
637+ def test_can_shutdown_standby_only(self):
638 '''Confirm that this TestCase's test infrastructure works as needed.
639 '''
640 master_store = IMasterStore(Person)
641@@ -280,8 +280,8 @@ class MasterFallbackTestCase(TestCase):
642 master_store.get(Person, 2)
643 self.assertRaises(DisconnectionError, slave_store.get, Person, 2)
644
645- def test_startup_with_no_slave(self):
646- '''An attempt is made for the first time to connect to a slave.'''
647+ def test_startup_with_no_standby(self):
648+ '''An attempt is made for the first time to connect to a standby.'''
649 self.pgbouncer_fixture.stop()
650
651 master_store = IMasterStore(Person)
652@@ -290,8 +290,8 @@ class MasterFallbackTestCase(TestCase):
653 # The master and slave Stores are the same object.
654 self.assertIs(master_store, slave_store)
655
656- def test_slave_shutdown_during_transaction(self):
657- '''Slave is shutdown while running, but we can recover.'''
658+ def test_standby_shutdown_during_transaction(self):
659+ '''Standby is shutdown while running, but we can recover.'''
660 master_store = IMasterStore(Person)
661 slave_store = ISlaveStore(Person)
662
663@@ -313,8 +313,8 @@ class MasterFallbackTestCase(TestCase):
664
665 self.assertIs(master_store, slave_store)
666
667- def test_slave_shutdown_between_transactions(self):
668- '''Slave is shutdown in between transactions.'''
669+ def test_standby_shutdown_between_transactions(self):
670+ '''Standby is shutdown in between transactions.'''
671 master_store = IMasterStore(Person)
672 slave_store = ISlaveStore(Person)
673 self.assertIsNot(master_store, slave_store)
674@@ -322,8 +322,8 @@ class MasterFallbackTestCase(TestCase):
675 transaction.abort()
676 self.pgbouncer_fixture.stop()
677
678- # The process doesn't notice the slave going down, and things
679- # will fail the next time the slave is used.
680+ # The process doesn't notice the standby going down, and things
681+ # will fail the next time the standby is used.
682 master_store = IMasterStore(Person)
683 slave_store = ISlaveStore(Person)
684 self.assertIsNot(master_store, slave_store)
685@@ -336,8 +336,8 @@ class MasterFallbackTestCase(TestCase):
686 slave_store = ISlaveStore(Person)
687 self.assertIs(master_store, slave_store)
688
689- def test_slave_reconnect_after_outage(self):
690- '''The slave is again used once it becomes available.'''
691+ def test_standby_reconnect_after_outage(self):
692+ '''The standby is again used once it becomes available.'''
693 self.pgbouncer_fixture.stop()
694
695 master_store = IMasterStore(Person)
696@@ -391,54 +391,54 @@ class TestFastDowntimeRollout(TestCase):
697 except DisconnectionError:
698 return False
699
700- def store_is_slave(self, store):
701- return store.get_database().name == 'main-slave'
702+ def store_is_standby(self, store):
703+ return store.get_database().name == 'main-standby'
704
705- def store_is_master(self, store):
706- return not self.store_is_slave(store)
707+ def store_is_primary(self, store):
708+ return not self.store_is_standby(store)
709
710- def test_slave_only_fast_downtime_rollout(self):
711- '''You can always access a working slave store during fast downtime.
712+ def test_standby_only_fast_downtime_rollout(self):
713+ '''You can always access a working standby store during fast downtime.
714 '''
715 # Everything is running happily.
716 store = ISlaveStore(Person)
717 original_store = store
718 self.assertTrue(self.store_is_working(store))
719- self.assertTrue(self.store_is_slave(store))
720+ self.assertTrue(self.store_is_standby(store))
721
722 # But fast downtime is about to happen.
723
724- # Replication is stopped on the slave, and lag starts
725+ # Replication is stopped on the standby, and lag starts
726 # increasing.
727
728- # All connections to the master are killed so database schema
729+ # All connections to the primary are killed so database schema
730 # updates can be applied.
731 self.pgbouncer_cur.execute('DISABLE %s' % self.primary_dbname)
732 self.pgbouncer_cur.execute('KILL %s' % self.primary_dbname)
733
734- # Of course, slave connections are unaffected.
735+ # Of course, standby connections are unaffected.
736 self.assertTrue(self.store_is_working(store))
737
738- # After schema updates have been made to the master, it is
739+ # After schema updates have been made to the primary, it is
740 # reenabled.
741 self.pgbouncer_cur.execute('RESUME %s' % self.primary_dbname)
742 self.pgbouncer_cur.execute('ENABLE %s' % self.primary_dbname)
743
744- # And the slaves taken down, and replication reenabled so the
745+ # And the standbys taken down, and replication reenabled so the
746 # schema updates can replicate.
747 self.pgbouncer_cur.execute('DISABLE %s' % self.standby_dbname)
748 self.pgbouncer_cur.execute('KILL %s' % self.standby_dbname)
749
750- # The next attempt at accessing the slave store will fail
751+ # The next attempt at accessing the standby store will fail
752 # with a DisconnectionError.
753 self.assertRaises(DisconnectionError, store.execute, 'SELECT TRUE')
754 transaction.abort()
755
756 # But if we handle that and retry, we can continue.
757 # Now the failed connection has been detected, the next Store
758- # we are handed is a master Store instead of a slave.
759+ # we are handed is a primary Store instead of a standby.
760 store = ISlaveStore(Person)
761- self.assertTrue(self.store_is_master(store))
762+ self.assertTrue(self.store_is_primary(store))
763 self.assertIsNot(ISlaveStore(Person), original_store)
764
765 # But alas, it might not work the first transaction. If it has
766@@ -447,10 +447,10 @@ class TestFastDowntimeRollout(TestCase):
767 self.assertFalse(self.store_is_working(store))
768 transaction.abort()
769
770- # Next retry attempt, everything is fine using the master
771- # connection, even though our code only asked for a slave.
772+ # Next retry attempt, everything is fine using the primary
773+ # connection, even though our code only asked for a standby.
774 store = ISlaveStore(Person)
775- self.assertTrue(self.store_is_master(store))
776+ self.assertTrue(self.store_is_primary(store))
777 self.assertTrue(self.store_is_working(store))
778
779 # The original Store is busted though. You cannot reuse Stores
780@@ -459,85 +459,85 @@ class TestFastDowntimeRollout(TestCase):
781 self.assertFalse(self.store_is_working(original_store))
782 transaction.abort()
783
784- # Once replication has caught up, the slave is reenabled.
785+ # Once replication has caught up, the standby is reenabled.
786 self.pgbouncer_cur.execute('RESUME %s' % self.standby_dbname)
787 self.pgbouncer_cur.execute('ENABLE %s' % self.standby_dbname)
788
789 # And next transaction, we are back to normal.
790 store = ISlaveStore(Person)
791 self.assertTrue(self.store_is_working(store))
792- self.assertTrue(self.store_is_slave(store))
793+ self.assertTrue(self.store_is_standby(store))
794 self.assertIs(original_store, store)
795
796- def test_master_slave_fast_downtime_rollout(self):
797+ def test_primary_standby_fast_downtime_rollout(self):
798 '''Parts of your app can keep working during a fast downtime update.
799 '''
800 # Everything is running happily.
801 master_store = IMasterStore(Person)
802- self.assertTrue(self.store_is_master(master_store))
803+ self.assertTrue(self.store_is_primary(master_store))
804 self.assertTrue(self.store_is_working(master_store))
805
806 slave_store = ISlaveStore(Person)
807- self.assertTrue(self.store_is_slave(slave_store))
808+ self.assertTrue(self.store_is_standby(slave_store))
809 self.assertTrue(self.store_is_working(slave_store))
810
811 # But fast downtime is about to happen.
812
813- # Replication is stopped on the slave, and lag starts
814+ # Replication is stopped on the standby, and lag starts
815 # increasing.
816
817- # All connections to the master are killed so database schema
818+ # All connections to the primary are killed so database schema
819 # updates can be applied.
820 self.pgbouncer_cur.execute('DISABLE %s' % self.primary_dbname)
821 self.pgbouncer_cur.execute('KILL %s' % self.primary_dbname)
822
823- # Of course, slave connections are unaffected.
824+ # Of course, standby connections are unaffected.
825 self.assertTrue(self.store_is_working(slave_store))
826
827- # But attempts to use a master store will fail.
828+ # But attempts to use a primary store will fail.
829 self.assertFalse(self.store_is_working(master_store))
830 transaction.abort()
831
832- # After schema updates have been made to the master, it is
833+ # After schema updates have been made to the primary, it is
834 # reenabled.
835 self.pgbouncer_cur.execute('RESUME %s' % self.primary_dbname)
836 self.pgbouncer_cur.execute('ENABLE %s' % self.primary_dbname)
837
838- # And the slaves taken down, and replication reenabled so the
839+ # And the standbys taken down, and replication reenabled so the
840 # schema updates can replicate.
841 self.pgbouncer_cur.execute('DISABLE %s' % self.standby_dbname)
842 self.pgbouncer_cur.execute('KILL %s' % self.standby_dbname)
843
844- # The master store is working again.
845+ # The primary store is working again.
846 master_store = IMasterStore(Person)
847- self.assertTrue(self.store_is_master(master_store))
848+ self.assertTrue(self.store_is_primary(master_store))
849 self.assertTrue(self.store_is_working(master_store))
850
851- # The next attempt at accessing the slave store will fail
852+ # The next attempt at accessing the standby store will fail
853 # with a DisconnectionError.
854 slave_store = ISlaveStore(Person)
855- self.assertTrue(self.store_is_slave(slave_store))
856+ self.assertTrue(self.store_is_standby(slave_store))
857 self.assertRaises(
858 DisconnectionError, slave_store.execute, 'SELECT TRUE')
859 transaction.abort()
860
861 # But if we handle that and retry, we can continue.
862 # Now the failed connection has been detected, the next Store
863- # we are handed is a master Store instead of a slave.
864+ # we are handed is a primary Store instead of a standby.
865 slave_store = ISlaveStore(Person)
866- self.assertTrue(self.store_is_master(slave_store))
867+ self.assertTrue(self.store_is_primary(slave_store))
868 self.assertTrue(self.store_is_working(slave_store))
869
870- # Once replication has caught up, the slave is reenabled.
871+ # Once replication has caught up, the standby is reenabled.
872 self.pgbouncer_cur.execute('RESUME %s' % self.standby_dbname)
873 self.pgbouncer_cur.execute('ENABLE %s' % self.standby_dbname)
874
875 # And next transaction, we are back to normal.
876 transaction.abort()
877 master_store = IMasterStore(Person)
878- self.assertTrue(self.store_is_master(master_store))
879+ self.assertTrue(self.store_is_primary(master_store))
880 self.assertTrue(self.store_is_working(master_store))
881
882 slave_store = ISlaveStore(Person)
883- self.assertTrue(self.store_is_slave(slave_store))
884+ self.assertTrue(self.store_is_standby(slave_store))
885 self.assertTrue(self.store_is_working(slave_store))

Subscribers

People subscribed via source and target branches

to status/vote changes: