Closed Bug 1360185 Opened 3 years ago Closed 3 years ago

Use IPCBlob in IndexedDB

Categories

(Core :: DOM: File, enhancement)

enhancement
Not set

Tracking

()

RESOLVED FIXED
mozilla55
Tracking Status
firefox55 --- fixed

People

(Reporter: baku, Assigned: baku)

References

Details

Attachments

(6 files, 8 obsolete files)

25.48 KB, patch
janv
: review+
Details | Diff | Splinter Review
4.61 KB, patch
janv
: review+
Details | Diff | Splinter Review
7.26 KB, patch
janv
: review+
Details | Diff | Splinter Review
2.09 KB, patch
janv
: review+
Details | Diff | Splinter Review
24.01 KB, patch
janv
: review+
Details | Diff | Splinter Review
16.91 KB, patch
janv
: review+
Details | Diff | Splinter Review
This is the last bit needed for the PBlob refactoring.
Blocks: 1353629
Assignee: nobody → amarchesini
Attachment #8862401 - Flags: review?(jvarga)
Attached patch part 4 - ShareableBlobService (obsolete) — Splinter Review
Attachment #8862405 - Flags: review?(jvarga)
rebased
Attachment #8862406 - Attachment is obsolete: true
Attachment #8862406 - Flags: review?(jvarga)
Attachment #8862784 - Flags: review?(jvarga)
Component: DOM → DOM: File
Depends on: 1350644
Comment on attachment 8862401 [details] [diff] [review]
part 1 - Replacement of PBlob with IPCBlob

Review of attachment 8862401 [details] [diff] [review]:
-----------------------------------------------------------------

Only some nits

::: dom/indexedDB/ActorsChild.cpp
@@ +30,2 @@
>  #include "mozilla/ipc/BackgroundUtils.h"
> +#include "mozilla/dom/IPCBlobUtils.h"

Nit: Why not keep mozilla/dom together ?

@@ +614,5 @@
>        const BlobOrMutableFile& blobOrMutableFile = serializedFile.file();
>  
>        switch (serializedFile.type()) {
>          case StructuredCloneFile::eBlob: {
> +          MOZ_ASSERT(blobOrMutableFile.type() == BlobOrMutableFile::TIPCBlob);

Nit: I would keep the blank line here.

@@ +705,5 @@
>  
>              break;
>            }
>  
> +          MOZ_ASSERT(blobOrMutableFile.type() == BlobOrMutableFile::TIPCBlob);

Nit: I would keep the blank line here.

@@ +1785,5 @@
>    }
>  }
>  
>  PBackgroundIDBDatabaseFileChild*
> +BackgroundDatabaseChild::AllocPBackgroundIDBDatabaseFileChild(const IPCBlob& aIPCBlob)

Nit: 80 chars limit

::: dom/indexedDB/IDBDatabase.cpp
@@ +31,5 @@
>  #include "mozilla/dom/indexedDB/PBackgroundIDBDatabaseFileChild.h"
>  #include "mozilla/dom/indexedDB/PBackgroundIDBSharedTypes.h"
>  #include "mozilla/ipc/BackgroundChild.h"
>  #include "mozilla/ipc/BackgroundUtils.h"
> +#include "mozilla/dom/IPCBlobUtils.h"

Nit: Why not keep mozilla/dom together ?
Attachment #8862401 - Flags: review?(jvarga) → review+
Comment on attachment 8862403 [details] [diff] [review]
part 2 - Lazy Data set to any received blob

Review of attachment 8862403 [details] [diff] [review]:
-----------------------------------------------------------------

::: dom/indexedDB/IDBObjectStore.cpp
@@ -468,5 @@
> -ResolveMysteryFile(BlobImpl* aImpl,
> -                   const nsString& aName,
> -                   const nsString& aContentType,
> -                   uint64_t aSize,
> -                   uint64_t aLastModifiedDate)

I think ResolveMysteryMutableFile() can now be remove too, it was created just to match these two methods which you are removing.

