summaryrefslogtreecommitdiff
path: root/FreeFileSync/Source/lib/binary.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'FreeFileSync/Source/lib/binary.cpp')
-rw-r--r--FreeFileSync/Source/lib/binary.cpp134
1 files changed, 134 insertions, 0 deletions
diff --git a/FreeFileSync/Source/lib/binary.cpp b/FreeFileSync/Source/lib/binary.cpp
new file mode 100644
index 00000000..0e41f7a6
--- /dev/null
+++ b/FreeFileSync/Source/lib/binary.cpp
@@ -0,0 +1,134 @@
+// **************************************************************************
+// * 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) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
+// **************************************************************************
+
+#include "binary.h"
+#include <zen/tick_count.h>
+#include <vector>
+#include <zen/file_io.h>
+#include <zen/int64.h>
+#include <boost/thread/tss.hpp>
+
+using namespace zen;
+
+
+namespace
+{
+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);
+}
+
+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 = 64 * 1024;
+ static const size_t BUFFER_SIZE_START = 128 * 1024; //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;
+};
+
+
+const std::int64_t TICKS_PER_SEC = ticksPerSec();
+}
+
+
+bool zen::filesHaveSameContent(const Zstring& filename1, const Zstring& filename2, CompareCallback& callback)
+{
+ 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;
+
+ FileInput file1(filename1); //throw FileError
+ FileInput file2(filename2); //
+
+ BufferSize bufferSize;
+
+ TickVal lastDelayViolation = getTicks();
+
+ do
+ {
+ setMinSize(memory1, bufferSize);
+ setMinSize(memory2, bufferSize);
+
+ const TickVal startTime = getTicks();
+
+ const size_t length1 = file1.read(&memory1[0], bufferSize); //throw FileError
+ const size_t length2 = file2.read(&memory2[0], bufferSize); //returns actual number of bytes read
+ //send progress updates immediately after reading to reliably allow speed calculations for our clients!
+ callback.updateCompareStatus(to<Int64>(std::max(length1, length2)));
+
+ if (length1 != length2 || ::memcmp(&memory1[0], &memory2[0], length1) != 0)
+ return false;
+
+ //-------- dynamically set buffer size to keep callback interval between 100 - 500ms ---------------------
+ if (TICKS_PER_SEC > 0)
+ {
+ const TickVal now = getTicks();
+
+ const std::int64_t loopTime = dist(startTime, now) * 1000 / TICKS_PER_SEC; //unit: [ms]
+ if (loopTime < 100)
+ {
+ if (dist(lastDelayViolation, now) / TICKS_PER_SEC > 2) //avoid "flipping back": e.g. DVD-Roms read 32MB at once, so first read may be > 500 ms, but second one will be 0ms!
+ {
+ lastDelayViolation = now;
+ bufferSize.inc();
+ }
+ }
+ else if (loopTime > 500)
+ {
+ lastDelayViolation = now;
+ bufferSize.dec();
+ }
+ }
+ //------------------------------------------------------------------------------------------------
+ }
+ while (!file1.eof());
+
+ if (!file2.eof()) //highly unlikely, but possible! (but then again, not in this context where both files have same size...)
+ return false;
+
+ return true;
+}
bgstack15