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

Proposed by Stuart Bishop
Status: Merged
Approved by: Gary Poster
Approved revision: no longer in the source branch.
Merged at revision: not available
Proposed branch: lp:~stub/launchpad/replication
Merge into: lp:launchpad
Diff against target: 136 lines
4 files modified
lib/canonical/launchpad/webapp/configure.zcml (+1/-1)
lib/canonical/launchpad/webapp/dbpolicy.py (+33/-13)
lib/canonical/launchpad/webapp/tests/test_dbpolicy.py (+3/-3)
lib/lp/code/stories/webservice/xx-branchmergeproposal.txt (+2/-0)
To merge this branch: bzr merge lp:~stub/launchpad/replication
Reviewer Review Type Date Requested Status
Francis J. Lacoste (community) release-critical Approve
Gary Poster (community) Approve
Review via email: mp+13203@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Stuart Bishop (stub) wrote :

Handle Bug #447453 by getting web service requests to update the last_write value on their session cookie, if they have one.

This is a cherry pick candidate.

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

Also, the web service may remain partially operational during read-only mode.

Revision history for this message
Gary Poster (gary) wrote :

OK, given that on you don't think we are in immediate danger from bug 297052 because of this, I'm cool with just using the master all the time. I think we do need to address that bug soon though.

Thank you!

Gary