@@ +635,5 @@
>      MOZ_ASSERT(parent);
>  
>      if (aData.tag == SCTAG_DOM_BLOB) {
> +      aFile.mBlob->Impl()->SetLazyData(NullString(), aData.type, aData.size,
> +                                       INT64_MAX);

BTW, the style in IDB is to put all args on the same line or all on separate lines.
Attachment #8862403 - Flags: review?(jvarga) → review+
Comment on attachment 8862404 [details] [diff] [review]
part 3 - IPCBlob must support fileId and fullPath values for indexedDB

Review of attachment 8862404 [details] [diff] [review]:
-----------------------------------------------------------------

::: dom/file/ipc/IPCBlobUtils.cpp
@@ +151,5 @@
>    if (NS_WARN_IF(rv.Failed())) {
>      return rv.StealNSResult();
>    }
>  
> +  aIPCBlob.fileId() = aBlobImpl->GetFileId();

Nit: This should go after if/else block (before GetInternalStream call) to match the order in Deserialize().

::: dom/indexedDB/IDBObjectStore.cpp
@@ +638,5 @@
>        aFile.mBlob->Impl()->SetLazyData(NullString(), aData.type, aData.size,
>                                         INT64_MAX);
>        MOZ_ASSERT(!aFile.mBlob->IsFile());
>  
> +      // ActorParent sends here a kind of half blob and half file. Better to

Nit: ActorsParent

@@ +640,5 @@
>        MOZ_ASSERT(!aFile.mBlob->IsFile());
>  
> +      // ActorParent sends here a kind of half blob and half file. Better to
> +      // recreate the blob from scratch otherwise it can be considered a File
> +      // when maybe SetLazyData has just converted it to a Blob.

I don't understand the change here. You have |MOZ_ASSERT(!aFile.mBlob->IsFile());| after SetLazyData() call, so how come you have to recreate the blob ?
Does ActorsParent always sends us a File (not blob) ?
How come it worked ok before (with PBlob).

Please fix this or clarify and I'll r+ then
Better description. Before, PBlob was sending a Blob object and we were converting it to a File in case the tag was SCTAG_DOM_FILE. Now we send a File and we need to create a Blob if the tag is a SCTAG_DOM_BLOB. I inverted this logic in order to call GetMozFullPathInternal() correctly. There is a comment about GetMozFullPathInternal() and why I force mIsFile = true.
Attachment #8862404 - Attachment is obsolete: true
Attachment #8862404 - Flags: review?(jvarga)
Attachment #8867877 - Flags: review?(jvarga)
Ah, ToFile() did the magic before.
Comment on attachment 8862403 [details] [diff] [review]
part 2 - Lazy Data set to any received blob

Review of attachment 8862403 [details] [diff] [review]:
-----------------------------------------------------------------

::: dom/indexedDB/IDBObjectStore.cpp
@@ +635,5 @@
>      MOZ_ASSERT(parent);
>  
>      if (aData.tag == SCTAG_DOM_BLOB) {
> +      aFile.mBlob->Impl()->SetLazyData(NullString(), aData.type, aData.size,
> +                                       INT64_MAX);

and please keep the blank line before |MOZ_ASSERT(!aFile.mBlob->IsFile());|
Comment on attachment 8867877 [details] [diff] [review]
part 3 - IPCBlob must support fileId and fullPath values for indexedDB

Review of attachment 8867877 [details] [diff] [review]:
-----------------------------------------------------------------

::: dom/indexedDB/IDBObjectStore.cpp
@@ +646,5 @@
> +      // DOM File wrapping.
> +      // Before exposing it to content, we must recreate a DOM Blob object.
> +
> +      RefPtr<Blob> blob =
> +        Blob::Create(aFile.mBlob->GetParentObject(), aFile.mBlob->Impl());

One would think that there should be a ToBlob() method, but making a blob from a blob sounds weird.
Instead, it seems that we shouldn't create blob/file until we have the info from structure clone data. StructuredCloneFile could have mBlobImpl which would be set in DeserializeStructuredCloneFiles in ActorsChild.cpp
We can't replace mBlob with mBlobImpl becase serialization needs a Blob object to get the weak ref, etc.
If you think this makes sense, you can add an additional comment that would suggest doing this to avoid recreating the blob ?

@@ +647,5 @@
> +      // Before exposing it to content, we must recreate a DOM Blob object.
> +
> +      RefPtr<Blob> blob =
> +        Blob::Create(aFile.mBlob->GetParentObject(), aFile.mBlob->Impl());
> +      MOZ_ASSERT(blob);

Nit: Add a blank line after this assert.
Attachment #8867877 - Flags: review?(jvarga) → review+
Comment on attachment 8862405 [details] [diff] [review]
part 4 - ShareableBlobService

Review of attachment 8862405 [details] [diff] [review]:
-----------------------------------------------------------------

As we discussed several days ago, I think the connection between blob id and fileInfo could be maintained by FileManager.
Let me investigate if it's worth it.
> As we discussed several days ago, I think the connection between blob id and
> fileInfo could be maintained by FileManager.

The issue with what you are suggesting is that FileManager must know the inputStream of the blob. Having a connection FileManager <-> inputStream seems wrong: Today FileManager and FileInfo doesn't need to know how a Blob is implemented.
Better to keep the logic in the dom/file world, and not in the dom/indexedDB world.

Plus, in order to do that, you still need to change IPCBlobInputStreamStorage so that it can retrieve the FileManager out of the inputStream. This means that that inputStream must be wrapped. My approach is definitely simpler :)
Flags: needinfo?(jvarga)
(In reply to Andrea Marchesini [:baku] from comment #15)
> > As we discussed several days ago, I think the connection between blob id and
> > fileInfo could be maintained by FileManager.
> 
> The issue with what you are suggesting is that FileManager must know the
> inputStream of the blob. Having a connection FileManager <-> inputStream
> seems wrong: Today FileManager and FileInfo doesn't need to know how a Blob
> is implemented.
> Better to keep the logic in the dom/file world, and not in the dom/indexedDB
> world.

Yeah, but you mix all fileInfos together, so for example ShareableBlobService::Forget(FileManager* aFileManager) is not that simple. It must iterate over all entries instead of just destroying entire hashtable.
Also, IPCBlobInputStreamStorage::ForgetStream(const nsID& aID) now calls ShareableBlobService::Get()->Forget(aID) for all streams, not just IDB ones. That's additional hashtable lookup plus additional lock.
Not mentioning that we already have a mutex for FileInfos, adding a new one could be dangerous (e.g. deadlocks).

> 
> Plus, in order to do that, you still need to change
> IPCBlobInputStreamStorage so that it can retrieve the FileManager out of the
> inputStream. This means that that inputStream must be wrapped. My approach
> is definitely simpler :)

Yeah, that's a bit annoying, any other ideas how to make it simpler or avoid the wrapping ?
Flags: needinfo?(jvarga)
baku, I found out how to not add another bulky stream wrapper :)
Instead we can reuse the one in FileSnapshot.cpp
So, we can use this in ActorsParent.cpp to create a stream which holds a FileManager. This stream can be then returned in BlobImplStoredFile::GetInternalStream()

