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

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: Singleton wrapper approach 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
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
22 // Synchronously obtain the |keys| from |values| for the given |key_path|.
23 void CreateIDBKeysFromSerializedValuesAndKeyPath(
24 const std::vector<SerializedScriptValue>& values,
25 const string16& key_path,
26 std::vector<IndexedDBKey>* keys);
27
28 private:
29 class Client : public UtilityProcessHost::Client {
30 public:
31 explicit Client(KeyUtilityClientImpl* parent);
32
33 // UtilityProcessHost::Client
34 virtual void OnProcessCrashed(int exit_code);
35 virtual void OnIDBKeysFromValuesAndKeyPathSucceeded(
36 int id, const std::vector<IndexedDBKey>& keys);
37 virtual void OnIDBKeysFromValuesAndKeyPathFailed(int id);
38
39 private:
40 KeyUtilityClientImpl* parent_;
41
42 DISALLOW_COPY_AND_ASSIGN(Client);
43 };
44
45 friend class base::RefCountedThreadSafe<KeyUtilityClientImpl>;
46 friend class IndexedDBKeyUtilityClient;
bulach 2011/01/20 16:49:15 perhaps remove the friendship and just publish the
hans 2011/01/20 17:24:59 Done.
47 KeyUtilityClientImpl();
48 ~KeyUtilityClientImpl();
49
50 // Starts the UtilityProcess. Must be called before any other method.
51 void StartUtilityProcess();
52
53 // Stops the UtilityProcess. No further keys can be created after this.
54 void Shutdown();
55
56 void GetRDHAndStartUtilityProcess();
57 void StartUtilityProcessInternal(ResourceDispatcherHost* rdh);
58 void EndUtilityProcessInternal();
59 void CallStartIDBKeyFromValueAndKeyPathFromIOThread(
60 const std::vector<SerializedScriptValue>& values,
61 const string16& key_path);
62
63 void SetKeys(const std::vector<IndexedDBKey>& keys);
64 void FinishCreatingKeys();
65
66 base::WaitableEvent waitable_event_;
67
68 // Used in both IO and WEBKIT threads, but guarded by WaitableEvent, i.e.,
69 // these members are only set / read when the other thread is blocked.
70 enum State {
71 STATE_UNINITIALIZED,
72 STATE_INITIALIZED,
73 STATE_CREATING_KEYS,
74 STATE_SHUTDOWN,
75 };
76 State state_;
77 std::vector<IndexedDBKey> keys_;
78
79 // Used in the IO thread.
80 UtilityProcessHost* utility_process_host_;
81 scoped_refptr<Client> client_;
82
83 DISALLOW_COPY_AND_ASSIGN(KeyUtilityClientImpl);
84 };
85
86 // IndexedDBKeyUtilityClient definitions.
87
13 IndexedDBKeyUtilityClient::IndexedDBKeyUtilityClient() 88 IndexedDBKeyUtilityClient::IndexedDBKeyUtilityClient()
89 : is_shutdown_(false) {
90 }
91
92 IndexedDBKeyUtilityClient::~IndexedDBKeyUtilityClient() { }
93
94 IndexedDBKeyUtilityClient* IndexedDBKeyUtilityClient::GetInstance() {
95 return Singleton<IndexedDBKeyUtilityClient>::get();
96 }
97
98 void IndexedDBKeyUtilityClient::Shutdown() {
99 if (!impl_)
100 return;
101
102 impl_->Shutdown();
103 is_shutdown_ = true;
bulach 2011/01/20 16:49:15 maybe swap the order?
hans 2011/01/20 17:24:59 Done.
104 }
105
106 void IndexedDBKeyUtilityClient::CreateIDBKeysFromSerializedValuesAndKeyPath(
107 const std::vector<SerializedScriptValue>& values,
108 const string16& key_path,
109 std::vector<IndexedDBKey>* keys) {
110 if (is_shutdown_) {
111 keys->clear();
112 return;
113 }
114
115 if (!impl_) {
116 impl_ = new KeyUtilityClientImpl();
117 impl_->StartUtilityProcess();
118 }
119
120 return impl_->CreateIDBKeysFromSerializedValuesAndKeyPath(values, key_path,
121 keys);
122 }
123
124 // KeyUtilityClientImpl definitions.
125
126 void KeyUtilityClientImpl::Shutdown() {
127 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
128
129 utility_process_host_->EndBatchMode();
130 utility_process_host_ = NULL;
131 client_ = NULL;
132 state_ = STATE_SHUTDOWN;
133 }
134
135 KeyUtilityClientImpl::KeyUtilityClientImpl()
14 : waitable_event_(false, false), 136 : waitable_event_(false, false),
15 state_(STATE_UNINITIALIZED), 137 state_(STATE_UNINITIALIZED),
16 utility_process_host_(NULL) { 138 utility_process_host_(NULL) {
17 } 139 }
18 140
19 IndexedDBKeyUtilityClient::~IndexedDBKeyUtilityClient() { 141 KeyUtilityClientImpl::~KeyUtilityClientImpl() {
20 DCHECK(state_ == STATE_UNINITIALIZED || state_ == STATE_SHUTDOWN); 142 DCHECK(state_ == STATE_UNINITIALIZED || state_ == STATE_SHUTDOWN);
21 DCHECK(!utility_process_host_); 143 DCHECK(!utility_process_host_);
22 DCHECK(!client_.get()); 144 DCHECK(!client_.get());
23 } 145 }
24 146
25 void IndexedDBKeyUtilityClient::StartUtilityProcess() { 147 void KeyUtilityClientImpl::StartUtilityProcess() {
26 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); 148 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
27 DCHECK(state_ == STATE_UNINITIALIZED); 149 DCHECK(state_ == STATE_UNINITIALIZED);
28 150
29 GetRDHAndStartUtilityProcess(); 151 GetRDHAndStartUtilityProcess();
30 bool ret = waitable_event_.Wait(); 152 bool ret = waitable_event_.Wait();
31 153
32 DCHECK(ret && state_ == STATE_INITIALIZED); 154 DCHECK(ret && state_ == STATE_INITIALIZED);
33 } 155 }
34 156
35 void IndexedDBKeyUtilityClient::EndUtilityProcess() { 157 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, 158 const std::vector<SerializedScriptValue>& values,
47 const string16& key_path, 159 const string16& key_path,
48 std::vector<IndexedDBKey>* keys) { 160 std::vector<IndexedDBKey>* keys) {
49 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); 161 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
162 if (state_ == STATE_SHUTDOWN) {
163 keys->clear();
164 return;
165 }
166
50 DCHECK(state_ == STATE_INITIALIZED); 167 DCHECK(state_ == STATE_INITIALIZED);
51 168
52 state_ = STATE_CREATING_KEYS; 169 state_ = STATE_CREATING_KEYS;
53 CallStartIDBKeyFromValueAndKeyPathFromIOThread(values, key_path); 170 CallStartIDBKeyFromValueAndKeyPathFromIOThread(values, key_path);
54 bool ret = waitable_event_.Wait(); 171 bool ret = waitable_event_.Wait();
55 DCHECK(ret && state_ == STATE_INITIALIZED); 172 DCHECK(ret && state_ == STATE_INITIALIZED);
56 173
57 *keys = keys_; 174 *keys = keys_;
58 } 175 }
59 176
60 void IndexedDBKeyUtilityClient::GetRDHAndStartUtilityProcess() { 177 void KeyUtilityClientImpl::GetRDHAndStartUtilityProcess() {
61 // In order to start the UtilityProcess, we need to grab 178 // In order to start the UtilityProcess, we need to grab
62 // a pointer to the ResourceDispatcherHost. This can only 179 // a pointer to the ResourceDispatcherHost. This can only
63 // be done on the UI thread. See the comment at the top of 180 // be done on the UI thread. See the comment at the top of
64 // browser_process.h 181 // browser_process.h
65 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 182 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
66 BrowserThread::PostTask( 183 BrowserThread::PostTask(
67 BrowserThread::UI, FROM_HERE, 184 BrowserThread::UI, FROM_HERE,
68 NewRunnableMethod( 185 NewRunnableMethod(
69 this, 186 this,
70 &IndexedDBKeyUtilityClient::GetRDHAndStartUtilityProcess)); 187 &KeyUtilityClientImpl::GetRDHAndStartUtilityProcess));
71 return; 188 return;
72 } 189 }
73 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 190 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
74 StartUtilityProcessInternal(g_browser_process->resource_dispatcher_host()); 191 StartUtilityProcessInternal(g_browser_process->resource_dispatcher_host());
75 } 192 }
76 193
77 void IndexedDBKeyUtilityClient::StartUtilityProcessInternal( 194 void KeyUtilityClientImpl::StartUtilityProcessInternal(
78 ResourceDispatcherHost* rdh) { 195 ResourceDispatcherHost* rdh) {
79 DCHECK(rdh); 196 DCHECK(rdh);
80 // The ResourceDispatcherHost can only be used on the IO thread. 197 // The ResourceDispatcherHost can only be used on the IO thread.
81 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { 198 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
82 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 199 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
83 BrowserThread::PostTask( 200 BrowserThread::PostTask(
84 BrowserThread::IO, FROM_HERE, 201 BrowserThread::IO, FROM_HERE,
85 NewRunnableMethod( 202 NewRunnableMethod(
86 this, 203 this,
87 &IndexedDBKeyUtilityClient::StartUtilityProcessInternal, 204 &KeyUtilityClientImpl::StartUtilityProcessInternal,
88 rdh)); 205 rdh));
89 return; 206 return;
90 } 207 }
91 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 208 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
92 DCHECK(state_ == STATE_UNINITIALIZED); 209 DCHECK(state_ == STATE_UNINITIALIZED);
93 210
94 client_ = new IndexedDBKeyUtilityClient::Client(this); 211 client_ = new KeyUtilityClientImpl::Client(this);
95 utility_process_host_ = new UtilityProcessHost( 212 utility_process_host_ = new UtilityProcessHost(
96 rdh, client_.get(), BrowserThread::IO); 213 rdh, client_.get(), BrowserThread::IO);
97 utility_process_host_->StartBatchMode(); 214 utility_process_host_->StartBatchMode();
98 state_ = STATE_INITIALIZED; 215 state_ = STATE_INITIALIZED;
99 waitable_event_.Signal(); 216 waitable_event_.Signal();
100 } 217 }
101 218
102 void IndexedDBKeyUtilityClient::EndUtilityProcessInternal() { 219 void KeyUtilityClientImpl::EndUtilityProcessInternal() {
103 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { 220 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
104 BrowserThread::PostTask( 221 BrowserThread::PostTask(
105 BrowserThread::IO, FROM_HERE, 222 BrowserThread::IO, FROM_HERE,
106 NewRunnableMethod( 223 NewRunnableMethod(
107 this, 224 this,
108 &IndexedDBKeyUtilityClient::EndUtilityProcessInternal)); 225 &KeyUtilityClientImpl::EndUtilityProcessInternal));
109 return; 226 return;
110 } 227 }
111 228
112 utility_process_host_->EndBatchMode(); 229 utility_process_host_->EndBatchMode();
113 utility_process_host_ = NULL; 230 utility_process_host_ = NULL;
114 client_ = NULL; 231 client_ = NULL;
115 state_ = STATE_SHUTDOWN; 232 state_ = STATE_SHUTDOWN;
116 waitable_event_.Signal(); 233 waitable_event_.Signal();
117 } 234 }
118 235
119 void IndexedDBKeyUtilityClient::CallStartIDBKeyFromValueAndKeyPathFromIOThread( 236 void KeyUtilityClientImpl::CallStartIDBKeyFromValueAndKeyPathFromIOThread(
120 const std::vector<SerializedScriptValue>& values, 237 const std::vector<SerializedScriptValue>& values,
121 const string16& key_path) { 238 const string16& key_path) {
122 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { 239 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
123 BrowserThread::PostTask( 240 BrowserThread::PostTask(
124 BrowserThread::IO, FROM_HERE, 241 BrowserThread::IO, FROM_HERE,
125 NewRunnableMethod(this, 242 NewRunnableMethod(this,
126 &IndexedDBKeyUtilityClient:: 243 &KeyUtilityClientImpl::
127 CallStartIDBKeyFromValueAndKeyPathFromIOThread, 244 CallStartIDBKeyFromValueAndKeyPathFromIOThread,
128 values, key_path)); 245 values, key_path));
129 return; 246 return;
130 } 247 }
131 248
132 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 249 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
133 utility_process_host_->StartIDBKeysFromValuesAndKeyPath( 250 utility_process_host_->StartIDBKeysFromValuesAndKeyPath(
134 0, values, key_path); 251 0, values, key_path);
135 } 252 }
136 253
137 void IndexedDBKeyUtilityClient::SetKeys(const std::vector<IndexedDBKey>& keys) { 254 void KeyUtilityClientImpl::SetKeys(const std::vector<IndexedDBKey>& keys) {
138 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 255 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
139 keys_ = keys; 256 keys_ = keys;
140 } 257 }
141 258
142 void IndexedDBKeyUtilityClient::FinishCreatingKeys() { 259 void KeyUtilityClientImpl::FinishCreatingKeys() {
143 DCHECK(state_ == STATE_CREATING_KEYS); 260 DCHECK(state_ == STATE_CREATING_KEYS);
144 state_ = STATE_INITIALIZED; 261 state_ = STATE_INITIALIZED;
145 waitable_event_.Signal(); 262 waitable_event_.Signal();
146 } 263 }
147 264
148 IndexedDBKeyUtilityClient::Client::Client(IndexedDBKeyUtilityClient* parent) 265 KeyUtilityClientImpl::Client::Client(KeyUtilityClientImpl* parent)
149 : parent_(parent) { 266 : parent_(parent) {
150 } 267 }
151 268
152 void IndexedDBKeyUtilityClient::Client::OnProcessCrashed(int exit_code) { 269 void KeyUtilityClientImpl::Client::OnProcessCrashed(int exit_code) {
153 if (parent_->state_ == STATE_CREATING_KEYS) 270 if (parent_->state_ == STATE_CREATING_KEYS)
154 parent_->FinishCreatingKeys(); 271 parent_->FinishCreatingKeys();
155 } 272 }
156 273
157 void IndexedDBKeyUtilityClient::Client::OnIDBKeysFromValuesAndKeyPathSucceeded( 274 void KeyUtilityClientImpl::Client::OnIDBKeysFromValuesAndKeyPathSucceeded(
158 int id, const std::vector<IndexedDBKey>& keys) { 275 int id, const std::vector<IndexedDBKey>& keys) {
159 parent_->SetKeys(keys); 276 parent_->SetKeys(keys);
160 parent_->FinishCreatingKeys(); 277 parent_->FinishCreatingKeys();
161 } 278 }
162 279
163 void IndexedDBKeyUtilityClient::Client::OnIDBKeysFromValuesAndKeyPathFailed( 280 void KeyUtilityClientImpl::Client::OnIDBKeysFromValuesAndKeyPathFailed(
164 int id) { 281 int id) {
165 parent_->FinishCreatingKeys(); 282 parent_->FinishCreatingKeys();
166 } 283 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698