review: Approve
Revision history for this message
Francis J. Lacoste (flacoste) :
review: Approve (release-critical)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/canonical/launchpad/webapp/configure.zcml'
--- lib/canonical/launchpad/webapp/configure.zcml 2009-09-11 15:26:11 +0000
+++ lib/canonical/launchpad/webapp/configure.zcml 2009-10-12 09:45:29 +0000
@@ -48,7 +48,7 @@
48 <adapter48 <adapter
49 for="canonical.launchpad.layers.WebServiceLayer"49 for="canonical.launchpad.layers.WebServiceLayer"
50 provides="canonical.launchpad.webapp.interfaces.IDatabasePolicy"50 provides="canonical.launchpad.webapp.interfaces.IDatabasePolicy"
51 factory="canonical.launchpad.webapp.dbpolicy.MasterDatabasePolicy"51 factory="canonical.launchpad.webapp.dbpolicy.WebServiceDatabasePolicyFactory"
52 />52 />
53 <adapter53 <adapter
54 for="canonical.launchpad.layers.FeedsLayer"54 for="canonical.launchpad.layers.FeedsLayer"
5555
=== modified file 'lib/canonical/launchpad/webapp/dbpolicy.py'
--- lib/canonical/launchpad/webapp/dbpolicy.py 2009-08-20 06:42:07 +0000
+++ lib/canonical/launchpad/webapp/dbpolicy.py 2009-10-12 09:45:29 +0000
@@ -162,12 +162,11 @@
162 # The super constructor is a no-op.162 # The super constructor is a no-op.
163 # pylint: disable-msg=W0231163 # pylint: disable-msg=W0231
164 self.request = request164 self.request = request
165
166 def install(self):
167 """See `IDatabasePolicy`."""
168 # Detect if this is a read only request or not.165 # Detect if this is a read only request or not.
169 self.read_only = self.request.method in ['GET', 'HEAD']166 self.read_only = self.request.method in ['GET', 'HEAD']
170167
168 def install(self):
169 """See `IDatabasePolicy`."""
171 default_flavor = None170 default_flavor = None
172171
173 # If this is a Retry attempt, force use of the master database.172 # If this is a Retry attempt, force use of the master database.
@@ -231,16 +230,15 @@
231 else:230 else:
232 session_available = True231 session_available = True
233 if session_available:232 if session_available:
234 # A non-readonly request has been made. Store this fact in the233 # A non-readonly request has been made. Store this fact
235 # session. Precision is hard coded at 1 minute (so we don't234 # in the session. Precision is hard coded at 1 minute
236 # update the timestamp if it is # no more than 1 minute out of235 # (so we don't update the timestamp if it is no more
237 # date to avoid unnecessary and expensive write operations).236 # than 1 minute out of date to avoid unnecessary and
238 # Webservice and XMLRPC clients may not support cookies, so237 # expensive write operations). Feeds are always read
239 # don't mess with their session. Feeds are always read only,238 # only, and since they run over http, browsers won't
240 # and since they run over http, browsers won't send their239 # send their session key that was set over https, so we
241 # session key that was set over https, so we don't want to240 # don't want to access the session which will overwrite
242 # access the session which will overwrite the cookie and log241 # the cookie and log the user out.
243 # the user out.
244 session_data = ISession(self.request)['lp.dbpolicy']242 session_data = ISession(self.request)['lp.dbpolicy']
245 last_write = session_data.get('last_write', None)243 last_write = session_data.get('last_write', None)
246 now = _now()244 now = _now()
@@ -274,6 +272,28 @@
274 "SELECT replication_lag(%d)" % slave_node_id).get_one()[0]272 "SELECT replication_lag(%d)" % slave_node_id).get_one()[0]
275273
276274
275def WebServiceDatabasePolicyFactory(request):
276 """Return the Launchpad IDatabasePolicy for the current appserver state.
277 """
278 if config.launchpad.read_only:
279 return ReadOnlyLaunchpadDatabasePolicy(request)
280 else:
281 return WebServiceDatabasePolicy(request)
282
283
284class WebServiceDatabasePolicy(LaunchpadDatabasePolicy):
285 """Policy for the Launchpad web service.
286
287 XXX StuartBishop 2009-10-12 bug=297052: Because the webservice
288 never offloads requests to slave databases, Launchpad will
289 collapse if the web service becomes popular.
290 """
291 default_flavor = MASTER_FLAVOR
292 def install(self):
293 """See `IDatabasePolicy`."""
294 pass
295
296
277class ReadOnlyLaunchpadDatabasePolicy(BaseDatabasePolicy):297class ReadOnlyLaunchpadDatabasePolicy(BaseDatabasePolicy):
278 """Policy for Launchpad web requests when running in read-only mode.298 """Policy for Launchpad web requests when running in read-only mode.
279299
280300
=== modified file 'lib/canonical/launchpad/webapp/tests/test_dbpolicy.py'
--- lib/canonical/launchpad/webapp/tests/test_dbpolicy.py 2009-07-17 00:26:05 +0000
+++ lib/canonical/launchpad/webapp/tests/test_dbpolicy.py 2009-10-12 09:45:29 +0000
@@ -20,7 +20,7 @@
20from canonical.launchpad.webapp.dbpolicy import (20from canonical.launchpad.webapp.dbpolicy import (
21 BaseDatabasePolicy, LaunchpadDatabasePolicy, MasterDatabasePolicy,21 BaseDatabasePolicy, LaunchpadDatabasePolicy, MasterDatabasePolicy,
22 ReadOnlyLaunchpadDatabasePolicy, SlaveDatabasePolicy,22 ReadOnlyLaunchpadDatabasePolicy, SlaveDatabasePolicy,
23 SlaveOnlyDatabasePolicy)23 SlaveOnlyDatabasePolicy, WebServiceDatabasePolicy)
24from canonical.launchpad.webapp.interfaces import (24from canonical.launchpad.webapp.interfaces import (
25 ALL_STORES, AUTH_STORE, DEFAULT_FLAVOR, DisallowedStore, IDatabasePolicy,25 ALL_STORES, AUTH_STORE, DEFAULT_FLAVOR, DisallowedStore, IDatabasePolicy,
26 IStoreSelector, MAIN_STORE, MASTER_FLAVOR, ReadOnlyModeDisallowedStore,26 IStoreSelector, MAIN_STORE, MASTER_FLAVOR, ReadOnlyModeDisallowedStore,
@@ -157,7 +157,7 @@
157 policy = IDatabasePolicy(request)157 policy = IDatabasePolicy(request)
158 self.assertIsInstance(policy, SlaveOnlyDatabasePolicy)158 self.assertIsInstance(policy, SlaveOnlyDatabasePolicy)
159159
160 def test_WebServiceRequest_uses_MasterDatabasePolicy(self):160 def test_WebServiceRequest_uses_WebServiceDatabasePolicy(self):
161 """WebService requests should always use the master flavor, since161 """WebService requests should always use the master flavor, since
162 it's likely that clients won't support cookies and thus mixing read162 it's likely that clients won't support cookies and thus mixing read
163 and write requests will result in incoherent views of the data.163 and write requests will result in incoherent views of the data.
@@ -171,7 +171,7 @@
171 request = LaunchpadTestRequest(SERVER_URL=server_url)171 request = LaunchpadTestRequest(SERVER_URL=server_url)
172 setFirstLayer(request, WebServiceLayer)172 setFirstLayer(request, WebServiceLayer)
173 policy = IDatabasePolicy(request)173 policy = IDatabasePolicy(request)
174 self.assertIsInstance(policy, MasterDatabasePolicy)174 self.assertIsInstance(policy, WebServiceDatabasePolicy)
175175
176 def test_read_only_mode_uses_ReadOnlyLaunchpadDatabasePolicy(self):176 def test_read_only_mode_uses_ReadOnlyLaunchpadDatabasePolicy(self):
177 config.push('read_only', """177 config.push('read_only', """
178178
=== modified file 'lib/lp/code/stories/webservice/xx-branchmergeproposal.txt'
--- lib/lp/code/stories/webservice/xx-branchmergeproposal.txt 2009-10-05 14:17:48 +0000
+++ lib/lp/code/stories/webservice/xx-branchmergeproposal.txt 2009-10-12 09:45:29 +0000
@@ -213,6 +213,7 @@
213 HTTP/1.1 200 Ok213 HTTP/1.1 200 Ok
214 ...214 ...
215 Content-Type: application/json215 Content-Type: application/json
216 ...
216 Vary: ...217 Vary: ...
217 ...218 ...
218219
@@ -250,6 +251,7 @@
250 HTTP/1.1 200 Ok251 HTTP/1.1 200 Ok
251 ...252 ...
252 Content-Type: application/json253 Content-Type: application/json
254 ...
253 Vary: ...255 Vary: ...
254 ...256 ...
255257