IPCBlobInputStreamStorage::ForgetStream() should probably call something like IndexedDatabaseManager::UnmapBlobInputStream(nsIInputStream* aStream)
So dom/file won't need to touch a FileManager directly.

UnmapBlobInputStream can just QI to a private interface and if it's successful, get FileManager.

Hopefully, this will all work w/o any threading issues.

I can finish it today if you are ok with it.
It's not just about using the FileSnapshot wrapper. What you are proposing is:

1. to implement a indexedDB:IDBBlobImpl. This is wrapper around FileBlobImpl that returns a IDBBlobInputStream (wrapper around a nsFileStream). This IDBBlobInputStream is the wrapper in FileSnapshot.cpp, just renamed.

2. the wrapper must be cloneable: Note that BlobImpl::GetInternalStream clones the original inputStream when called.

3. the wrapper must be serializable. This involve that we must implement the serialization of IDBBlobInputStream in IPCInputStream because this IDBBlobInputStream could be send to the child process if the blob is used with FileReader.

4. IDBBlobInputStream must implement a nsIIDBBlobInputStream. This interface must have a method that allows the storing of a FileManager.

5. FileManager must be a weakRef because we don't want to keep  it alive because of the stream (this involves a mutex).

6. Each time a IPCBlobInputStreamChild is deleted, IPCBlobInputStreamStorage must do QI to see if it is nsIIDBBlobInputStream and, if it is, we need to call: nsIIDBBlobInputStream::ForgetFileManager();

7. IDBBlobInputStream must do all of this using a mutex :/

