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
1=== modified file 'lib/canonical/launchpad/webapp/configure.zcml'
2--- lib/canonical/launchpad/webapp/configure.zcml 2009-09-11 15:26:11 +0000
3+++ lib/canonical/launchpad/webapp/configure.zcml 2009-10-12 09:45:29 +0000
4@@ -48,7 +48,7 @@
5 <adapter
6 for="canonical.launchpad.layers.WebServiceLayer"
7 provides="canonical.launchpad.webapp.interfaces.IDatabasePolicy"
8- factory="canonical.launchpad.webapp.dbpolicy.MasterDatabasePolicy"
9+ factory="canonical.launchpad.webapp.dbpolicy.WebServiceDatabasePolicyFactory"
10 />
11 <adapter
12 for="canonical.launchpad.layers.FeedsLayer"
13
14=== modified file 'lib/canonical/launchpad/webapp/dbpolicy.py'
15--- lib/canonical/launchpad/webapp/dbpolicy.py 2009-08-20 06:42:07 +0000
16+++ lib/canonical/launchpad/webapp/dbpolicy.py 2009-10-12 09:45:29 +0000
17@@ -162,12 +162,11 @@
18 # The super constructor is a no-op.
19 # pylint: disable-msg=W0231
20 self.request = request
21-
22- def install(self):
23- """See `IDatabasePolicy`."""
24 # Detect if this is a read only request or not.
25 self.read_only = self.request.method in ['GET', 'HEAD']
26
27+ def install(self):
28+ """See `IDatabasePolicy`."""
29 default_flavor = None
30
31 # If this is a Retry attempt, force use of the master database.
32@@ -231,16 +230,15 @@
33 else:
34 session_available = True
35 if session_available:
36- # A non-readonly request has been made. Store this fact in the
37- # session. Precision is hard coded at 1 minute (so we don't
38- # update the timestamp if it is # no more than 1 minute out of
39- # date to avoid unnecessary and expensive write operations).
40- # Webservice and XMLRPC clients may not support cookies, so
41- # don't mess with their session. Feeds are always read only,
42- # and since they run over http, browsers won't send their
43- # session key that was set over https, so we don't want to
44- # access the session which will overwrite the cookie and log
45- # the user out.
46+ # A non-readonly request has been made. Store this fact
47+ # in the session. Precision is hard coded at 1 minute
48+ # (so we don't update the timestamp if it is no more
49+ # than 1 minute out of date to avoid unnecessary and
50+ # expensive write operations). Feeds are always read
51+ # only, and since they run over http, browsers won't
52+ # send their session key that was set over https, so we
53+ # don't want to access the session which will overwrite
54+ # the cookie and log the user out.
55 session_data = ISession(self.request)['lp.dbpolicy']
56 last_write = session_data.get('last_write', None)
57 now = _now()
58@@ -274,6 +272,28 @@
59 "SELECT replication_lag(%d)" % slave_node_id).get_one()[0]
60
61
62+def WebServiceDatabasePolicyFactory(request):
63+ """Return the Launchpad IDatabasePolicy for the current appserver state.
64+ """
65+ if config.launchpad.read_only:
66+ return ReadOnlyLaunchpadDatabasePolicy(request)
67+ else:
68+ return WebServiceDatabasePolicy(request)
69+
70+
71+class WebServiceDatabasePolicy(LaunchpadDatabasePolicy):
72+ """Policy for the Launchpad web service.
73+
74+ XXX StuartBishop 2009-10-12 bug=297052: Because the webservice
75+ never offloads requests to slave databases, Launchpad will
76+ collapse if the web service becomes popular.
77+ """
78+ default_flavor = MASTER_FLAVOR
79+ def install(self):
80+ """See `IDatabasePolicy`."""
81+ pass
82+
83+
84 class ReadOnlyLaunchpadDatabasePolicy(BaseDatabasePolicy):
85 """Policy for Launchpad web requests when running in read-only mode.
86
87
88=== modified file 'lib/canonical/launchpad/webapp/tests/test_dbpolicy.py'
89--- lib/canonical/launchpad/webapp/tests/test_dbpolicy.py 2009-07-17 00:26:05 +0000
90+++ lib/canonical/launchpad/webapp/tests/test_dbpolicy.py 2009-10-12 09:45:29 +0000
91@@ -20,7 +20,7 @@
92 from canonical.launchpad.webapp.dbpolicy import (
93 BaseDatabasePolicy, LaunchpadDatabasePolicy, MasterDatabasePolicy,
94 ReadOnlyLaunchpadDatabasePolicy, SlaveDatabasePolicy,
95- SlaveOnlyDatabasePolicy)
96+ SlaveOnlyDatabasePolicy, WebServiceDatabasePolicy)
97 from canonical.launchpad.webapp.interfaces import (
98 ALL_STORES, AUTH_STORE, DEFAULT_FLAVOR, DisallowedStore, IDatabasePolicy,
99 IStoreSelector, MAIN_STORE, MASTER_FLAVOR, ReadOnlyModeDisallowedStore,
100@@ -157,7 +157,7 @@
101 policy = IDatabasePolicy(request)
102 self.assertIsInstance(policy, SlaveOnlyDatabasePolicy)
103
104- def test_WebServiceRequest_uses_MasterDatabasePolicy(self):
105+ def test_WebServiceRequest_uses_WebServiceDatabasePolicy(self):
106 """WebService requests should always use the master flavor, since
107 it's likely that clients won't support cookies and thus mixing read
108 and write requests will result in incoherent views of the data.
109@@ -171,7 +171,7 @@
110 request = LaunchpadTestRequest(SERVER_URL=server_url)
111 setFirstLayer(request, WebServiceLayer)
112 policy = IDatabasePolicy(request)
113- self.assertIsInstance(policy, MasterDatabasePolicy)
114+ self.assertIsInstance(policy, WebServiceDatabasePolicy)
115
116 def test_read_only_mode_uses_ReadOnlyLaunchpadDatabasePolicy(self):
117 config.push('read_only', """
118
119=== modified file 'lib/lp/code/stories/webservice/xx-branchmergeproposal.txt'
120--- lib/lp/code/stories/webservice/xx-branchmergeproposal.txt 2009-10-05 14:17:48 +0000
121+++ lib/lp/code/stories/webservice/xx-branchmergeproposal.txt 2009-10-12 09:45:29 +0000
122@@ -213,6 +213,7 @@
123 HTTP/1.1 200 Ok
124 ...
125 Content-Type: application/json
126+ ...
127 Vary: ...
128 ...
129
130@@ -250,6 +251,7 @@
131 HTTP/1.1 200 Ok
132 ...
133 Content-Type: application/json
134+ ...
135 Vary: ...
136 ...
137