e.BytesTransferred / e.TotalBytesToTransfer error?

Jun 19, 2009 at 2:33 PM

Cheeso,

Testing v1.8.3.29 and having a bytes transferred issue when I update - only update.

Stack Trace:

6/19/2009 10:12:18 AM
Value of '101' is not valid for 'Value'. 'Value' should be between 'minimum' and 'maximum'.
Parameter name: Value
   at System.Windows.Forms.ProgressBar.set_Value(Int32 value)
   at SMG_Backup.MainForm.zipFileUpdate_SaveProgress(Object sender, SaveProgressEventArgs e) in C:\Users\jeffy.SELLETHICS\Documents\Visual Studio 2005\Projects\SMG Backup\SMG Backup\MainForm.vb:line 295
   at Ionic.Zip.ZipFile.OnSaveBlock(ZipEntry entry, Int64 bytesXferred, Int64 totalBytesToXfer)
   at Ionic.Zip.ZipEntry.OnWriteBlock(Int64 bytesXferred, Int64 totalBytesToXfer)
   at Ionic.Zip.ZipEntry.CopyThroughOneEntry(Stream outstream)
   at Ionic.Zip.ZipEntry.Write(Stream s)
   at Ionic.Zip.ZipFile.Save()
   at SMG_Backup.MainForm.ZipUpdate(String OriginalFile) in C:\Users\jeffy.SELLETHICS\Documents\Visual Studio 2005\Projects\SMG Backup\SMG Backup\MainForm.vb:line 227

Line 227 calls the zipsave, line 295 is in my progress bar code as follows:

    Private Sub zipFileUpdate_SaveProgress(ByVal sender As Object, ByVal e As Ionic.Zip.SaveProgressEventArgs) Handles zipFileUpdate.SaveProgress

        If e.EntriesTotal > 0 Then
            pbarTotal.Maximum = e.EntriesTotal
        End If

        If e.EntriesSaved > 0 Then
            pbarTotal.Value = e.EntriesSaved
        End If

        If e.BytesTransferred > 0 Then
   **line 295**         pbarCurrent.Value = CType((e.BytesTransferred / e.TotalBytesToTransfer) * 100, Integer)
            lblCurrentFile.ResetText()
            lblCurrentFile.Text = e.CurrentEntry.FileName
            lblCurrentFile.Update()
        End If

        Application.DoEvents()

    End Sub
I have the same exact code for a zipArchive_SaveProgress for the "full".
When I do a full, it works, when I do a partial - it fails with the stack trace I reported above. I haven't changed anything except adding the new v1.8.3.29.
I stepped thru the code taking note of the byte values (reference line 295 above for the format)
45966/45829*100
48715/48593*100
8192/8133*100 (it errors on this one)
Now, BytesTransferred should not be higher than TotalBytesToTransfer I would think, yet it is. Obviously, doing the math, sooner or later I will exceed my maximum value of 100.
Yet on the 3 examples\files above pbarcurrent.value is 100.298 (100), 100.251 (100), and 100.725 (101 and thus error).
Again, it only happens on updating the archive.
Advice? I assume something happened in the new version that is more correct than before but now is exposing my code\errors, or the code has a bug.
Jun 19, 2009 at 2:41 PM
Edited Jun 19, 2009 at 2:42 PM

I stepped thru the code on the full and the bytestransferred never exceeded the totalbytestotransfer. (I stopped looking after about 5 files.)

Coordinator
Jun 19, 2009 at 4:49 PM

Two things.

  1. You've identified a bug.  When updating. TotalBytesToTransfer gets set incorrectly. Actually the broken code is setting TotalBytesToTransfer to the size of the compressed bytestream for an entry.  But there are metadata that need to be transferred, too, when updating a zip file.  This accounts for the difference of 59 bytes, or 122 bytes, or 137 bytes in your examples.
  2. In general, there's no guarantee that BytesTransferred will be less than or equal to TotalBytesToTransfer.   In some cases, when creating new zip files, TotalBytesToTransfer will be zero.  This can happen when zipping up from a forward-only (non seekable) stream. This is not happening in your case!  In your case you have a filesystem file, and it is seekable.  In that case, when the bug is fixed, you will be able to rely on the fact that BytesTransferred <= TotalBytesToTransfer.

Some additional detail:
The Save() takes a different code path when updating, versus creating a zip the first time.  When creating a zip entry, the progress event tracks only the file data, not metadata.  The "denominator" in this case - the TotalBytesToTransfer - is set to the size of the uncompressed data. in your case, the length of the file. When calling Save() on an updated zip, any entry that is unchanged is just transferred from the original zip file to the new one.  The update copies the entire zipentry -  header, compressed bytes and footer. But it was using only the size of the compressed bytestream as the TotalBytesToTransfer.

I've fixed that now.


You have a couple options:

  • code defensively and just round down.  
  • wait for v1.8.3.31, which has the fix.

 

Coordinator
Jun 19, 2009 at 4:53 PM

v1.8.3.31 will be up shortly.

Coordinator
Jun 19, 2009 at 5:12 PM

v1.8.3.31 is now up.

Jun 19, 2009 at 6:21 PM

Again, you rock...Penguins style.

Seems to work just fine now. I'll also work on coding more defensive in general and round down.

Thanks.