Bug 1149815 - Don't assume that index creation always succeeds, r=janv.

This commit is contained in:
Ben Turner 2015-06-20 09:08:26 -07:00
Родитель dbe52fd678
Коммит 778f5ee935
1 изменённых файлов: 151 добавлений и 51 удалений

Просмотреть файл

@ -5343,11 +5343,10 @@ protected:
const Key& aObjectStoreKey,
const FallibleTArray<IndexDataValue>& aIndexValues);
#ifdef DEBUG
static bool
static nsresult
ObjectStoreHasIndexes(DatabaseConnection* aConnection,
const int64_t aObjectStoreId);
#endif
const int64_t aObjectStoreId,
bool* aHasIndexes);
private:
template <typename T>
@ -6941,7 +6940,6 @@ class DeleteObjectStoreOp final
const nsRefPtr<FullObjectStoreMetadata> mMetadata;
const bool mIsLastObjectStore;
const bool mObjectStoreHasIndexes;
private:
// Only created by VersionChangeTransaction.
@ -6951,7 +6949,6 @@ private:
: VersionChangeTransactionOp(aTransaction)
, mMetadata(aMetadata)
, mIsLastObjectStore(aIsLastObjectStore)
, mObjectStoreHasIndexes(aMetadata->HasLiveIndexes())
{
MOZ_ASSERT(aMetadata->mCommonMetadata.id());
}
@ -7138,6 +7135,15 @@ protected:
~NormalTransactionOp()
{ }
// An overload of DatabaseOperationBase's function that can avoid doing extra
// work on non-versionchange transactions.
static nsresult
ObjectStoreHasIndexes(NormalTransactionOp* aOp,
DatabaseConnection* aConnection,
const int64_t aObjectStoreId,
const bool aMayHaveIndexes,
bool* aHasIndexes);
// Subclasses use this override to set the IPDL response value.
virtual void
GetResponse(RequestResponse& aResponse) = 0;
@ -7179,7 +7185,7 @@ class ObjectStoreAddOrPutRequestOp final
const nsCString mOrigin;
const PersistenceType mPersistenceType;
const bool mOverwrite;
const bool mObjectStoreHasIndexes;
const bool mObjectStoreMayHaveIndexes;
private:
// Only created by TransactionBase.
@ -7297,7 +7303,7 @@ class ObjectStoreDeleteRequestOp final
const ObjectStoreDeleteParams mParams;
ObjectStoreDeleteResponse mResponse;
const bool mObjectStoreHasIndexes;
const bool mObjectStoreMayHaveIndexes;
private:
ObjectStoreDeleteRequestOp(TransactionBase* aTransaction,
@ -7323,7 +7329,7 @@ class ObjectStoreClearRequestOp final
const ObjectStoreClearParams mParams;
ObjectStoreClearResponse mResponse;
const bool mObjectStoreHasIndexes;
const bool mObjectStoreMayHaveIndexes;
private:
ObjectStoreClearRequestOp(TransactionBase* aTransaction,
@ -18063,8 +18069,16 @@ DatabaseOperationBase::DeleteObjectStoreDataTableRowsWithIndexes(
MOZ_ASSERT(aConnection);
aConnection->AssertIsOnConnectionThread();
MOZ_ASSERT(aObjectStoreId);
MOZ_ASSERT(ObjectStoreHasIndexes(aConnection, aObjectStoreId),
"Don't use this slow method if there are no indexes!");
#ifdef DEBUG
{
bool hasIndexes = false;
MOZ_ASSERT(NS_SUCCEEDED(
ObjectStoreHasIndexes(aConnection, aObjectStoreId, &hasIndexes)));
MOZ_ASSERT(hasIndexes,
"Don't use this slow method if there are no indexes!");
}
#endif
PROFILER_LABEL("IndexedDB",
"DatabaseOperationBase::"
@ -18272,38 +18286,45 @@ DatabaseOperationBase::UpdateIndexValues(
return NS_OK;
}
#ifdef DEBUG
// static
bool
nsresult
DatabaseOperationBase::ObjectStoreHasIndexes(DatabaseConnection* aConnection,
const int64_t aObjectStoreId)
const int64_t aObjectStoreId,
bool* aHasIndexes)
{
MOZ_ASSERT(aConnection);
aConnection->AssertIsOnConnectionThread();
MOZ_ASSERT(aObjectStoreId);
MOZ_ASSERT(aHasIndexes);
DatabaseConnection::CachedStatement stmt;
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
"SELECT id "
"FROM object_store_index "
"WHERE object_store_id = :object_store_id;"),
&stmt)));
nsresult rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
"SELECT id "
"FROM object_store_index "
"WHERE object_store_id = :object_store_id "
"LIMIT 1;"),
&stmt);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
stmt->BindInt64ByName(NS_LITERAL_CSTRING("object_store_id"),
aObjectStoreId)));
rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("object_store_id"),
aObjectStoreId);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
bool hasResult;
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)));
rv = stmt->ExecuteStep(&hasResult);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return hasResult;
*aHasIndexes = hasResult;
return NS_OK;
}
#endif // DEBUG
NS_IMPL_ISUPPORTS_INHERITED(DatabaseOperationBase,
nsRunnable,
mozIStorageProgressHandler)
@ -21635,11 +21656,6 @@ DeleteObjectStoreOp::DoDatabaseWork(DatabaseConnection* aConnection)
foundThisObjectStore && !foundOtherObjectStore);
MOZ_ASSERT_IF(!mIsLastObjectStore,
foundThisObjectStore && foundOtherObjectStore);
// Make sure |hasIndexes| is telling the truth.
MOZ_ASSERT(mObjectStoreHasIndexes ==
ObjectStoreHasIndexes(aConnection,
mMetadata->mCommonMetadata.id()));
}
#endif
@ -21712,7 +21728,15 @@ DeleteObjectStoreOp::DoDatabaseWork(DatabaseConnection* aConnection)
return rv;
}
} else {
if (mObjectStoreHasIndexes) {
bool hasIndexes;
rv = ObjectStoreHasIndexes(aConnection,
mMetadata->mCommonMetadata.id(),
&hasIndexes);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (hasIndexes) {
rv = DeleteObjectStoreDataTableRowsWithIndexes(
aConnection,
mMetadata->mCommonMetadata.id(),
@ -22790,6 +22814,48 @@ DeleteIndexOp::DoDatabaseWork(DatabaseConnection* aConnection)
return NS_OK;
}
// static
nsresult
NormalTransactionOp::ObjectStoreHasIndexes(NormalTransactionOp* aOp,
DatabaseConnection* aConnection,
const int64_t aObjectStoreId,
const bool aMayHaveIndexes,
bool* aHasIndexes)
{
MOZ_ASSERT(aOp);
MOZ_ASSERT(aConnection);
aConnection->AssertIsOnConnectionThread();
MOZ_ASSERT(aObjectStoreId);
MOZ_ASSERT(aHasIndexes);
bool hasIndexes;
if (aOp->Transaction()->GetMode() == IDBTransaction::VERSION_CHANGE &&
aMayHaveIndexes) {
// If this is a version change transaction then mObjectStoreMayHaveIndexes
// could be wrong (e.g. if a unique index failed to be created due to a
// constraint error). We have to check on this thread by asking the database
// directly.
nsresult rv =
DatabaseOperationBase::ObjectStoreHasIndexes(aConnection,
aObjectStoreId,
&hasIndexes);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
} else {
MOZ_ASSERT(NS_SUCCEEDED(
DatabaseOperationBase::ObjectStoreHasIndexes(aConnection,
aObjectStoreId,
&hasIndexes)));
MOZ_ASSERT(aMayHaveIndexes == hasIndexes);
hasIndexes = aMayHaveIndexes;
}
*aHasIndexes = hasIndexes;
return NS_OK;
}
nsresult
NormalTransactionOp::SendSuccessResult()
{
@ -22866,7 +22932,7 @@ ObjectStoreAddOrPutRequestOp::ObjectStoreAddOrPutRequestOp(
, mOrigin(aTransaction->GetDatabase()->Origin())
, mPersistenceType(aTransaction->GetDatabase()->Type())
, mOverwrite(aParams.type() == RequestParams::TObjectStorePutParams)
, mObjectStoreHasIndexes(false)
, mObjectStoreMayHaveIndexes(false)
{
MOZ_ASSERT(aParams.type() == RequestParams::TObjectStoreAddParams ||
aParams.type() == RequestParams::TObjectStorePutParams);
@ -22875,7 +22941,7 @@ ObjectStoreAddOrPutRequestOp::ObjectStoreAddOrPutRequestOp(
aTransaction->GetMetadataForObjectStoreId(mParams.objectStoreId());
MOZ_ASSERT(mMetadata);
const_cast<bool&>(mObjectStoreHasIndexes) = mMetadata->HasLiveIndexes();
const_cast<bool&>(mObjectStoreMayHaveIndexes) = mMetadata->HasLiveIndexes();
}
nsresult
@ -22886,7 +22952,18 @@ ObjectStoreAddOrPutRequestOp::RemoveOldIndexDataValues(
MOZ_ASSERT(aConnection);
MOZ_ASSERT(mOverwrite);
MOZ_ASSERT(!mResponse.IsUnset());
MOZ_ASSERT(mObjectStoreHasIndexes);
#ifdef DEBUG
{
bool hasIndexes = false;
MOZ_ASSERT(NS_SUCCEEDED(
DatabaseOperationBase::ObjectStoreHasIndexes(aConnection,
mParams.objectStoreId(),
&hasIndexes)));
MOZ_ASSERT(hasIndexes,
"Don't use this slow method if there are no indexes!");
}
#endif
DatabaseConnection::CachedStatement indexValuesStmt;
nsresult rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
@ -23098,8 +23175,6 @@ ObjectStoreAddOrPutRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
aConnection->AssertIsOnConnectionThread();
MOZ_ASSERT(aConnection->GetStorageConnection());
MOZ_ASSERT_IF(mFileManager, !mStoredFileInfos.IsEmpty());
MOZ_ASSERT(mObjectStoreHasIndexes ==
ObjectStoreHasIndexes(aConnection, mParams.objectStoreId()));
PROFILER_LABEL("IndexedDB",
"ObjectStoreAddOrPutRequestOp::DoDatabaseWork",
@ -23115,6 +23190,16 @@ ObjectStoreAddOrPutRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
return rv;
}
bool objectStoreHasIndexes;
rv = ObjectStoreHasIndexes(this,
aConnection,
mParams.objectStoreId(),
mObjectStoreMayHaveIndexes,
&objectStoreHasIndexes);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
// This will be the final key we use.
Key& key = mResponse;
key = mParams.key();
@ -23125,7 +23210,7 @@ ObjectStoreAddOrPutRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
// First delete old index_data_values if we're overwriting something and we
// have indexes.
if (mOverwrite && !keyUnset && mObjectStoreHasIndexes) {
if (mOverwrite && !keyUnset && objectStoreHasIndexes) {
rv = RemoveOldIndexDataValues(aConnection);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
@ -23779,7 +23864,7 @@ ObjectStoreDeleteRequestOp::ObjectStoreDeleteRequestOp(
const ObjectStoreDeleteParams& aParams)
: NormalTransactionOp(aTransaction)
, mParams(aParams)
, mObjectStoreHasIndexes(false)
, mObjectStoreMayHaveIndexes(false)
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(aTransaction);
@ -23788,7 +23873,7 @@ ObjectStoreDeleteRequestOp::ObjectStoreDeleteRequestOp(
aTransaction->GetMetadataForObjectStoreId(mParams.objectStoreId());
MOZ_ASSERT(metadata);
const_cast<bool&>(mObjectStoreHasIndexes) = metadata->HasLiveIndexes();
const_cast<bool&>(mObjectStoreMayHaveIndexes) = metadata->HasLiveIndexes();
}
nsresult
@ -23796,9 +23881,6 @@ ObjectStoreDeleteRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
{
MOZ_ASSERT(aConnection);
aConnection->AssertIsOnConnectionThread();
MOZ_ASSERT(mObjectStoreHasIndexes ==
ObjectStoreHasIndexes(aConnection, mParams.objectStoreId()));
PROFILER_LABEL("IndexedDB",
"ObjectStoreDeleteRequestOp::DoDatabaseWork",
js::ProfileEntry::Category::STORAGE);
@ -23809,7 +23891,17 @@ ObjectStoreDeleteRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
return rv;
}
if (mObjectStoreHasIndexes) {
bool objectStoreHasIndexes;
rv = ObjectStoreHasIndexes(this,
aConnection,
mParams.objectStoreId(),
mObjectStoreMayHaveIndexes,
&objectStoreHasIndexes);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (objectStoreHasIndexes) {
rv = DeleteObjectStoreDataTableRowsWithIndexes(aConnection,
mParams.objectStoreId(),
mParams.keyRange());
@ -23864,7 +23956,7 @@ ObjectStoreClearRequestOp::ObjectStoreClearRequestOp(
const ObjectStoreClearParams& aParams)
: NormalTransactionOp(aTransaction)
, mParams(aParams)
, mObjectStoreHasIndexes(false)
, mObjectStoreMayHaveIndexes(false)
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(aTransaction);
@ -23873,7 +23965,7 @@ ObjectStoreClearRequestOp::ObjectStoreClearRequestOp(
aTransaction->GetMetadataForObjectStoreId(mParams.objectStoreId());
MOZ_ASSERT(metadata);
const_cast<bool&>(mObjectStoreHasIndexes) = metadata->HasLiveIndexes();
const_cast<bool&>(mObjectStoreMayHaveIndexes) = metadata->HasLiveIndexes();
}
nsresult
@ -23881,8 +23973,6 @@ ObjectStoreClearRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
{
MOZ_ASSERT(aConnection);
aConnection->AssertIsOnConnectionThread();
MOZ_ASSERT(mObjectStoreHasIndexes ==
ObjectStoreHasIndexes(aConnection, mParams.objectStoreId()));
PROFILER_LABEL("IndexedDB",
"ObjectStoreClearRequestOp::DoDatabaseWork",
@ -23894,7 +23984,17 @@ ObjectStoreClearRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
return rv;
}
if (mObjectStoreHasIndexes) {
bool objectStoreHasIndexes;
rv = ObjectStoreHasIndexes(this,
aConnection,
mParams.objectStoreId(),
mObjectStoreMayHaveIndexes,
&objectStoreHasIndexes);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (objectStoreHasIndexes) {
rv = DeleteObjectStoreDataTableRowsWithIndexes(aConnection,
mParams.objectStoreId(),
void_t());