I suspect that the number of mutex objects is higher here :) And the complexity as well.
Flags: needinfo?(jvarga)
(In reply to Andrea Marchesini [:baku] from comment #19)
> It's not just about using the FileSnapshot wrapper. What you are proposing
> is:
> 
> 1. to implement a indexedDB:IDBBlobImpl. This is wrapper around FileBlobImpl
> that returns a IDBBlobInputStream (wrapper around a nsFileStream). This
> IDBBlobInputStream is the wrapper in FileSnapshot.cpp, just renamed.

Why a wrapper around FileBlobImpl ?
IDBBlobImpl can just inherit FileBlobImpl and override just one method GetInternalStream

> 
> 2. the wrapper must be cloneable: Note that BlobImpl::GetInternalStream
> clones the original inputStream when called.

So IDBBlobImpl can just call parent class method GetInternalStream and then wrap it, no ?

> 
> 3. the wrapper must be serializable. This involve that we must implement the
> serialization of IDBBlobInputStream in IPCInputStream because this
> IDBBlobInputStream could be send to the child process if the blob is used
> with FileReader.

I'm not sure about this, what extra serialization do we need here, the wrapper stream would just contain a strong ref to a FileManager. That doesn't need to be serialized. So we use serialization which is provided by the stream we are wrapping, no ?

> 
> 4. IDBBlobInputStream must implement a nsIIDBBlobInputStream. This interface
> must have a method that allows the storing of a FileManager.

That interface can be private, only accessible in ActorsParent.cpp

> 
> 5. FileManager must be a weakRef because we don't want to keep  it alive
> because of the stream (this involves a mutex).

Hm, there are strong references to FileManager in many places. I don't think
we need a weakRef here.

> 
> 6. Each time a IPCBlobInputStreamChild is deleted, IPCBlobInputStreamStorage
> must do QI to see if it is nsIIDBBlobInputStream and, if it is, we need to
> call: nsIIDBBlobInputStream::ForgetFileManager();

Is this more expensive then doing a protected hashtable lookup for all streams (not just IDB ones).
I suspect it's actually cheaper.

> 
> 7. IDBBlobInputStream must do all of this using a mutex :/

Why using a mutex ?
The wrapper is always deleted on the owning thread (PBackground thread)


I have a question ... So, in the parent, when we serialize for the parent to child case, we create an input stream and a parent actor for it. When the actor/stream is destroyed we want to unmap the ID->FileInfo.
There's also the Clone() method, so we want to unmap only after the original and clones are destroyed, is that correct ?
Flags: needinfo?(jvarga)
> > 2. the wrapper must be cloneable: Note that BlobImpl::GetInternalStream
> > clones the original inputStream when called.
> 
> So IDBBlobImpl can just call parent class method GetInternalStream and then
> wrap it, no ?

No. Because the parent GetInternalStream returns a nsFileInputStream. You want it to return your wrapped InputStream, otherwise when we call IPCBlobUtils::Serialize(IDBBlobImpl) we send the nsFileInputStream and not yours.

> > 3. the wrapper must be serializable. This involve that we must implement the
> I'm not sure about this, what extra serialization do we need here, the
> wrapper stream would just contain a strong ref to a FileManager. That
> doesn't need to be serialized. So we use serialization which is provided by
> the stream we are wrapping, no ?

All this code runs on the parent side. The parent does: IPCBlobUtils::Serialize(IDBBlobImpl). Doing this, IPCBlobUtils calls GetInternalStream(). here you have to return a IDBInputStream (the wrapper). This stream is stored in the IPCBlobInputStreamStorage. If the content child does: FileReader(the_blob_deserialized), we need to send the 'original' blob from the parent to the child. This means that IDBInputStream _must_ implement nsIIPCSerializable. If you don't do it, the File is read on the parent side and sent to the child process. Better to move the FD.
 
> Why using a mutex ?
> The wrapper is always deleted on the owning thread (PBackground thread)

What about the FileManager? If the stream goes away, the FileManager must be informed. We have a mutex for the FileManager.

> There's also the Clone() method, so we want to unmap only after the original
> and clones are destroyed, is that correct ?

you want to unmap only when IPCBlobInputStreamStorage::Forget() is called. Note that IPCBlobInputStreamStorage keeps a reference of the inputStream. In theory you can use the DTOR of the wrapper.
(In reply to Andrea Marchesini [:baku] from comment #21)
> you want to unmap only when IPCBlobInputStreamStorage::Forget() is called.
> Note that IPCBlobInputStreamStorage keeps a reference of the inputStream. In
> theory you can use the DTOR of the wrapper.

Yeah, I suspected that the DTOR could be used, just wasn't sure.
Please give me one more day ... :)
I'm testing a patch on try, will post results soon.
Attached patch Part 4-alt (obsolete) — Splinter Review
baku, here's an alternative patch for Part 4
It doesn't need any extra wrapping, locking, etc., but one test fails on try:
https://treeherder.mozilla.org/#/jobs?repo=try&revision=6b46d4d3dab354fe2db6bee7a2206ba69f460d37

test_blob_simple.html

I'm not sure if there's a problem with this patch or you have any additional patches that fix the test_blob_simple.html failure. I remember you sent me a link with your try push and there were other patches.

So, please take a look, tell me what you think about this approach and about the test failure.

Thanks!
Attachment #8868428 - Attachment is obsolete: true
Attachment #8868899 - Flags: feedback?(amarchesini)
Attachment #8868899 - Flags: feedback?(amarchesini) → feedback+
> baku, here's an alternative patch for Part 4

Your patch looks very good. About that failure, have you applied all the other patches as well?
If yes, I need to debug your patch. Give me a bit to debug it and I let you know asap
Attached patch fix.patchSplinter Review
Funny, I'm totally sure that this bug has been fixed in some other patch.
The issue here is that in that test we do blob.slice(1,2). The size of this blob is 1. When we do readAsText() we take a sniff code. At that point the stream is closed because all the data has been read.
Later on we do a stream->Available(). This returns CLOSED, and we report this error.
Attachment #8869024 - Flags: review?(jvarga)
Attachment #8862405 - Attachment is obsolete: true
Attachment #8862405 - Flags: review?(jvarga)
Cool, I pushed it all to try to make sure we are green.
Attachment #8868899 - Attachment is obsolete: true
Attachment #8869312 - Flags: review?(amarchesini)
Comment on attachment 8869312 [details] [diff] [review]
part 4 - inputStream actor ID to FileInfo mapping

Review of attachment 8869312 [details] [diff] [review]:
-----------------------------------------------------------------

::: dom/file/ipc/IPCBlobInputStreamParent.cpp
@@ +66,5 @@
> +  }
> +}
> +
> +void
> +IPCBlobInputStreamParent::SetCallback(

Put it in the same line. There is not this indentation style in dom/file code :)

