[Box Backup-dev] Seeking code review for file diff changes...
Alex Harper
boxbackup-dev@fluffy.co.uk
Tue, 04 Mar 2008 09:22:03 -0800
> This message is in MIME format. Since your mail reader does not understand
this format, some or all of this message may not be legible.
--B_3287467331_35320320
Content-type: text/plain;
charset="US-ASCII"
Content-transfer-encoding: 7bit
Hi,
As previously mentioned on the user discussion list, I'm looking for a code
review of the enclosed patch. This is a fairly substantial change to the
file diff process in an attempt to address the high CPU and IO load I
observed while backing up some of my files.
The patch makes several fundamental changes to the diff logic:
- Files are read no more than twice (versus read again and again for every
block size).
- Before performing a rolling checksum each server-side block is first
checked (by MD5) at its previous location in the file. In the event the
block has not changed or moved, the rolling checksum is skipped.
- Rolling checksums are searched in total-file-coverage order (size times
number of blocks) favoring larger blocks in the final recipe.
In my testing file diff is now CPU bound instead of disk IO bound. As a
result diff wall time was improved from 2-10x.
The patch should be applicable to trunk (tested with rev 2104). I have
tested on OS X (i386). I have not tested on other Unix-like OSes or Win32,
however, I have added no new dependencies or platform calls so I expect it
introduces no new platform issues.
The patch passes all unittests and I've been using variants of this code on
my own data for several days without problems. However, obviously this is a
big change and deserves careful attention. I'm hoping sharp eyes may find
anything I missed.
Questions and comments appreciated, I'd also love some guidance on how to
get broader user testing.
Thanks,
Alex
--
Alex Harper aharper@foobox.net
"Eternity is a terrible thought. I mean, where's it going to end?"
- Tom Stoppard
--B_3287467331_35320320
Content-type: application/octet-stream; name="BackupFileDiff.patch.zip"
Content-disposition: attachment;
filename="BackupFileDiff.patch.zip"
Content-transfer-encoding: base64
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
xLftuhII8rjx
JkKTBX8V/iP7pWLJsFGJIujHjR97myiCtra3ez+KUYhHHGA0AE9FmVOaiQhSLqE+nhwmi7LA
yVHv2Ws9ihd6gEcmfcC6grYHAIicL/Zs1ZSPq/sD/fvVN43PZE9PonKGMQwchTuarUf3q0ua
ulzARAyxMgfPAWQS8upR2mvv0iT/Kcv+OKEN9iMQMoVrCLdyrzKu1ebGxv3eFi7WvXsPe5uy
WvAlOqGsw4nHVNP1FE9hy0yBBor3f5g0/jIxw09n1mGFx37RBMht9eFIn1O62QG35ofHMyH3
3/CSlEdX9/N2K9h9XcEq394G4qzzj6Tm6XC//SPhjKjhtiKh+2x2pjgSepbTHAyd2iiqBCr+
pN7F0VUmeXyKvB45AMen4MdPlfbo8tKemLvyl55LdzTFy0ff3d+WAI//N5INUs3bw6N7W+JD
XYDSU0zaw5669d3Dw/vbY5iN8c912tLbO40OkxO8dIePebRSTkJU1wAGLAd7fnkIDsj2Ggb1
JVCcNWMYE+hmBEp9lyv6xV9+guWxVOhuWS+U1vPkluJ//Vs7Q29s/kdiUhuHfPfPH4iIpJZR
xVbum1vWx7l+c+fa/P9QSwcIJZwKNHgvAADPugAAUEsDBAoAAAAAAMJKZDgAAAAAAAAAAAAA
AAAJABAAX19NQUNPU1gvVVgMADyFzUc8hc1H3QUUAFBLAwQUAAgACAB2oWM4AAAAAAAAAAAA
AAAAHwAQAF9fTUFDT1NYLy5fQmFja3VwRmlsZURpZmYucGF0Y2hVWAwABEvNRwDMzEfdBVAA
Y2AVY2dgYmDwTUxW8A9WiFCAApAYAycQGwGxAhCD+EFAzBDiGhHCgAcAAFBLBwgQ0slKKwAA
AFIAAABQSwECFQMUAAgACAB2oWM4JZwKNHgvAADPugAAFAAMAAAAAAAAAABApIEAAAAAQmFj
a3VwRmlsZURpZmYucGF0Y2hVWAgABEvNRwDMzEdQSwECFQMKAAAAAADCSmQ4AAAAAAAAAAAA
AAAACQAMAAAAAAAAAABA/UHKLwAAX19NQUNPU1gvVVgIADyFzUc8hc1HUEsBAhUDFAAIAAgA
dqFjOBDSyUorAAAAUgAAAB8ADAAAAAAAAAAAQKSBATAAAF9fTUFDT1NYLy5fQmFja3VwRmls
ZURpZmYucGF0Y2hVWAgABEvNRwDMzEdQSwUGAAAAAAMAAwDqAAAAiTAAAAAA
--B_3287467331_35320320--