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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/in_process_webkit/indexed_db_key_utility_client.cc
diff --git a/chrome/browser/in_process_webkit/indexed_db_key_utility_client.cc b/chrome/browser/in_process_webkit/indexed_db_key_utility_client.cc
index f708b43dbf0a670e034299b422838af32ac75437..895b8f34dab8b811b969ae855c7ec56dfce6ebe6 100644
--- a/chrome/browser/in_process_webkit/indexed_db_key_utility_client.cc
+++ b/chrome/browser/in_process_webkit/indexed_db_key_utility_client.cc
@@ -4,25 +4,150 @@
#include "chrome/browser/in_process_webkit/indexed_db_key_utility_client.h"
-#include <vector>
-
+#include "base/synchronization/waitable_event.h"
#include "chrome/browser/browser_process.h"
+#include "chrome/browser/utility_process_host.h"
#include "chrome/common/indexed_db_key.h"
#include "chrome/common/serialized_script_value.h"
+// 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.
+// given an IDBKeyPath. It uses UtilityProcess to do this inside a sandbox
+// (a V8 lock is required there). At this level, all methods are synchronous
+// as required by the caller. The public API is used on WEBKIT thread,
+// but internally it moves around to UI and IO as needed.
+class KeyUtilityClientImpl
+ : public base::RefCountedThreadSafe<KeyUtilityClientImpl> {
+ public:
+ KeyUtilityClientImpl();
+
+ // Starts the UtilityProcess. Must be called before any other method.
+ void StartUtilityProcess();
+
+ // Stops the UtilityProcess. No further keys can be created after this.
+ void Shutdown();
+
+ // Synchronously obtain the |keys| from |values| for the given |key_path|.
+ void CreateIDBKeysFromSerializedValuesAndKeyPath(
+ const std::vector<SerializedScriptValue>& values,
+ const string16& key_path,
+ std::vector<IndexedDBKey>* keys);
+
+ private:
+ class Client : public UtilityProcessHost::Client {
+ public:
+ explicit Client(KeyUtilityClientImpl* parent);
+
+ // UtilityProcessHost::Client
+ virtual void OnProcessCrashed(int exit_code);
+ virtual void OnIDBKeysFromValuesAndKeyPathSucceeded(
+ int id, const std::vector<IndexedDBKey>& keys);
+ virtual void OnIDBKeysFromValuesAndKeyPathFailed(int id);
+
+ private:
+ KeyUtilityClientImpl* parent_;
+
+ DISALLOW_COPY_AND_ASSIGN(Client);
+ };
+
+ friend class base::RefCountedThreadSafe<KeyUtilityClientImpl>;
+
jorlow1 2011/01/21 09:33:00 extra space?
hans 2011/01/21 11:27:55 Done.
+ ~KeyUtilityClientImpl();
+
jorlow1 2011/01/21 09:33:00 extra space
hans 2011/01/21 11:27:55 Done.
+
+ void GetRDHAndStartUtilityProcess();
+ void StartUtilityProcessInternal(ResourceDispatcherHost* rdh);
+ void EndUtilityProcessInternal();
+ void CallStartIDBKeyFromValueAndKeyPathFromIOThread(
+ const std::vector<SerializedScriptValue>& values,
+ const string16& key_path);
+
+ void SetKeys(const std::vector<IndexedDBKey>& keys);
+ void FinishCreatingKeys();
+
+ base::WaitableEvent waitable_event_;
+
+ // Used in both IO and WEBKIT threads, but guarded by WaitableEvent, i.e.,
+ // these members are only set / read when the other thread is blocked.
+ enum State {
+ STATE_UNINITIALIZED,
+ STATE_INITIALIZED,
+ STATE_CREATING_KEYS,
+ STATE_SHUTDOWN,
+ };
+ State state_;
+ std::vector<IndexedDBKey> keys_;
+
+ // Used in the IO thread.
+ UtilityProcessHost* utility_process_host_;
+ scoped_refptr<Client> client_;
+
+ DISALLOW_COPY_AND_ASSIGN(KeyUtilityClientImpl);
+};
+
+// IndexedDBKeyUtilityClient definitions.
+
IndexedDBKeyUtilityClient::IndexedDBKeyUtilityClient()
+ : is_shutdown_(false) {
+ // Note that creating the impl_ object is deferred until it is first needed,
+ // as this class can be constructed even though it never gets used.
+}
+
+IndexedDBKeyUtilityClient::~IndexedDBKeyUtilityClient() { }
jorlow1 2011/01/21 09:33:00 Assert we've been shutdown?
hans 2011/01/21 11:27:55 Done.
+
+IndexedDBKeyUtilityClient* IndexedDBKeyUtilityClient::GetInstance() {
+ 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
+}
+
+void IndexedDBKeyUtilityClient::Shutdown() {
+ if (!impl_)
+ return;
+
+ is_shutdown_ = true;
+ impl_->Shutdown();
+}
+
+void IndexedDBKeyUtilityClient::CreateIDBKeysFromSerializedValuesAndKeyPath(
+ const std::vector<SerializedScriptValue>& values,
+ const string16& key_path,
+ std::vector<IndexedDBKey>* keys) {
+ if (is_shutdown_) {
+ keys->clear();
+ return;
+ }
+
+ if (!impl_) {
+ impl_ = new KeyUtilityClientImpl();
+ impl_->StartUtilityProcess();
+ }
+
+ return impl_->CreateIDBKeysFromSerializedValuesAndKeyPath(values, key_path,
+ keys);
+}
+
+// KeyUtilityClientImpl definitions.
+
+void KeyUtilityClientImpl::Shutdown() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ utility_process_host_->EndBatchMode();
+ utility_process_host_ = NULL;
+ client_ = NULL;
+ state_ = STATE_SHUTDOWN;
+}
+
+KeyUtilityClientImpl::KeyUtilityClientImpl()
: waitable_event_(false, false),
state_(STATE_UNINITIALIZED),
utility_process_host_(NULL) {
}
-IndexedDBKeyUtilityClient::~IndexedDBKeyUtilityClient() {
+KeyUtilityClientImpl::~KeyUtilityClientImpl() {
DCHECK(state_ == STATE_UNINITIALIZED || state_ == STATE_SHUTDOWN);
DCHECK(!utility_process_host_);
DCHECK(!client_.get());
}
-void IndexedDBKeyUtilityClient::StartUtilityProcess() {
+void KeyUtilityClientImpl::StartUtilityProcess() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
DCHECK(state_ == STATE_UNINITIALIZED);
@@ -32,21 +157,16 @@ void IndexedDBKeyUtilityClient::StartUtilityProcess() {
DCHECK(ret && state_ == STATE_INITIALIZED);
}
-void IndexedDBKeyUtilityClient::EndUtilityProcess() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
- DCHECK(state_ == STATE_INITIALIZED);
-
- EndUtilityProcessInternal();
- bool ret = waitable_event_.Wait();
-
- DCHECK(ret && state_ == STATE_SHUTDOWN);
-}
-
-void IndexedDBKeyUtilityClient::CreateIDBKeysFromSerializedValuesAndKeyPath(
+void KeyUtilityClientImpl::CreateIDBKeysFromSerializedValuesAndKeyPath(
const std::vector<SerializedScriptValue>& values,
const string16& key_path,
std::vector<IndexedDBKey>* keys) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ if (state_ == STATE_SHUTDOWN) {
+ keys->clear();
+ return;
+ }
+
DCHECK(state_ == STATE_INITIALIZED);
state_ = STATE_CREATING_KEYS;
@@ -57,7 +177,7 @@ void IndexedDBKeyUtilityClient::CreateIDBKeysFromSerializedValuesAndKeyPath(
*keys = keys_;
}
-void IndexedDBKeyUtilityClient::GetRDHAndStartUtilityProcess() {
+void KeyUtilityClientImpl::GetRDHAndStartUtilityProcess() {
// In order to start the UtilityProcess, we need to grab
// a pointer to the ResourceDispatcherHost. This can only
// be done on the UI thread. See the comment at the top of
@@ -67,14 +187,14 @@ void IndexedDBKeyUtilityClient::GetRDHAndStartUtilityProcess() {
BrowserThread::UI, FROM_HERE,
NewRunnableMethod(
this,
- &IndexedDBKeyUtilityClient::GetRDHAndStartUtilityProcess));
+ &KeyUtilityClientImpl::GetRDHAndStartUtilityProcess));
return;
}
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
StartUtilityProcessInternal(g_browser_process->resource_dispatcher_host());
}
-void IndexedDBKeyUtilityClient::StartUtilityProcessInternal(
+void KeyUtilityClientImpl::StartUtilityProcessInternal(
ResourceDispatcherHost* rdh) {
DCHECK(rdh);
// The ResourceDispatcherHost can only be used on the IO thread.
@@ -84,14 +204,14 @@ void IndexedDBKeyUtilityClient::StartUtilityProcessInternal(
BrowserThread::IO, FROM_HERE,
NewRunnableMethod(
this,
- &IndexedDBKeyUtilityClient::StartUtilityProcessInternal,
+ &KeyUtilityClientImpl::StartUtilityProcessInternal,
rdh));
return;
}
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
DCHECK(state_ == STATE_UNINITIALIZED);
- client_ = new IndexedDBKeyUtilityClient::Client(this);
+ client_ = new KeyUtilityClientImpl::Client(this);
utility_process_host_ = new UtilityProcessHost(
rdh, client_.get(), BrowserThread::IO);
utility_process_host_->StartBatchMode();
@@ -99,13 +219,13 @@ void IndexedDBKeyUtilityClient::StartUtilityProcessInternal(
waitable_event_.Signal();
}
-void IndexedDBKeyUtilityClient::EndUtilityProcessInternal() {
+void KeyUtilityClientImpl::EndUtilityProcessInternal() {
if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableMethod(
this,
- &IndexedDBKeyUtilityClient::EndUtilityProcessInternal));
+ &KeyUtilityClientImpl::EndUtilityProcessInternal));
return;
}
@@ -116,14 +236,14 @@ void IndexedDBKeyUtilityClient::EndUtilityProcessInternal() {
waitable_event_.Signal();
}
-void IndexedDBKeyUtilityClient::CallStartIDBKeyFromValueAndKeyPathFromIOThread(
+void KeyUtilityClientImpl::CallStartIDBKeyFromValueAndKeyPathFromIOThread(
const std::vector<SerializedScriptValue>& values,
const string16& key_path) {
if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableMethod(this,
- &IndexedDBKeyUtilityClient::
+ &KeyUtilityClientImpl::
CallStartIDBKeyFromValueAndKeyPathFromIOThread,
values, key_path));
return;
@@ -134,33 +254,33 @@ void IndexedDBKeyUtilityClient::CallStartIDBKeyFromValueAndKeyPathFromIOThread(
0, values, key_path);
}
-void IndexedDBKeyUtilityClient::SetKeys(const std::vector<IndexedDBKey>& keys) {
+void KeyUtilityClientImpl::SetKeys(const std::vector<IndexedDBKey>& keys) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
keys_ = keys;
}
-void IndexedDBKeyUtilityClient::FinishCreatingKeys() {
+void KeyUtilityClientImpl::FinishCreatingKeys() {
DCHECK(state_ == STATE_CREATING_KEYS);
state_ = STATE_INITIALIZED;
waitable_event_.Signal();
}
-IndexedDBKeyUtilityClient::Client::Client(IndexedDBKeyUtilityClient* parent)
+KeyUtilityClientImpl::Client::Client(KeyUtilityClientImpl* parent)
: parent_(parent) {
}
-void IndexedDBKeyUtilityClient::Client::OnProcessCrashed(int exit_code) {
+void KeyUtilityClientImpl::Client::OnProcessCrashed(int exit_code) {
if (parent_->state_ == STATE_CREATING_KEYS)
parent_->FinishCreatingKeys();
}
-void IndexedDBKeyUtilityClient::Client::OnIDBKeysFromValuesAndKeyPathSucceeded(
+void KeyUtilityClientImpl::Client::OnIDBKeysFromValuesAndKeyPathSucceeded(
int id, const std::vector<IndexedDBKey>& keys) {
parent_->SetKeys(keys);
parent_->FinishCreatingKeys();
}
-void IndexedDBKeyUtilityClient::Client::OnIDBKeysFromValuesAndKeyPathFailed(
+void KeyUtilityClientImpl::Client::OnIDBKeysFromValuesAndKeyPathFailed(
int id) {
parent_->FinishCreatingKeys();
}

Powered by Google App Engine
This is Rietveld 408576698