Closed Bug 941063 Opened 6 years ago Closed 5 years ago

Add a property to get the size of the downloads data written to disk

Categories

(Toolkit :: Downloads API, defect)

defect
Not set
Points:
3

Tracking

()

RESOLVED FIXED
mozilla38
Iteration:
38.1 - 26 Jan
Tracking Status
firefox26 --- wontfix
firefox27 + wontfix
firefox28 - affected
firefox29 - affected
firefox30 --- affected

People

(Reporter: Paolo, Assigned: Paolo)

References

(Blocks 2 open bugs)

Details

(Keywords: dev-doc-complete)

Attachments

(1 file, 3 obsolete files)

Add a property to the Download object to get the final file size on disk, that may work for completed downloads or canceled downloads that have partial data.

The size on disk might be different from the size of the data transferred from the server, if the data is decoded while downloading.
Depends on: 931477
We could have a property like "download.target.size" that is updated from disk when the download stops, and also when the "refresh" method is called on a finished, failed, or canceled download. Any change would trigger the "onchange" callback.

Optionally, this property could consider the size of the ".part" file, if available, for failed or canceled downloads.

While here, it is quite simple to also add a boolean that tells if the target of a successful download can be launched, with a similar refresh logic. It could be called "download.canLaunch" (or alternatively a "download.target.exists" property can be used). This will allow the front-end to disable the launch action if the user removes the file.
Hi Paolo,

Given we are already done with a couple of beta's for Firefox 27 and since there has not been any progress on this bug yet, can you please recommend next steps for Firefox 27 ?

This was tracked in reference to https://bugzilla.mozilla.org/show_bug.cgi?id=943843#c3
Flags: needinfo?(paolo.mozmail)
Thanks for the reminder! I don't think I'll have the bandwidth to work on this until after the Firefox Desktop work week. Given that this affects reporting the download size only for data compressed at the HTTP encoding level, which is not a very common case in downloads, I lean towards WONTFIXing bug 943843 for Firefox 27, and aim to get a proper fix for Firefox 28.
Flags: needinfo?(paolo.mozmail)
Based on Paolo's comment 3 I don't see this as a release-blocking issue we need to track since it's not a common download case.  We can consider a low-risk nomination for uplift to branches when a fix is verified.
Blocks: 1024918
Blocks: 1087228
Attached patch Initial work (obsolete) — Splinter Review
This issue is more common on Thunderbird because most of attachment files are base64-encoded.
I confirmed this patch works fine on Thunderbird.
I think a new test case of decoding data is necessary but I have not idea how to write such case in mozilla-central now. Just using .gz for test file is sufficient?

One thing I noticed is that progress value which is calculated in refresh() is wrong in case of decoding data.  It is calculated from the file size on disk but it should be transferred bytes in case of the data is encoded.
Attachment #8518578 - Flags: feedback?(paolo.mozmail)
Attached patch Initial work v2 (obsolete) — Splinter Review
I found there are some test cases for .gz encoding data.
Attachment #8518578 - Attachment is obsolete: true
Attachment #8518578 - Flags: feedback?(paolo.mozmail)
Attachment #8518588 - Flags: feedback?(paolo.mozmail)
Comment on attachment 8518588 [details] [diff] [review]
Initial work v2

Thanks for the patch! The approach looks good, but I'd appreciate if you can update the implementation to be optimized, reusing existing OS.File.stat calls or information we already have about the download. This probably implies ad-hoc updates instead of a helper function.

We also need a test for the value of "target.size" for the case of interrupted downloads.