::: dom/file/ipc/IPCBlobInputStreamParent.h
@@ +22,5 @@
> +
> +  NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
> +
> +protected:
> +  virtual ~IPCBlobInputStreamParentCallback()

= default;

@@ +52,5 @@
>    Size() const
>    {
>      return mSize;
>    }
>  

Write a comment here saying that the callback will be used to inform when this actor is destroyed.
Attachment #8869312 - Flags: review?(amarchesini) → review+
Attachment #8869312 - Attachment is obsolete: true
Attachment #8869361 - Flags: review+
Comment on attachment 8869024 [details] [diff] [review]
fix.patch

Review of attachment 8869024 [details] [diff] [review]:
-----------------------------------------------------------------

Both comments say that "the stream has already been closed", but it can also happen (which is more likely) that there's nothing to read (0 bytes available to read). So maybe you could mention that too.

::: dom/workers/FileReaderSync.cpp
@@ +265,5 @@
>    if (NS_WARN_IF(aRv.Failed())) {
>      return;
>    }
>  
> +  MOZ_ASSERT(syncStream);

So if the blob is empty, ReadAsText() will return an empty string, but ReadAsDataURL() will return NS_BASE_STREAM_CLOSED error, is that right ?
Maybe we should null check the returned stream here and return empty string result too.
Note, that there's another Available() call below that.

@@ +481,5 @@
>    }
>  
>    uint64_t length;
>    nsresult rv = aAsyncStream->Available(&length);
> +  // The stream has already been closed. Nothing to do.

Nit: this comment should go before |*aSyncStream = nullptr;|
Attachment #8869024 - Flags: review?(jvarga) → review+
> So if the blob is empty, ReadAsText() will return an empty string, but
> ReadAsDataURL() will return NS_BASE_STREAM_CLOSED error, is that right ?
> Maybe we should null check the returned stream here and return empty string
> result too.

We don't do any read() before calling ConvertAsyncToSyncStream(). In ReadAsText() we do read before, and that could close the stream.
Comment on attachment 8862784 [details] [diff] [review]
part 5 - IPCBlobInputStream must implement nsIFileMetadata

Review of attachment 8862784 [details] [diff] [review]:
-----------------------------------------------------------------

This looks good too, but it can be optimized a little bit, see my comments and patch.

::: dom/indexedDB/ActorsChild.cpp
@@ +1159,5 @@
>    BackgroundRequestChild* mActor;
>    uint32_t mModuleSetIndex;
>    nsresult mResultCode;
>  
> +  // These 2 are populated when the processing of the stream pairs runs.

Nit: I would place all these additional pointer members before mModuleSetIndex.

@@ +1225,5 @@
> +  void
> +  ContinueWithStatus(nsresult aStatus);
> +
> +  void
> +  ProcessStreamPairs();

