зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1335054 - Fix IndexedDB blob writing ownership race. r=janv
--HG-- extra : rebase_source : 1b67f4f1977233a196616f041622fa1bc4d8f0d9
This commit is contained in:
Родитель
e009a2b331
Коммит
45cc729bbb
|
@ -6671,6 +6671,13 @@ class DatabaseFile final
|
|||
{
|
||||
friend class Database;
|
||||
|
||||
// mBlobImpl's ownership lifecycle:
|
||||
// - Initialized on the background thread at creation time. Then
|
||||
// responsibility is handed off to the connection thread.
|
||||
// - Checked and used by the connection thread to generate a stream to write
|
||||
// the blob to disk by an add/put operation.
|
||||
// - Cleared on the connection thread once the file has successfully been
|
||||
// written to disk.
|
||||
RefPtr<BlobImpl> mBlobImpl;
|
||||
RefPtr<FileInfo> mFileInfo;
|
||||
|
||||
|
@ -6685,16 +6692,6 @@ public:
|
|||
return mFileInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is there a blob available to provide an input stream? This may be called
|
||||
* on any thread under current lifecycle constraints.
|
||||
*/
|
||||
bool
|
||||
HasBlobImpl() const
|
||||
{
|
||||
return (bool)mBlobImpl;
|
||||
}
|
||||
|
||||
/**
|
||||
* If mBlobImpl is non-null (implying the contents of this file have not yet
|
||||
* been written to disk), then return an input stream that is guaranteed to
|
||||
|
@ -6734,10 +6731,17 @@ public:
|
|||
already_AddRefed<nsIInputStream>
|
||||
GetBlockingInputStream(ErrorResult &rv) const;
|
||||
|
||||
/**
|
||||
* To be called upon successful copying of the stream GetBlockingInputStream()
|
||||
* returned so that we won't try and redundantly write the file to disk in the
|
||||
* future. This is a separate step from GetBlockingInputStream() because
|
||||
* the write could fail due to quota errors that happen now but that might
|
||||
* not happen in a future attempt.
|
||||
*/
|
||||
void
|
||||
ClearInputStream()
|
||||
WriteSucceededClearBlobImpl()
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(!IsOnBackgroundThread());
|
||||
|
||||
mBlobImpl = nullptr;
|
||||
}
|
||||
|
@ -6773,8 +6777,8 @@ private:
|
|||
already_AddRefed<nsIInputStream>
|
||||
DatabaseFile::GetBlockingInputStream(ErrorResult &rv) const
|
||||
{
|
||||
// We should only be called from a database I/O thread, not the background
|
||||
// thread. The background thread should call HasBlobImpl().
|
||||
// We should only be called from our DB connection thread, not the background
|
||||
// thread.
|
||||
MOZ_ASSERT(!IsOnBackgroundThread());
|
||||
|
||||
if (!mBlobImpl) {
|
||||
|
@ -8320,8 +8324,6 @@ class ObjectStoreAddOrPutRequestOp final
|
|||
|
||||
FallibleTArray<StoredFileInfo> mStoredFileInfos;
|
||||
|
||||
RefPtr<FileManager> mFileManager;
|
||||
|
||||
Key mResponse;
|
||||
const nsCString mGroup;
|
||||
const nsCString mOrigin;
|
||||
|
@ -8361,11 +8363,9 @@ struct ObjectStoreAddOrPutRequestOp::StoredFileInfo final
|
|||
// still have a stream for us to write.
|
||||
nsCOMPtr<nsIInputStream> mInputStream;
|
||||
StructuredCloneFile::FileType mType;
|
||||
bool mCopiedSuccessfully;
|
||||
|
||||
StoredFileInfo()
|
||||
: mType(StructuredCloneFile::eBlob)
|
||||
, mCopiedSuccessfully(false)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
|
@ -26155,10 +26155,6 @@ ObjectStoreAddOrPutRequestOp::Init(TransactionBase* aTransaction)
|
|||
return false;
|
||||
}
|
||||
|
||||
RefPtr<FileManager> fileManager =
|
||||
aTransaction->GetDatabase()->GetFileManager();
|
||||
MOZ_ASSERT(fileManager);
|
||||
|
||||
for (uint32_t index = 0; index < count; index++) {
|
||||
const FileAddInfo& fileAddInfo = fileAddInfos[index];
|
||||
|
||||
|
@ -26185,10 +26181,6 @@ ObjectStoreAddOrPutRequestOp::Init(TransactionBase* aTransaction)
|
|||
storedFileInfo->mFileInfo = storedFileInfo->mFileActor->GetFileInfo();
|
||||
MOZ_ASSERT(storedFileInfo->mFileInfo);
|
||||
|
||||
if (storedFileInfo->mFileActor->HasBlobImpl() && !mFileManager) {
|
||||
mFileManager = fileManager;
|
||||
}
|
||||
|
||||
storedFileInfo->mType = StructuredCloneFile::eBlob;
|
||||
break;
|
||||
}
|
||||
|
@ -26222,10 +26214,6 @@ ObjectStoreAddOrPutRequestOp::Init(TransactionBase* aTransaction)
|
|||
storedFileInfo->mFileInfo = storedFileInfo->mFileActor->GetFileInfo();
|
||||
MOZ_ASSERT(storedFileInfo->mFileInfo);
|
||||
|
||||
if (storedFileInfo->mFileActor->HasBlobImpl() && !mFileManager) {
|
||||
mFileManager = fileManager;
|
||||
}
|
||||
|
||||
storedFileInfo->mType = fileAddInfo.type();
|
||||
break;
|
||||
}
|
||||
|
@ -26240,12 +26228,11 @@ ObjectStoreAddOrPutRequestOp::Init(TransactionBase* aTransaction)
|
|||
StoredFileInfo* storedFileInfo = mStoredFileInfos.AppendElement(fallible);
|
||||
MOZ_ASSERT(storedFileInfo);
|
||||
|
||||
if (!mFileManager) {
|
||||
mFileManager = aTransaction->GetDatabase()->GetFileManager();
|
||||
MOZ_ASSERT(mFileManager);
|
||||
}
|
||||
RefPtr<FileManager> fileManager =
|
||||
aTransaction->GetDatabase()->GetFileManager();
|
||||
MOZ_ASSERT(fileManager);
|
||||
|
||||
storedFileInfo->mFileInfo = mFileManager->GetNewFileInfo();
|
||||
storedFileInfo->mFileInfo = fileManager->GetNewFileInfo();
|
||||
|
||||
storedFileInfo->mInputStream =
|
||||
new SCInputStream(mParams.cloneInfo().data().data);
|
||||
|
@ -26262,7 +26249,6 @@ ObjectStoreAddOrPutRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
|
|||
MOZ_ASSERT(aConnection);
|
||||
aConnection->AssertIsOnConnectionThread();
|
||||
MOZ_ASSERT(aConnection->GetStorageConnection());
|
||||
MOZ_ASSERT_IF(mFileManager, !mStoredFileInfos.IsEmpty());
|
||||
|
||||
PROFILER_LABEL("IndexedDB",
|
||||
"ObjectStoreAddOrPutRequestOp::DoDatabaseWork",
|
||||
|
@ -26439,19 +26425,10 @@ ObjectStoreAddOrPutRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
|
|||
}
|
||||
}
|
||||
|
||||
Maybe<FileHelper> fileHelper;
|
||||
|
||||
if (mFileManager) {
|
||||
fileHelper.emplace(mFileManager);
|
||||
|
||||
rv = fileHelper->Init();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
IDB_REPORT_INTERNAL_ERR();
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mStoredFileInfos.IsEmpty()) {
|
||||
// Moved outside the loop to allow it to be cached when demanded by the
|
||||
// first write. (We may have mStoredFileInfos without any required writes.)
|
||||
Maybe<FileHelper> fileHelper;
|
||||
nsAutoString fileIds;
|
||||
|
||||
for (uint32_t count = mStoredFileInfos.Length(), index = 0;
|
||||
|
@ -26465,8 +26442,7 @@ ObjectStoreAddOrPutRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
|
|||
// MUST be non-null.
|
||||
// - This is a reference to a Blob that may or may not have already been
|
||||
// written to disk. storedFileInfo.mFileActor MUST be non-null, but
|
||||
// its HasBlobImpl() may return false and so GetBlockingInputStream may
|
||||
// return null (so don't assert on them).
|
||||
// its GetBlockingInputStream may return null (so don't assert on them).
|
||||
// - It's a mutable file. No writing will be performed.
|
||||
MOZ_ASSERT(storedFileInfo.mInputStream || storedFileInfo.mFileActor ||
|
||||
storedFileInfo.mType == StructuredCloneFile::eMutableFile);
|
||||
|
@ -26485,6 +26461,19 @@ ObjectStoreAddOrPutRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
|
|||
}
|
||||
|
||||
if (inputStream) {
|
||||
if (fileHelper.isNothing()) {
|
||||
RefPtr<FileManager> fileManager =
|
||||
Transaction()->GetDatabase()->GetFileManager();
|
||||
MOZ_ASSERT(fileManager);
|
||||
|
||||
fileHelper.emplace(fileManager);
|
||||
rv = fileHelper->Init();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
IDB_REPORT_INTERNAL_ERR();
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<FileInfo>& fileInfo = storedFileInfo.mFileInfo;
|
||||
|
||||
nsCOMPtr<nsIFile> file = fileHelper->GetFile(fileInfo);
|
||||
|
@ -26521,7 +26510,9 @@ ObjectStoreAddOrPutRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
|
|||
return rv;
|
||||
}
|
||||
|
||||
storedFileInfo.mCopiedSuccessfully = true;
|
||||
if (storedFileInfo.mFileActor) {
|
||||
storedFileInfo.mFileActor->WriteSucceededClearBlobImpl();
|
||||
}
|
||||
}
|
||||
|
||||
if (index) {
|
||||
|
@ -26605,23 +26596,7 @@ ObjectStoreAddOrPutRequestOp::Cleanup()
|
|||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
if (!mStoredFileInfos.IsEmpty()) {
|
||||
for (uint32_t count = mStoredFileInfos.Length(), index = 0;
|
||||
index < count;
|
||||
index++) {
|
||||
StoredFileInfo& storedFileInfo = mStoredFileInfos[index];
|
||||
|
||||
MOZ_ASSERT_IF(storedFileInfo.mType == StructuredCloneFile::eMutableFile,
|
||||
!storedFileInfo.mCopiedSuccessfully);
|
||||
|
||||
RefPtr<DatabaseFile>& fileActor = storedFileInfo.mFileActor;
|
||||
if (fileActor && storedFileInfo.mCopiedSuccessfully) {
|
||||
fileActor->ClearInputStream();
|
||||
}
|
||||
}
|
||||
|
||||
mStoredFileInfos.Clear();
|
||||
}
|
||||
mStoredFileInfos.Clear();
|
||||
|
||||
NormalTransactionOp::Cleanup();
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче