Modified: trunk/Source/WebCore/ChangeLog (122290 => 122291)
--- trunk/Source/WebCore/ChangeLog 2012-07-11 03:11:30 UTC (rev 122290)
+++ trunk/Source/WebCore/ChangeLog 2012-07-11 04:24:22 UTC (rev 122291)
@@ -1,3 +1,33 @@
+2012-07-10 Joshua Bell <[email protected]>
+
+ IndexedDB: Ensure transaction abort events are deterministic in multiprocess ports
+ https://bugs.webkit.org/show_bug.cgi?id=90412
+
+ Reviewed by Tony Chang.
+
+ In multi-process ports (e.g. Chromium), transaction aborts triggered on the front-end could
+ be initiated while a "success" event was in-flight from the back end. This would lead to
+ apparently flaky behavior when requests would sometimes report success and sometimes report
+ an error. Address this by having front-end triggered aborts do the abort steps immediately,
+ then send the async abort request to the back end.
+
+ No new tests - behavior in single process ports (and DRT) covered by existing
+ tests. Will enable currently disabled Chromium tests to be enabled (crbug.com/83226).
+
+ * Modules/indexeddb/IDBRequest.cpp:
+ (WebCore::IDBRequest::IDBRequest): Initialize a new m_requestAborted flag, used to prevent
+ dispatching if an in-flight request comes in after the abort.
+ (WebCore::IDBRequest::abort): Set flag to prevent double dispatching.
+ (WebCore::IDBRequest::onError): Handle aborted-then-received-event case.
+ (WebCore::IDBRequest::onSuccess): Ditto.
+ (WebCore::IDBRequest::onSuccessWithContinuation): Ditto.
+ (WebCore::IDBRequest::dispatchEvent): On uncaught error, trigger abort on transaction front-end.
+ * Modules/indexeddb/IDBRequest.h:
+ (IDBRequest):
+ * Modules/indexeddb/IDBTransaction.cpp:
+ (WebCore::IDBTransaction::abort): Do abort steps locally first, then notify back-end.
+ (WebCore::IDBTransaction::onAbort): If abort wasn't triggered locally, clean up is still necessary.
+
2012-07-10 Julien Chaffraix <[email protected]>
REGRESSION(r112113): absolutely positioned INPUT boxes with a table cell containing block have a 0px height
Modified: trunk/Source/WebCore/Modules/indexeddb/IDBRequest.cpp (122290 => 122291)
--- trunk/Source/WebCore/Modules/indexeddb/IDBRequest.cpp 2012-07-11 03:11:30 UTC (rev 122290)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBRequest.cpp 2012-07-11 04:24:22 UTC (rev 122291)
@@ -57,6 +57,7 @@
, m_source(source)
, m_transaction(transaction)
, m_readyState(PENDING)
+ , m_requestAborted(false)
, m_requestFinished(false)
, m_cursorFinished(false)
, m_contextStopped(false)
@@ -166,6 +167,7 @@
void IDBRequest::abort()
{
+ ASSERT(!m_requestAborted);
if (m_contextStopped || !scriptExecutionContext())
return;
@@ -186,6 +188,7 @@
m_errorMessage = String();
m_result.clear();
onError(IDBDatabaseError::create(IDBDatabaseException::IDB_ABORT_ERR, "The transaction was aborted, so the request cannot be fulfilled."));
+ m_requestAborted = true;
}
void IDBRequest::setCursorDetails(IDBCursorBackendInterface::CursorType cursorType, IDBCursor::Direction direction)
@@ -210,6 +213,8 @@
void IDBRequest::onError(PassRefPtr<IDBDatabaseError> error)
{
+ if (m_requestAborted)
+ return;
ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_result);
m_errorCode = error->code();
ASSERT(!m_error);
@@ -227,6 +232,8 @@
void IDBRequest::onSuccess(PassRefPtr<DOMStringList> domStringList)
{
IDB_TRACE("IDBRequest::onSuccess(DOMStringList)");
+ if (m_requestAborted)
+ return;
ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_error && !m_result);
m_result = IDBAny::create(domStringList);
enqueueEvent(createSuccessEvent());
@@ -235,6 +242,8 @@
void IDBRequest::onSuccess(PassRefPtr<IDBCursorBackendInterface> backend)
{
IDB_TRACE("IDBRequest::onSuccess(IDBCursor)");
+ if (m_requestAborted)
+ return;
ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_error && !m_result);
ASSERT(m_cursorType != IDBCursorBackendInterface::InvalidCursorType);
RefPtr<IDBCursor> cursor;
@@ -250,6 +259,8 @@
void IDBRequest::onSuccess(PassRefPtr<IDBDatabaseBackendInterface> backend)
{
IDB_TRACE("IDBRequest::onSuccess(IDBDatabase)");
+ if (m_requestAborted)
+ return;
ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_error && !m_result);
if (m_contextStopped || !scriptExecutionContext())
return;
@@ -264,6 +275,8 @@
void IDBRequest::onSuccess(PassRefPtr<IDBKey> idbKey)
{
IDB_TRACE("IDBRequest::onSuccess(IDBKey)");
+ if (m_requestAborted)
+ return;
ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_error && !m_result);
if (idbKey && idbKey->isValid())
m_result = IDBAny::create(idbKey);
@@ -275,6 +288,8 @@
void IDBRequest::onSuccess(PassRefPtr<IDBTransactionBackendInterface> prpBackend)
{
IDB_TRACE("IDBRequest::onSuccess(IDBTransaction)");
+ if (m_requestAborted)
+ return;
ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_error && !m_result);
RefPtr<IDBTransactionBackendInterface> backend = prpBackend;
@@ -297,6 +312,8 @@
void IDBRequest::onSuccess(PassRefPtr<SerializedScriptValue> serializedScriptValue)
{
IDB_TRACE("IDBRequest::onSuccess(SerializedScriptValue)");
+ if (m_requestAborted)
+ return;
ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_error && !m_result);
m_result = IDBAny::create(serializedScriptValue);
m_cursor.clear();
@@ -307,6 +324,8 @@
void IDBRequest::onSuccess(PassRefPtr<SerializedScriptValue> prpSerializedScriptValue, PassRefPtr<IDBKey> prpPrimaryKey, const IDBKeyPath& keyPath)
{
LOG_ERROR("CHECKING: onSuccess(value, key, keypath)");
+ if (m_requestAborted)
+ return;
RefPtr<SerializedScriptValue> serializedScriptValue = prpSerializedScriptValue;
#ifndef NDEBUG
// FIXME: Assert until we can actually inject the right value.
@@ -321,6 +340,8 @@
void IDBRequest::onSuccessWithContinuation()
{
IDB_TRACE("IDBRequest::onSuccessWithContinuation");
+ if (m_requestAborted)
+ return;
ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_error && !m_result);
ASSERT(m_cursor);
setResultCursor(m_cursor, m_cursorType);
@@ -421,7 +442,7 @@
// If an error event and the default wasn't prevented...
if (dontPreventDefault && event->type() == eventNames().errorEvent) {
m_transaction->setError(m_error);
- m_transaction->backend()->abort();
+ m_transaction->abort();
}
m_transaction->backend()->didCompleteTaskEvents();
}
Modified: trunk/Source/WebCore/Modules/indexeddb/IDBRequest.h (122290 => 122291)
--- trunk/Source/WebCore/Modules/indexeddb/IDBRequest.h 2012-07-11 03:11:30 UTC (rev 122290)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBRequest.h 2012-07-11 04:24:22 UTC (rev 122291)
@@ -128,6 +128,7 @@
RefPtr<IDBTransaction> m_transaction;
ReadyState m_readyState;
+ bool m_requestAborted; // May be aborted by transaction then receive async onsuccess; ignore vs. assert.
bool m_requestFinished; // Is it possible that we'll fire any more events? If not, we're finished.
bool m_cursorFinished;
bool m_contextStopped;
Modified: trunk/Source/WebCore/Modules/indexeddb/IDBTransaction.cpp (122290 => 122291)
--- trunk/Source/WebCore/Modules/indexeddb/IDBTransaction.cpp 2012-07-11 03:11:30 UTC (rev 122290)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBTransaction.cpp 2012-07-11 04:24:22 UTC (rev 122291)
@@ -213,6 +213,13 @@
return;
m_state = Finishing;
m_active = false;
+
+ while (!m_requestList.isEmpty()) {
+ IDBRequest* request = *m_requestList.begin();
+ m_requestList.remove(request);
+ request->abort();
+ }
+
RefPtr<IDBTransaction> selfRef = this;
if (m_backend)
m_backend->abort();
@@ -267,11 +274,16 @@
void IDBTransaction::onAbort()
{
ASSERT(m_state != Finished);
- m_state = Finishing;
- while (!m_requestList.isEmpty()) {
- IDBRequest* request = *m_requestList.begin();
- m_requestList.remove(request);
- request->abort();
+
+ if (m_state != Finishing) {
+ // Abort was not triggered by front-end, so outstanding requests must
+ // be aborted now.
+ while (!m_requestList.isEmpty()) {
+ IDBRequest* request = *m_requestList.begin();
+ m_requestList.remove(request);
+ request->abort();
+ }
+ m_state = Finishing;
}
if (isVersionChange()) {