I think we can remove this method.

@@ +1241,5 @@
>    virtual nsresult
>    Cancel() override;
>  };
>  
> +NS_IMPL_ISUPPORTS_INHERITED(BackgroundRequestChild::PreprocessHelper,

Nit: This should be placed before Run() method definition.

@@ +3038,5 @@
>  PreprocessHelper::Dispatch()
>  {
>    AssertIsOnOwningThread();
>  
> +  if (!mTaskQueue) {

Please add a comment why we need a task queue now.

@@ +3090,5 @@
> +}
> +
> +void
> +BackgroundRequestChild::
> +PreprocessHelper::ContinueWithStatus(nsresult aStatus)

Nit: All these new methods, except OnInputStreamReady, should be placed before Run() method, actually before NS_IMPL_ISUPPORTS_INHERITED.

@@ +3107,5 @@
> +    MOZ_ALWAYS_SUCCEEDS(mOwningThread->Dispatch(this, NS_DISPATCH_NORMAL));
> +    return;
> +  }
> +
> +  ProcessStreamPairs();

So, here we are called with NS_OK, there's only one such caller and that's ProcessCurrentStreamPair(). If there are more stream pairs we end up calling ProcessCurrentStreamPair() which is a recursion. Recursion is fine, shouldn't be too deep. However, stack traces are a bit hard to read if there's such recursion. What about dispatching itself to the task queue instead. That should be quite cheap operation.
This way, the stack trace should always belong to one stream pair processing.

@@ +3148,3 @@
>      }
>  
> +    if (!mCurrentBytecodeFileDesc) {

We already checked mCurrentBytecodeFileDesc, don't need to do it again.
Also, I think we always want to wait for the stream. So this block can be changed to:
  if (!mCurrentBytecodeFileDesc) {
    const nsCOMPtr<nsIInputStream>& bytecodeStream = streamPair.first;
    MOZ_ASSERT(bytecodeStream);

    mCurrentBytecodeFileDesc = GetFileDescriptorFromStream(bytecodeStream);
    if (!mCurrentBytecodeFileDesc) {
      rv = WaitForStreamReady(bytecodeStream);
      if (NS_WARN_IF(NS_FAILED(rv))) {
        ContinueWithStatus(rv);
      }
      return;
    }
  }

@@ +3256,1 @@
>    return NS_OK;

|return| after MOZ_CRASH() is useless.
Attachment #8862784 - Flags: review?(jvarga)
Attached patch patch for part 5 (obsolete) — Splinter Review
Attachment #8870023 - Flags: review?(amarchesini)
Attachment #8862784 - Attachment is obsolete: true
Attachment #8870023 - Attachment is obsolete: true
Attachment #8870023 - Flags: review?(amarchesini)
Attachment #8870028 - Flags: review?(jvarga)
Comment on attachment 8870028 [details] [diff] [review]
part 5 - IPCBlobInputStream must implement nsIFileMetadata

Review of attachment 8870028 [details] [diff] [review]:
-----------------------------------------------------------------

Thanks!
Attachment #8870028 - Flags: review?(jvarga) → review+
Pushed by amarchesini@mozilla.com:
https://hg.mozilla.org/integration/mozilla-inbound/rev/f95212c33517
Use of IPCBlob in IndexedDB - part 1 - Replacement of PBlob with IPCBlob, r=janv
https://hg.mozilla.org/integration/mozilla-inbound/rev/71c721848177
Use of IPCBlob in IndexedDB - part 2 - Lazy Data set to any received blob, r=janv
https://hg.mozilla.org/integration/mozilla-inbound/rev/2132c33a4fa7
Use of IPCBlob in IndexedDB - part 3 - IPCBlob must support fileId and fullPath values for indexedDB, r=janv
https://hg.mozilla.org/integration/mozilla-inbound/rev/bf3791b00505
Use of IPCBlob in IndexedDB - part 4 - IPCBlob and sharing files when used by IDB, r=baku
https://hg.mozilla.org/integration/mozilla-inbound/rev/ed16949f7456
Use of IPCBlob in IndexedDB - part 5 - IPCBlobInputStream must implement nsIFileMetadata, r=janv
https://hg.mozilla.org/integration/mozilla-inbound/rev/e2357be6f07b
Use of IPCBlob in IndexedDB - part 6 - FileReaderSync should check if the streams are already closed, r=janv
You need to log in before you can comment on or make changes to this bug.