summaryrefslogtreecommitdiff
path: root/lib/binary.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/binary.cpp')
-rw-r--r--lib/binary.cpp125
1 files changed, 125 insertions, 0 deletions
diff --git a/lib/binary.cpp b/lib/binary.cpp
new file mode 100644
index 00000000..4fdf8899
--- /dev/null
+++ b/lib/binary.cpp
@@ -0,0 +1,125 @@
+// **************************************************************************
+// * This file is part of the FreeFileSync project. It is distributed under *
+// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
+// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) *
+// **************************************************************************
+
+#include "binary.h"
+#include <wx/stopwatch.h>
+#include <vector>
+#include <zen/file_io.h>
+#include <zen/int64.h>
+#include <boost/thread/tss.hpp>
+
+inline
+void setMinSize(std::vector<char>& buffer, size_t minSize)
+{
+ if (buffer.size() < minSize) //this is similar to reserve(), but we need a "properly initialized" array here
+ buffer.resize(minSize);
+}
+
+
+namespace
+{
+class BufferSize
+{
+public:
+ BufferSize() : bufSize(BUFFER_SIZE_START) {}
+
+ void inc()
+ {
+ if (bufSize < BUFFER_SIZE_MAX)
+ bufSize *= 2;
+ }
+
+ void dec()
+ {
+ if (bufSize > BUFFER_SIZE_MIN)
+ bufSize /= 2;
+ }
+
+ operator size_t() const { return bufSize; }
+
+private:
+ static const size_t BUFFER_SIZE_MIN = 128 * 1024;
+ static const size_t BUFFER_SIZE_START = 512 * 1024; //512 kb seems to be a reasonable initial buffer size
+ static const size_t BUFFER_SIZE_MAX = 16 * 1024 * 1024;
+
+ /*Tests on Win7 x64 show that buffer size does NOT matter if files are located on different physical disks!
+ Impact of buffer size when files are on same disk:
+
+ buffer MB/s
+ ------------
+ 64 10
+ 128 19
+ 512 40
+ 1024 48
+ 2048 56
+ 4096 56
+ 8192 56
+ */
+
+ size_t bufSize;
+};
+}
+
+
+bool zen::filesHaveSameContent(const Zstring& filename1, const Zstring& filename2, CompareCallback& callback)
+{
+ FileInput file1(filename1); //throw FileError
+ FileInput file2(filename2); //throw FileError
+
+ static boost::thread_specific_ptr<std::vector<char>> cpyBuf1;
+ static boost::thread_specific_ptr<std::vector<char>> cpyBuf2;
+ if (!cpyBuf1.get())
+ cpyBuf1.reset(new std::vector<char>());
+ if (!cpyBuf2.get())
+ cpyBuf2.reset(new std::vector<char>());
+
+ std::vector<char>& memory1 = *cpyBuf1;
+ std::vector<char>& memory2 = *cpyBuf2;
+
+ BufferSize bufferSize;
+ zen::UInt64 bytesCompared;
+
+ wxLongLong lastDelayViolation = wxGetLocalTimeMillis();
+
+ do
+ {
+ setMinSize(memory1, bufferSize);
+ setMinSize(memory2, bufferSize);
+
+ const wxLongLong startTime = wxGetLocalTimeMillis();
+
+ const size_t length1 = file1.read(&memory1[0], bufferSize); //returns actual number of bytes read; throw FileError()
+ const size_t length2 = file2.read(&memory2[0], bufferSize); //
+
+ const wxLongLong stopTime = wxGetLocalTimeMillis();
+
+ //-------- dynamically set buffer size to keep callback interval between 200 - 500ms ---------------------
+ const wxLongLong loopTime = stopTime - startTime;
+ if (loopTime < 200 && stopTime - lastDelayViolation > 2000) //avoid "flipping back": e.g. DVD-Roms read 32MB at once, so first read may be > 300 ms, but second one will be 0ms!
+ {
+ lastDelayViolation = stopTime;
+ bufferSize.inc(); //practically no costs!
+ }
+ else if (loopTime > 500)
+ {
+ lastDelayViolation = stopTime;
+ bufferSize.dec(); //
+ }
+ //------------------------------------------------------------------------------------------------
+
+ if (length1 != length2 || ::memcmp(&memory1[0], &memory2[0], length1) != 0)
+ return false;
+
+ bytesCompared += length1 * 2;
+ callback.updateCompareStatus(bytesCompared); //send progress updates
+ }
+ while (!file1.eof());
+
+ if (!file2.eof()) //highly unlikely, but theoretically possible! (but then again, not in this context where both files have same size...)
+ return false;
+
+ return true;
+}
bgstack15