diff options
Diffstat (limited to 'FreeFileSync/Source/lib/binary.cpp')
-rw-r--r-- | FreeFileSync/Source/lib/binary.cpp | 134 |
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; +} |