зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1360185 - Use of IPCBlob in IndexedDB - part 4 - IPCBlob and sharing files when used by IDB, r=baku
This commit is contained in:
Родитель
335ccef6d3
Коммит
148a63cc3f
|
@ -26,6 +26,7 @@ FileBlobImpl::FileBlobImpl(nsIFile* aFile)
|
|||
: BaseBlobImpl(EmptyString(), EmptyString(), UINT64_MAX, INT64_MAX)
|
||||
, mFile(aFile)
|
||||
, mWholeFile(true)
|
||||
, mFileId(-1)
|
||||
{
|
||||
MOZ_ASSERT(mFile, "must have file");
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
|
@ -40,6 +41,7 @@ FileBlobImpl::FileBlobImpl(const nsAString& aName,
|
|||
: BaseBlobImpl(aName, aContentType, aLength, UINT64_MAX)
|
||||
, mFile(aFile)
|
||||
, mWholeFile(true)
|
||||
, mFileId(-1)
|
||||
{
|
||||
MOZ_ASSERT(mFile, "must have file");
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
|
@ -52,6 +54,7 @@ FileBlobImpl::FileBlobImpl(const nsAString& aName,
|
|||
: BaseBlobImpl(aName, aContentType, aLength, aLastModificationDate)
|
||||
, mFile(aFile)
|
||||
, mWholeFile(true)
|
||||
, mFileId(-1)
|
||||
{
|
||||
MOZ_ASSERT(mFile, "must have file");
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
|
@ -62,6 +65,7 @@ FileBlobImpl::FileBlobImpl(nsIFile* aFile, const nsAString& aName,
|
|||
: BaseBlobImpl(aName, aContentType, UINT64_MAX, INT64_MAX)
|
||||
, mFile(aFile)
|
||||
, mWholeFile(true)
|
||||
, mFileId(-1)
|
||||
{
|
||||
MOZ_ASSERT(mFile, "must have file");
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
|
@ -76,6 +80,7 @@ FileBlobImpl::FileBlobImpl(const FileBlobImpl* aOther, uint64_t aStart,
|
|||
: BaseBlobImpl(aContentType, aOther->mStart + aStart, aLength)
|
||||
, mFile(aOther->mFile)
|
||||
, mWholeFile(false)
|
||||
, mFileId(-1)
|
||||
{
|
||||
MOZ_ASSERT(mFile, "must have file");
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
|
|
|
@ -60,6 +60,16 @@ public:
|
|||
mContentType = aType;
|
||||
}
|
||||
|
||||
int64_t GetFileId() override
|
||||
{
|
||||
return mFileId;
|
||||
}
|
||||
|
||||
void SetFileId(int64_t aFileId)
|
||||
{
|
||||
mFileId = aFileId;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~FileBlobImpl() = default;
|
||||
|
||||
|
@ -74,6 +84,7 @@ private:
|
|||
|
||||
nsCOMPtr<nsIFile> mFile;
|
||||
bool mWholeFile;
|
||||
int64_t mFileId;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -57,6 +57,23 @@ IPCBlobInputStreamParent::ActorDestroy(IProtocol::ActorDestroyReason aReason)
|
|||
mPBackgroundManager = nullptr;
|
||||
|
||||
IPCBlobInputStreamStorage::Get()->ForgetStream(mID);
|
||||
|
||||
RefPtr<IPCBlobInputStreamParentCallback> callback;
|
||||
mCallback.swap(callback);
|
||||
|
||||
if (callback) {
|
||||
callback->ActorDestroyed(mID);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
IPCBlobInputStreamParent::SetCallback(
|
||||
IPCBlobInputStreamParentCallback* aCallback)
|
||||
{
|
||||
MOZ_ASSERT(aCallback);
|
||||
MOZ_ASSERT(!mCallback);
|
||||
|
||||
mCallback = aCallback;
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
|
|
|
@ -14,6 +14,19 @@ class nsIInputStream;
|
|||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class NS_NO_VTABLE IPCBlobInputStreamParentCallback
|
||||
{
|
||||
public:
|
||||
virtual void
|
||||
ActorDestroyed(const nsID& aID) = 0;
|
||||
|
||||
NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
|
||||
|
||||
protected:
|
||||
virtual ~IPCBlobInputStreamParentCallback()
|
||||
{ }
|
||||
};
|
||||
|
||||
class IPCBlobInputStreamParent final
|
||||
: public mozilla::ipc::PIPCBlobInputStreamParent
|
||||
{
|
||||
|
@ -41,6 +54,9 @@ public:
|
|||
return mSize;
|
||||
}
|
||||
|
||||
void
|
||||
SetCallback(IPCBlobInputStreamParentCallback* aCallback);
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
RecvStreamNeeded() override;
|
||||
|
||||
|
@ -61,6 +77,8 @@ private:
|
|||
// the parent actor alive. The pointers will be nullified in ActorDestroyed.
|
||||
nsIContentParent* mContentManager;
|
||||
mozilla::ipc::PBackgroundParent* mPBackgroundManager;
|
||||
|
||||
RefPtr<IPCBlobInputStreamParentCallback> mCallback;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
#include "mozilla/dom/indexedDB/PBackgroundIndexedDBUtilsParent.h"
|
||||
#include "mozilla/dom/indexedDB/PIndexedDBPermissionRequestParent.h"
|
||||
#include "mozilla/dom/IPCBlobUtils.h"
|
||||
#include "mozilla/dom/ipc/IPCBlobInputStreamParent.h"
|
||||
#include "mozilla/dom/quota/Client.h"
|
||||
#include "mozilla/dom/quota/FileStreams.h"
|
||||
#include "mozilla/dom/quota/OriginScope.h"
|
||||
|
@ -127,9 +128,6 @@
|
|||
#define IDB_MOBILE
|
||||
#endif
|
||||
|
||||
#define BLOB_IMPL_STORED_FILE_IID \
|
||||
{0x6b505c84, 0x2c60, 0x4ffb, {0x8b, 0x91, 0xfe, 0x22, 0xb1, 0xec, 0x75, 0xe2}}
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPRFileDesc,
|
||||
|
@ -6397,6 +6395,7 @@ class Database final
|
|||
friend class VersionChangeTransaction;
|
||||
|
||||
class StartTransactionOp;
|
||||
class UnmapBlobCallback;
|
||||
|
||||
private:
|
||||
RefPtr<Factory> mFactory;
|
||||
|
@ -6405,6 +6404,7 @@ private:
|
|||
RefPtr<DirectoryLock> mDirectoryLock;
|
||||
nsTHashtable<nsPtrHashKey<TransactionBase>> mTransactions;
|
||||
nsTHashtable<nsPtrHashKey<MutableFile>> mMutableFiles;
|
||||
nsRefPtrHashtable<nsIDHashKey, FileInfo> mMappedBlobs;
|
||||
RefPtr<DatabaseConnection> mConnection;
|
||||
const PrincipalInfo mPrincipalInfo;
|
||||
const Maybe<ContentParentId> mOptionalContentParentId;
|
||||
|
@ -6422,6 +6422,9 @@ private:
|
|||
bool mActorWasAlive;
|
||||
bool mActorDestroyed;
|
||||
bool mMetadataCleanedUp;
|
||||
#ifdef DEBUG
|
||||
bool mAllBlobsUnmapped;
|
||||
#endif
|
||||
|
||||
public:
|
||||
// Created by OpenDatabaseOp.
|
||||
|
@ -6571,6 +6574,9 @@ public:
|
|||
void
|
||||
SetActorAlive();
|
||||
|
||||
void
|
||||
MapBlob(const IPCBlob& aIPCBlob, FileInfo* aFileInfo);
|
||||
|
||||
bool
|
||||
IsActorAlive() const
|
||||
{
|
||||
|
@ -6626,6 +6632,15 @@ private:
|
|||
MOZ_ASSERT_IF(mActorWasAlive, mActorDestroyed);
|
||||
}
|
||||
|
||||
already_AddRefed<FileInfo>
|
||||
GetBlob(const IPCBlob& aID);
|
||||
|
||||
void
|
||||
UnmapBlob(const nsID& aID);
|
||||
|
||||
void
|
||||
UnmapAllBlobs();
|
||||
|
||||
bool
|
||||
CloseInternal();
|
||||
|
||||
|
@ -6747,6 +6762,36 @@ private:
|
|||
Cleanup() override;
|
||||
};
|
||||
|
||||
class Database::UnmapBlobCallback final
|
||||
: public IPCBlobInputStreamParentCallback
|
||||
{
|
||||
RefPtr<Database> mDatabase;
|
||||
|
||||
public:
|
||||
explicit UnmapBlobCallback(Database* aDatabase)
|
||||
: mDatabase(aDatabase)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
}
|
||||
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Database::UnmapBlobCallback, override)
|
||||
|
||||
void
|
||||
ActorDestroyed(const nsID& aID) override
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(mDatabase);
|
||||
|
||||
RefPtr<Database> database;
|
||||
mDatabase.swap(database);
|
||||
|
||||
database->UnmapBlob(aID);
|
||||
}
|
||||
|
||||
private:
|
||||
~UnmapBlobCallback() = default;
|
||||
};
|
||||
|
||||
/**
|
||||
* In coordination with IDBDatabase's mFileActors weak-map on the child side, a
|
||||
* long-lived mapping from a child process's live Blobs to their corresponding
|
||||
|
@ -6755,15 +6800,15 @@ private:
|
|||
* - Blobs retrieved from this database and sent to the child that do not need
|
||||
* to be written to disk because they already exist on disk in this database's
|
||||
* files directory.
|
||||
* - Blobs retrieved from other databases (that are therefore !IsShareable())
|
||||
* or from anywhere else that will need to be written to this database's files
|
||||
* directory. In this case we will hold a reference to its BlobImpl in
|
||||
* mBlobImpl until we have successfully written the Blob to disk.
|
||||
* - Blobs retrieved from other databases or from anywhere else that will need
|
||||
* to be written to this database's files directory. In this case we will
|
||||
* hold a reference to its BlobImpl in mBlobImpl until we have successfully
|
||||
* written the Blob to disk.
|
||||
*
|
||||
* Relevant Blob context: Blobs sent from the parent process to child processes
|
||||
* are automatically linked back to their source BlobImpl when the child process
|
||||
* references the Blob via IPC. This is done using the internal IPCBlob
|
||||
* inputStream ID and IPCBlobInputStreamStorage. However, when getting an actor
|
||||
* inputStream actor ID to FileInfo mapping. However, when getting an actor
|
||||
* in the child process for sending an in-child-created Blob to the parent
|
||||
* process, there is (currently) no Blob machinery to automatically establish
|
||||
* and reuse a long-lived Actor. As a result, without IDB's weak-map
|
||||
|
@ -9109,75 +9154,6 @@ private:
|
|||
~DatabaseLoggingInfo();
|
||||
};
|
||||
|
||||
class BlobImplStoredFile final
|
||||
: public FileBlobImpl
|
||||
{
|
||||
RefPtr<FileInfo> mFileInfo;
|
||||
const bool mSnapshot;
|
||||
|
||||
public:
|
||||
BlobImplStoredFile(nsIFile* aFile, FileInfo* aFileInfo, bool aSnapshot)
|
||||
: FileBlobImpl(aFile)
|
||||
, mFileInfo(aFileInfo)
|
||||
, mSnapshot(aSnapshot)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
// Getting the content type is not currently supported off the main thread.
|
||||
// This isn't a problem here because:
|
||||
//
|
||||
// 1. The real content type is stored in the structured clone data and
|
||||
// that's all that the DOM will see.
|
||||
// 2. The nsExternalHelperAppService guesses the content type based only
|
||||
// on the file extension. Our stored files have no extension so the
|
||||
// current code path fails and sets the content type to the empty
|
||||
// string.
|
||||
//
|
||||
// So, this is a hack to keep the nsExternalHelperAppService out of the
|
||||
// picture entirely. Eventually we should probably fix this some other way.
|
||||
mContentType.Truncate();
|
||||
|
||||
// In order to call GetMozFullPathInternal, this must be a file.
|
||||
// In reality, we don't know the real 'nature' if this BlobImpl because we
|
||||
// need to wait to retrieve such information from the structured clone data.
|
||||
// But at that point we are already on the child side and we will update the
|
||||
// blob generated by IPCBlob, and not this one.
|
||||
mIsFile = true;
|
||||
}
|
||||
|
||||
bool
|
||||
IsShareable(FileManager* aFileManager) const
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
return mFileInfo->Manager() == aFileManager && !mSnapshot;
|
||||
}
|
||||
|
||||
FileInfo*
|
||||
GetFileInfo() const
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
return mFileInfo;
|
||||
}
|
||||
|
||||
private:
|
||||
~BlobImplStoredFile() override = default;
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(BLOB_IMPL_STORED_FILE_IID)
|
||||
|
||||
int64_t
|
||||
GetFileId() override
|
||||
{
|
||||
MOZ_ASSERT(mFileInfo);
|
||||
|
||||
return mFileInfo->Id();
|
||||
}
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(BlobImplStoredFile, BLOB_IMPL_STORED_FILE_IID)
|
||||
|
||||
class QuotaClient final
|
||||
: public mozilla::dom::quota::Client
|
||||
{
|
||||
|
@ -10162,9 +10138,8 @@ SerializeStructuredCloneFiles(
|
|||
|
||||
switch (file.mType) {
|
||||
case StructuredCloneFile::eBlob: {
|
||||
RefPtr<BlobImpl> impl = new BlobImplStoredFile(nativeFile,
|
||||
file.mFileInfo,
|
||||
/* aSnapshot */ false);
|
||||
RefPtr<FileBlobImpl> impl = new FileBlobImpl(nativeFile);
|
||||
impl->SetFileId(file.mFileInfo->Id());
|
||||
|
||||
IPCBlob ipcBlob;
|
||||
nsresult rv = IPCBlobUtils::Serialize(impl, aBackgroundActor, ipcBlob);
|
||||
|
@ -10174,12 +10149,14 @@ SerializeStructuredCloneFiles(
|
|||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
SerializedStructuredCloneFile* file = aResult.AppendElement(fallible);
|
||||
MOZ_ASSERT(file);
|
||||
SerializedStructuredCloneFile* serializedFile =
|
||||
aResult.AppendElement(fallible);
|
||||
MOZ_ASSERT(serializedFile);
|
||||
|
||||
file->file() = ipcBlob;
|
||||
file->type() = StructuredCloneFile::eBlob;
|
||||
serializedFile->file() = ipcBlob;
|
||||
serializedFile->type() = StructuredCloneFile::eBlob;
|
||||
|
||||
aDatabase->MapBlob(ipcBlob, file.mFileInfo);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -10239,9 +10216,8 @@ SerializeStructuredCloneFiles(
|
|||
serializedFile->file() = null_t();
|
||||
serializedFile->type() = file.mType;
|
||||
} else {
|
||||
RefPtr<BlobImpl> impl = new BlobImplStoredFile(nativeFile,
|
||||
file.mFileInfo,
|
||||
/* aSnapshot */ false);
|
||||
RefPtr<FileBlobImpl> impl = new FileBlobImpl(nativeFile);
|
||||
impl->SetFileId(file.mFileInfo->Id());
|
||||
|
||||
IPCBlob ipcBlob;
|
||||
nsresult rv =
|
||||
|
@ -10258,6 +10234,8 @@ SerializeStructuredCloneFiles(
|
|||
|
||||
serializedFile->file() = ipcBlob;
|
||||
serializedFile->type() = file.mType;
|
||||
|
||||
aDatabase->MapBlob(ipcBlob, file.mFileInfo);
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -14176,6 +14154,9 @@ Database::Database(Factory* aFactory,
|
|||
, mActorWasAlive(false)
|
||||
, mActorDestroyed(false)
|
||||
, mMetadataCleanedUp(false)
|
||||
#ifdef DEBUG
|
||||
, mAllBlobsUnmapped(false)
|
||||
#endif
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aFactory);
|
||||
|
@ -14401,6 +14382,76 @@ Database::SetActorAlive()
|
|||
AddRef();
|
||||
}
|
||||
|
||||
void
|
||||
Database::MapBlob(const IPCBlob& aIPCBlob, FileInfo* aFileInfo)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
const IPCBlobStream& stream = aIPCBlob.inputStream();
|
||||
MOZ_ASSERT(stream.type() == IPCBlobStream::TPIPCBlobInputStreamParent);
|
||||
|
||||
IPCBlobInputStreamParent* actor =
|
||||
static_cast<IPCBlobInputStreamParent*>(stream.get_PIPCBlobInputStreamParent());
|
||||
|
||||
MOZ_ASSERT(!mMappedBlobs.GetWeak(actor->ID()));
|
||||
mMappedBlobs.Put(actor->ID(), aFileInfo);
|
||||
|
||||
RefPtr<UnmapBlobCallback> callback = new UnmapBlobCallback(this);
|
||||
actor->SetCallback(callback);
|
||||
}
|
||||
|
||||
already_AddRefed<FileInfo>
|
||||
Database::GetBlob(const IPCBlob& aIPCBlob)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
const IPCBlobStream& stream = aIPCBlob.inputStream();
|
||||
MOZ_ASSERT(stream.type() == IPCBlobStream::TIPCStream);
|
||||
|
||||
const IPCStream& ipcStream = stream.get_IPCStream();
|
||||
|
||||
if (ipcStream.type() != IPCStream::TInputStreamParamsWithFds) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const InputStreamParams& inputStreamParams =
|
||||
ipcStream.get_InputStreamParamsWithFds().stream();
|
||||
if (inputStreamParams.type() !=
|
||||
InputStreamParams::TIPCBlobInputStreamParams) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const nsID& id = inputStreamParams.get_IPCBlobInputStreamParams().id();
|
||||
|
||||
RefPtr<FileInfo> fileInfo;
|
||||
if (!mMappedBlobs.Get(id, getter_AddRefs(fileInfo))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return fileInfo.forget();
|
||||
}
|
||||
|
||||
void
|
||||
Database::UnmapBlob(const nsID& aID)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
MOZ_ASSERT_IF(!mAllBlobsUnmapped, mMappedBlobs.GetWeak(aID));
|
||||
mMappedBlobs.Remove(aID);
|
||||
}
|
||||
|
||||
void
|
||||
Database::UnmapAllBlobs()
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
#ifdef DEBUG
|
||||
mAllBlobsUnmapped = true;
|
||||
#endif
|
||||
|
||||
mMappedBlobs.Clear();
|
||||
}
|
||||
|
||||
bool
|
||||
Database::CloseInternal()
|
||||
{
|
||||
|
@ -14466,6 +14517,8 @@ Database::ConnectionClosedCallback()
|
|||
|
||||
CleanupMetadata();
|
||||
|
||||
UnmapAllBlobs();
|
||||
|
||||
if (IsInvalidated() && IsActorAlive()) {
|
||||
// Step 3 and 4 of "5.2 Closing a Database":
|
||||
// 1. Wait for all transactions to complete.
|
||||
|
@ -14549,15 +14602,10 @@ Database::AllocPBackgroundIDBDatabaseFileParent(const IPCBlob& aIPCBlob)
|
|||
RefPtr<BlobImpl> blobImpl = IPCBlobUtils::Deserialize(aIPCBlob);
|
||||
MOZ_ASSERT(blobImpl);
|
||||
|
||||
RefPtr<FileInfo> fileInfo;
|
||||
RefPtr<FileInfo> fileInfo = GetBlob(aIPCBlob);
|
||||
RefPtr<DatabaseFile> actor;
|
||||
|
||||
RefPtr<BlobImplStoredFile> storedFileImpl = do_QueryObject(blobImpl);
|
||||
if (storedFileImpl && storedFileImpl->IsShareable(mFileManager)) {
|
||||
// This blob was previously shared with the child.
|
||||
fileInfo = storedFileImpl->GetFileInfo();
|
||||
MOZ_ASSERT(fileInfo);
|
||||
|
||||
if (fileInfo) {
|
||||
actor = new DatabaseFile(fileInfo);
|
||||
} else {
|
||||
// This is a blob we haven't seen before.
|
||||
|
@ -17678,14 +17726,6 @@ FileManager::GetUsage(nsIFile* aDirectory, uint64_t* aUsage)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* FileImplStoredFile
|
||||
******************************************************************************/
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED(BlobImplStoredFile,
|
||||
FileBlobImpl,
|
||||
BlobImplStoredFile)
|
||||
|
||||
/*******************************************************************************
|
||||
* QuotaClient
|
||||
******************************************************************************/
|
||||
|
@ -20850,8 +20890,9 @@ MutableFile::CreateBlobImpl()
|
|||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
RefPtr<BlobImpl> blobImpl =
|
||||
new BlobImplStoredFile(mFile, mFileInfo, /* aSnapshot */ true);
|
||||
RefPtr<FileBlobImpl> blobImpl = new FileBlobImpl(mFile);
|
||||
blobImpl->SetFileId(mFileInfo->Id());
|
||||
|
||||
return blobImpl.forget();
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче