Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(386)

Side by Side Diff: chrome/browser/in_process_webkit/indexed_db_key_utility_client.cc

Issue 6209005: Fix IndexedDB race condition during shutdown. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Addressing Marcus's comments Created 9 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/in_process_webkit/indexed_db_key_utility_client.h" 5 #include "chrome/browser/in_process_webkit/indexed_db_key_utility_client.h"
6 6
7 #include <vector> 7 #include "base/synchronization/waitable_event.h"
8
9 #include "chrome/browser/browser_process.h" 8 #include "chrome/browser/browser_process.h"
9 #include "chrome/browser/utility_process_host.h"
10 #include "chrome/common/indexed_db_key.h" 10 #include "chrome/common/indexed_db_key.h"
11 #include "chrome/common/serialized_script_value.h" 11 #include "chrome/common/serialized_script_value.h"
12 12
13 // This class is used to obtain IndexedDBKeys from the SerializedScriptValues
jorlow1 2011/01/21 09:33:00 no the
hans 2011/01/21 11:27:55 Done.
14 // given an IDBKeyPath. It uses UtilityProcess to do this inside a sandbox
15 // (a V8 lock is required there). At this level, all methods are synchronous
16 // as required by the caller. The public API is used on WEBKIT thread,
17 // but internally it moves around to UI and IO as needed.
18 class KeyUtilityClientImpl
19 : public base::RefCountedThreadSafe<KeyUtilityClientImpl> {
20 public:
21 KeyUtilityClientImpl();
22
23 // Starts the UtilityProcess. Must be called before any other method.
24 void StartUtilityProcess();
25
26 // Stops the UtilityProcess. No further keys can be created after this.
27 void Shutdown();
28
29 // Synchronously obtain the |keys| from |values| for the given |key_path|.
30 void CreateIDBKeysFromSerializedValuesAndKeyPath(
31 const std::vector<SerializedScriptValue>& values,
32 const string16& key_path,
33 std::vector<IndexedDBKey>* keys);
34
35 private:
36 class Client : public UtilityProcessHost::Client {
37 public:
38 explicit Client(KeyUtilityClientImpl* parent);
39
40 // UtilityProcessHost::Client
41 virtual void OnProcessCrashed(int exit_code);
42 virtual void OnIDBKeysFromValuesAndKeyPathSucceeded(
43 int id, const std::vector<IndexedDBKey>& keys);
44 virtual void OnIDBKeysFromValuesAndKeyPathFailed(int id);
45
46 private:
47 KeyUtilityClientImpl* parent_;
48
49 DISALLOW_COPY_AND_ASSIGN(Client);
50 };
51
52 friend class base::RefCountedThreadSafe<KeyUtilityClientImpl>;
53
jorlow1 2011/01/21 09:33:00 extra space?
hans 2011/01/21 11:27:55 Done.
54 ~KeyUtilityClientImpl();
55
jorlow1 2011/01/21 09:33:00 extra space
hans 2011/01/21 11:27:55 Done.
56
57 void GetRDHAndStartUtilityProcess();
58 void StartUtilityProcessInternal(ResourceDispatcherHost* rdh);
59 void EndUtilityProcessInternal();
60 void CallStartIDBKeyFromValueAndKeyPathFromIOThread(
61 const std::vector<SerializedScriptValue>& values,
62 const string16& key_path);
63
64 void SetKeys(const std::vector<IndexedDBKey>& keys);
65 void FinishCreatingKeys();
66
67 base::WaitableEvent waitable_event_;
68
69 // Used in both IO and WEBKIT threads, but guarded by WaitableEvent, i.e.,
70 // these members are only set / read when the other thread is blocked.
71 enum State {
72 STATE_UNINITIALIZED,
73 STATE_INITIALIZED,
74 STATE_CREATING_KEYS,
75 STATE_SHUTDOWN,
76 };
77 State state_;
78 std::vector<IndexedDBKey> keys_;
79
80 // Used in the IO thread.
81 UtilityProcessHost* utility_process_host_;
82 scoped_refptr<Client> client_;
83
84 DISALLOW_COPY_AND_ASSIGN(KeyUtilityClientImpl);
85 };
86
87 // IndexedDBKeyUtilityClient definitions.
88
13 IndexedDBKeyUtilityClient::IndexedDBKeyUtilityClient() 89 IndexedDBKeyUtilityClient::IndexedDBKeyUtilityClient()
90 : is_shutdown_(false) {
91 // Note that creating the impl_ object is deferred until it is first needed,
92 // as this class can be constructed even though it never gets used.
93 }
94
95 IndexedDBKeyUtilityClient::~IndexedDBKeyUtilityClient() { }
jorlow1 2011/01/21 09:33:00 Assert we've been shutdown?
hans 2011/01/21 11:27:55 Done.
96
97 IndexedDBKeyUtilityClient* IndexedDBKeyUtilityClient::GetInstance() {
98 return Singleton<IndexedDBKeyUtilityClient>::get();
jorlow1 2011/01/21 09:33:00 What if we've been shutdown...should we allow this
hans 2011/01/21 11:27:55 Well, we need to somehow get to the instance to ch
jorlow1 2011/01/21 11:39:34 If the io thread is done, the transaction will be
99 }
100
101 void IndexedDBKeyUtilityClient::Shutdown() {
102 if (!impl_)
103 return;
104
105 is_shutdown_ = true;
106 impl_->Shutdown();
107 }
108
109 void IndexedDBKeyUtilityClient::CreateIDBKeysFromSerializedValuesAndKeyPath(
110 const std::vector<SerializedScriptValue>& values,
111 const string16& key_path,
112 std::vector<IndexedDBKey>* keys) {
113 if (is_shutdown_) {
114 keys->clear();
115 return;
116 }
117
118 if (!impl_) {
119 impl_ = new KeyUtilityClientImpl();
120 impl_->StartUtilityProcess();
121 }
122
123 return impl_->CreateIDBKeysFromSerializedValuesAndKeyPath(values, key_path,
124 keys);
125 }
126
127 // KeyUtilityClientImpl definitions.
128
129 void KeyUtilityClientImpl::Shutdown() {
130 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
131
132 utility_process_host_->EndBatchMode();
133 utility_process_host_ = NULL;
134 client_ = NULL;
135 state_ = STATE_SHUTDOWN;
136 }
137
138 KeyUtilityClientImpl::KeyUtilityClientImpl()
14 : waitable_event_(false, false), 139 : waitable_event_(false, false),
15 state_(STATE_UNINITIALIZED), 140 state_(STATE_UNINITIALIZED),
16 utility_process_host_(NULL) { 141 utility_process_host_(NULL) {
17 } 142 }
18 143
19 IndexedDBKeyUtilityClient::~IndexedDBKeyUtilityClient() { 144 KeyUtilityClientImpl::~KeyUtilityClientImpl() {
20 DCHECK(state_ == STATE_UNINITIALIZED || state_ == STATE_SHUTDOWN); 145 DCHECK(state_ == STATE_UNINITIALIZED || state_ == STATE_SHUTDOWN);
21 DCHECK(!utility_process_host_); 146 DCHECK(!utility_process_host_);
22 DCHECK(!client_.get()); 147 DCHECK(!client_.get());
23 } 148 }
24 149
25 void IndexedDBKeyUtilityClient::StartUtilityProcess() { 150 void KeyUtilityClientImpl::StartUtilityProcess() {
26 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); 151 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
27 DCHECK(state_ == STATE_UNINITIALIZED); 152 DCHECK(state_ == STATE_UNINITIALIZED);
28 153
29 GetRDHAndStartUtilityProcess(); 154 GetRDHAndStartUtilityProcess();
30 bool ret = waitable_event_.Wait(); 155 bool ret = waitable_event_.Wait();
31 156
32 DCHECK(ret && state_ == STATE_INITIALIZED); 157 DCHECK(ret && state_ == STATE_INITIALIZED);
33 } 158 }
34 159
35 void IndexedDBKeyUtilityClient::EndUtilityProcess() { 160 void KeyUtilityClientImpl::CreateIDBKeysFromSerializedValuesAndKeyPath(
36 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
37 DCHECK(state_ == STATE_INITIALIZED);
38
39 EndUtilityProcessInternal();
40 bool ret = waitable_event_.Wait();
41
42 DCHECK(ret && state_ == STATE_SHUTDOWN);
43 }
44
45 void IndexedDBKeyUtilityClient::CreateIDBKeysFromSerializedValuesAndKeyPath(
46 const std::vector<SerializedScriptValue>& values, 161 const std::vector<SerializedScriptValue>& values,
47 const string16& key_path, 162 const string16& key_path,
48 std::vector<IndexedDBKey>* keys) { 163 std::vector<IndexedDBKey>* keys) {
49 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); 164 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
165 if (state_ == STATE_SHUTDOWN) {
166 keys->clear();
167 return;
168 }
169
50 DCHECK(state_ == STATE_INITIALIZED); 170 DCHECK(state_ == STATE_INITIALIZED);
51 171
52 state_ = STATE_CREATING_KEYS; 172 state_ = STATE_CREATING_KEYS;
53 CallStartIDBKeyFromValueAndKeyPathFromIOThread(values, key_path); 173 CallStartIDBKeyFromValueAndKeyPathFromIOThread(values, key_path);
54 bool ret = waitable_event_.Wait(); 174 bool ret = waitable_event_.Wait();
55 DCHECK(ret && state_ == STATE_INITIALIZED); 175 DCHECK(ret && state_ == STATE_INITIALIZED);
56 176
57 *keys = keys_; 177 *keys = keys_;
58 } 178 }
59 179
60 void IndexedDBKeyUtilityClient::GetRDHAndStartUtilityProcess() { 180 void KeyUtilityClientImpl::GetRDHAndStartUtilityProcess() {
61 // In order to start the UtilityProcess, we need to grab 181 // In order to start the UtilityProcess, we need to grab
62 // a pointer to the ResourceDispatcherHost. This can only 182 // a pointer to the ResourceDispatcherHost. This can only
63 // be done on the UI thread. See the comment at the top of 183 // be done on the UI thread. See the comment at the top of
64 // browser_process.h 184 // browser_process.h
65 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 185 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
66 BrowserThread::PostTask( 186 BrowserThread::PostTask(
67 BrowserThread::UI, FROM_HERE, 187 BrowserThread::UI, FROM_HERE,
68 NewRunnableMethod( 188 NewRunnableMethod(
69 this, 189 this,
70 &IndexedDBKeyUtilityClient::GetRDHAndStartUtilityProcess)); 190 &KeyUtilityClientImpl::GetRDHAndStartUtilityProcess));
71 return; 191 return;
72 } 192 }
73 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 193 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
74 StartUtilityProcessInternal(g_browser_process->resource_dispatcher_host()); 194 StartUtilityProcessInternal(g_browser_process->resource_dispatcher_host());
75 } 195 }
76 196
77 void IndexedDBKeyUtilityClient::StartUtilityProcessInternal( 197 void KeyUtilityClientImpl::StartUtilityProcessInternal(
78 ResourceDispatcherHost* rdh) { 198 ResourceDispatcherHost* rdh) {
79 DCHECK(rdh); 199 DCHECK(rdh);
80 // The ResourceDispatcherHost can only be used on the IO thread. 200 // The ResourceDispatcherHost can only be used on the IO thread.
81 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { 201 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
82 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 202 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
83 BrowserThread::PostTask( 203 BrowserThread::PostTask(
84 BrowserThread::IO, FROM_HERE, 204 BrowserThread::IO, FROM_HERE,
85 NewRunnableMethod( 205 NewRunnableMethod(
86 this, 206 this,
87 &IndexedDBKeyUtilityClient::StartUtilityProcessInternal, 207 &KeyUtilityClientImpl::StartUtilityProcessInternal,
88 rdh)); 208 rdh));
89 return; 209 return;
90 } 210 }
91 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 211 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
92 DCHECK(state_ == STATE_UNINITIALIZED); 212 DCHECK(state_ == STATE_UNINITIALIZED);
93 213
94 client_ = new IndexedDBKeyUtilityClient::Client(this); 214 client_ = new KeyUtilityClientImpl::Client(this);
95 utility_process_host_ = new UtilityProcessHost( 215 utility_process_host_ = new UtilityProcessHost(
96 rdh, client_.get(), BrowserThread::IO); 216 rdh, client_.get(), BrowserThread::IO);
97 utility_process_host_->StartBatchMode(); 217 utility_process_host_->StartBatchMode();
98 state_ = STATE_INITIALIZED; 218 state_ = STATE_INITIALIZED;
99 waitable_event_.Signal(); 219 waitable_event_.Signal();
100 } 220 }
101 221
102 void IndexedDBKeyUtilityClient::EndUtilityProcessInternal() { 222 void KeyUtilityClientImpl::EndUtilityProcessInternal() {
103 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { 223 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
104 BrowserThread::PostTask( 224 BrowserThread::PostTask(
105 BrowserThread::IO, FROM_HERE, 225 BrowserThread::IO, FROM_HERE,
106 NewRunnableMethod( 226 NewRunnableMethod(
107 this, 227 this,
108 &IndexedDBKeyUtilityClient::EndUtilityProcessInternal)); 228 &KeyUtilityClientImpl::EndUtilityProcessInternal));
109 return; 229 return;
110 } 230 }
111 231
112 utility_process_host_->EndBatchMode(); 232 utility_process_host_->EndBatchMode();
113 utility_process_host_ = NULL; 233 utility_process_host_ = NULL;
114 client_ = NULL; 234 client_ = NULL;
115 state_ = STATE_SHUTDOWN; 235 state_ = STATE_SHUTDOWN;
116 waitable_event_.Signal(); 236 waitable_event_.Signal();
117 } 237 }
118 238
119 void IndexedDBKeyUtilityClient::CallStartIDBKeyFromValueAndKeyPathFromIOThread( 239 void KeyUtilityClientImpl::CallStartIDBKeyFromValueAndKeyPathFromIOThread(
120 const std::vector<SerializedScriptValue>& values, 240 const std::vector<SerializedScriptValue>& values,
121 const string16& key_path) { 241 const string16& key_path) {
122 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { 242 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
123 BrowserThread::PostTask( 243 BrowserThread::PostTask(
124 BrowserThread::IO, FROM_HERE, 244 BrowserThread::IO, FROM_HERE,
125 NewRunnableMethod(this, 245 NewRunnableMethod(this,
126 &IndexedDBKeyUtilityClient:: 246 &KeyUtilityClientImpl::
127 CallStartIDBKeyFromValueAndKeyPathFromIOThread, 247 CallStartIDBKeyFromValueAndKeyPathFromIOThread,
128 values, key_path)); 248 values, key_path));
129 return; 249 return;
130 } 250 }
131 251
132 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 252 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
133 utility_process_host_->StartIDBKeysFromValuesAndKeyPath( 253 utility_process_host_->StartIDBKeysFromValuesAndKeyPath(
134 0, values, key_path); 254 0, values, key_path);
135 } 255 }
136 256
137 void IndexedDBKeyUtilityClient::SetKeys(const std::vector<IndexedDBKey>& keys) { 257 void KeyUtilityClientImpl::SetKeys(const std::vector<IndexedDBKey>& keys) {
138 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 258 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
139 keys_ = keys; 259 keys_ = keys;
140 } 260 }
141 261
142 void IndexedDBKeyUtilityClient::FinishCreatingKeys() { 262 void KeyUtilityClientImpl::FinishCreatingKeys() {
143 DCHECK(state_ == STATE_CREATING_KEYS); 263 DCHECK(state_ == STATE_CREATING_KEYS);
144 state_ = STATE_INITIALIZED; 264 state_ = STATE_INITIALIZED;
145 waitable_event_.Signal(); 265 waitable_event_.Signal();
146 } 266 }
147 267
148 IndexedDBKeyUtilityClient::Client::Client(IndexedDBKeyUtilityClient* parent) 268 KeyUtilityClientImpl::Client::Client(KeyUtilityClientImpl* parent)
149 : parent_(parent) { 269 : parent_(parent) {
150 } 270 }
151 271
152 void IndexedDBKeyUtilityClient::Client::OnProcessCrashed(int exit_code) { 272 void KeyUtilityClientImpl::Client::OnProcessCrashed(int exit_code) {
153 if (parent_->state_ == STATE_CREATING_KEYS) 273 if (parent_->state_ == STATE_CREATING_KEYS)
154 parent_->FinishCreatingKeys(); 274 parent_->FinishCreatingKeys();
155 } 275 }
156 276
157 void IndexedDBKeyUtilityClient::Client::OnIDBKeysFromValuesAndKeyPathSucceeded( 277 void KeyUtilityClientImpl::Client::OnIDBKeysFromValuesAndKeyPathSucceeded(
158 int id, const std::vector<IndexedDBKey>& keys) { 278 int id, const std::vector<IndexedDBKey>& keys) {
159 parent_->SetKeys(keys); 279 parent_->SetKeys(keys);
160 parent_->FinishCreatingKeys(); 280 parent_->FinishCreatingKeys();
161 } 281 }
162 282
163 void IndexedDBKeyUtilityClient::Client::OnIDBKeysFromValuesAndKeyPathFailed( 283 void KeyUtilityClientImpl::Client::OnIDBKeysFromValuesAndKeyPathFailed(
164 int id) { 284 int id) {
165 parent_->FinishCreatingKeys(); 285 parent_->FinishCreatingKeys();
166 } 286 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698