(In reply to Hiroyuki Ikezoe (:hiro) from comment #5)
> One thing I noticed is that progress value which is calculated in refresh()
> is wrong in case of decoding data.  It is calculated from the file size on
> disk but it should be transferred bytes in case of the data is encoded.

This works because, unfortunately, encoded downloads cannot be resumed, so we never retain partial data for them. Feel free to add a comment to clarify!
Attachment #8518588 - Flags: feedback?(paolo.mozmail) → feedback+
Attached patch Revised patch (obsolete) — Splinter Review
I've forgotten that I pushed a new patch on try server.
This patch is revised as Paolo advised in comment #7.

Please correct me if I am misunderstanding the advices.
  
https://treeherder.mozilla.org/ui/#/jobs?repo=try&revision=2253c3a6f7aa
Attachment #8518588 - Attachment is obsolete: true
Attachment #8521866 - Flags: review?(paolo.mozmail)
Comment on attachment 8521866 [details] [diff] [review]
Revised patch

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

Sorry for the delay. The changes you made look good!

Since I haven't had time to investigate if all the cases we can encounter are covered, this patch might need another round of review. However, to speed things up, I'm already asking you about the possible improvements I found.

First, I've noticed "this.DownloadTarget.prototype" needs a definition for "size" with a JavaDoc-style comment. The value in the prototype, as well as the value set if the file does not exist, should be 0 (and the comment should of course mention this).

While not strictly required, it would be great if you could add a new "exists" property on the prototype, and update it in the code as well. In fact, the code path for it is the same and we need it for other uses in the interface.

::: toolkit/components/jsdownloads/src/DownloadCore.jsm
@@ +491,5 @@
>            this.stopped = true;
>            this.speed = 0;
> +          if (this.hasPartialData && this.target.partFilePath) {
> +            this.target.size = this.currentBytes;
> +          } else if (yield OS.File.exists(this.target.path)) {

In this code path, you can assume the target exists, as an optimization.

However, you should still catch and report exceptions with the "stat" call. Something like:

try {
  this.target.size = (yield OS.File.stat(this.target.path)).size;
} catch (ex) {
  this.target.size = 0;
  Cu.reportError(ex);
}

@@ +779,2 @@
>        }
> +      this._notifyChange();

We should notify a change only if we really changed the "size" (or "exists") properties.

::: toolkit/components/jsdownloads/test/unit/common_test_Download.js
@@ +148,5 @@
>    // Check additional properties on the finished download.
>    do_check_true(download.source.referrer === null);
>  
>    yield promiseVerifyContents(download.target.path, TEST_DATA_SHORT);
> +  do_check_eq(download.target.size, TEST_DATA_SHORT.length);

Since we're using this pattern many times, can you please define a test helper function at the top of the file, that gets called like this:

promiseVerifyTarget(download.target, TEST_DATA_SHORT);

It should call promiseVerifyContents using the "path" property, then check that the "size" property matches the length of the second argument, and finally check that "exists" is true.

(In cases where we're checking that the file does not exits, we won't use this helper function.)
Attachment #8521866 - Flags: review?(paolo.mozmail) → feedback+
(In reply to :Paolo Amadini from comment #9)
> @@ +779,2 @@
> >        }
> > +      this._notifyChange();
> 
> We should notify a change only if we really changed the "size" (or "exists")
> properties.

Clarification: this in the "refresh" code path (it didn't show up in the review context).
Hey hiro, if you're not working on this I might help in moving it forward, as the patch may be useful for reducing main-thread I/O in the front-end.
Yes, please!
Blocks: 830675
Attached patch ContinuedSplinter Review
Updated hiro's patch. Steven, do you think you can review this?
Assignee: nobody → paolo.mozmail
Attachment #8521866 - Attachment is obsolete: true
Status: NEW → ASSIGNED
Attachment #8545965 - Flags: review?(smacleod)
Flags: qe-verify-
Flags: firefox-backlog+
Iteration: --- → 37.3 - 12 Jan
Comment on attachment 8545965 [details] [diff] [review]
Continued

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

This looks good to me.

It seems that the new properties are not updated based on partial progress:

(In reply to :Paolo Amadini from comment #1)
> We could have a property like "download.target.size" that is updated from
> disk when the download stops, and also when the "refresh" method is called
> on a finished, failed, or canceled download. Any change would trigger the
> "onchange" callback.
> 
> Optionally, this property could consider the size of the ".part" file, if
> available, for failed or canceled downloads.

All of the in code comments are clear that this is only used for the target
file and not the partFilePath, so I'm just going to assume you decided against
using this with partial data as well.

::: toolkit/components/jsdownloads/src/DownloadCore.jsm
@@ +1364,5 @@
> +   * Size in bytes of the target file, or zero if the download has not finished.
> +   *
> +   * Even if the target file does not exist anymore, this property may still
> +   * have a value taken from the download metadata, but it will be zero if the
> +   * file has been deleted and the size information is not available.

"but it will be zero if the file has been deleted" is not true if the file has been deleted by an external program or user action. We should maybe clarify this comment.
Attachment #8545965 - Flags: review?(smacleod) → review+
Hi Paolo, can you provide a point value.
Flags: needinfo?(paolo.mozmail)
Points: --- → 3
Flags: needinfo?(paolo.mozmail)
(In reply to Steven MacLeod [:smacleod] from comment #14)
> All of the in code comments are clear that this is only used for the target
> file and not the partFilePath, so I'm just going to assume you decided
> against using this with partial data as well.

Correct, this turned out to be unneeded in the front-end.

> ::: toolkit/components/jsdownloads/src/DownloadCore.jsm
> "but it will be zero if the file has been deleted" is not true if the file
> has been deleted by an external program or user action. We should maybe
> clarify this comment.

What about:

   * Even if the target file does not exist anymore, this property may still
   * have a value taken from the download metadata. If the metadata has never
   * been available in this session and the size cannot be obtained from the
   * file because it has been deleted, this property will be zero.
Documentation needed for the new DownloadTarget properties and the extended descriptions of some Download properties.
Keywords: dev-doc-needed
Iteration: 37.3 - 12 Jan → 38.1 - 26 Jan
https://hg.mozilla.org/mozilla-central/rev/f4f95ebb94e9
Status: ASSIGNED → RESOLVED
Closed: 5 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla38
You need to log in before you can comment on or make changes to this bug.