← Back to team overview

linuxdcpp-team team mailing list archive

[Branch ~dcplusplus-team/dcplusplus/trunk] Rev 2777: Mapped reader

 

------------------------------------------------------------
revno: 2777
committer: Jacek Sieka <arnetheduck@xxxxxxxxx>
branch nick: dcplusplus
timestamp: Sat 2011-12-31 16:13:51 +0100
message:
  Mapped reader
modified:
  dcpp/FileReader.cpp
  dcpp/FileReader.h
  utils/xsum.cpp


--
lp:dcplusplus
https://code.launchpad.net/~dcplusplus-team/dcplusplus/trunk

Your team Dcplusplus-team is subscribed to branch lp:dcplusplus.
To unsubscribe from this branch go to https://code.launchpad.net/~dcplusplus-team/dcplusplus/trunk/+edit-subscription
=== modified file 'dcpp/FileReader.cpp'
--- dcpp/FileReader.cpp	2011-12-31 11:50:24 +0000
+++ dcpp/FileReader.cpp	2011-12-31 15:13:51 +0000
@@ -36,28 +36,34 @@
 
 /** Read entire file, never returns READ_FAILED */
 size_t FileReader::readCached(const string& file, const DataCallback& callback) {
-	auto buf = getBuffer(512);
+	buffer.resize(getBlockSize(0));
 
+	auto buf = &buffer[0];
 	File f(file, File::READ, File::OPEN | File::SHARED);
 
 	size_t total = 0;
-	size_t n = buf.second;
-	while(f.read(buf.first, n) > 0) {
-		callback(buf.first, n);
+	size_t n = buffer.size();
+	while(f.read(buf, n) > 0) {
+		callback(buf, n);
 		total += n;
-		n = buf.second;
+		n = buffer.size();
 	}
 
 	return total;
 }
 
-pair<void*, size_t> FileReader::getBuffer(size_t alignment) {
-	auto block = (((blockSize == 0 ? DEFAULT_BLOCK_SIZE : blockSize) + alignment - 1) / alignment) * alignment;
-
-	buffer.resize(block * 2 + alignment); // Prepare for worst case alignment
-
-	auto start = reinterpret_cast<void*>(((reinterpret_cast<size_t>(&buffer[0]) + alignment - 1) / alignment) * alignment);
-	return make_pair(start, block);
+size_t FileReader::getBlockSize(size_t alignment) {
+	auto block = blockSize < DEFAULT_BLOCK_SIZE ? DEFAULT_BLOCK_SIZE : blockSize;
+	if(alignment > 0) {
+		block = ((block + alignment - 1) / alignment) * alignment;
+	}
+
+	return block;
+}
+
+void* FileReader::align(void *buf, size_t alignment) {
+	return alignment == 0 ? buf
+		: reinterpret_cast<void*>(((reinterpret_cast<size_t>(buf) + alignment - 1) / alignment) * alignment);
 }
 
 #ifdef _WIN32
@@ -86,64 +92,66 @@
 
 	if (tmp == INVALID_HANDLE_VALUE) {
 		dcdebug("Failed to open unbuffered file: %s\n", Util::translateError(::GetLastError()).c_str());
-		return false;
+		return READ_FAILED;
 	}
 
 	Handle h(tmp);
 
-	auto buf = getBuffer(sector);
-	DWORD bufSize = static_cast<DWORD>(buf.second);
+	DWORD bufSize = static_cast<DWORD>(getBlockSize(sector));
+	buffer.resize(bufSize * 2 + sector);
+
+	auto buf = align(&buffer[0], sector);
 
 	DWORD hn = 0;
 	DWORD rn = 0;
-	uint8_t* hbuf = static_cast<uint8_t*>(buf.first) + bufSize;
-	uint8_t* rbuf = static_cast<uint8_t*>(buf.first);
+	uint8_t* hbuf = static_cast<uint8_t*>(buf) + bufSize;
+	uint8_t* rbuf = static_cast<uint8_t*>(buf);
 	OVERLAPPED over = { 0 };
 
 	// Read the first block
-	auto res = ::ReadFile(h, hbuf, buf.second, &hn, &over);
-
-	if(!res) {
+	auto res = ::ReadFile(h, hbuf, bufSize, NULL, &over);
+	auto err = ::GetLastError();
+
+	if(!res && err != ERROR_IO_PENDING) {
+		if(err != ERROR_HANDLE_EOF) {
+			dcdebug("First overlapped read failed: %s\n", Util::translateError(::GetLastError()).c_str());
+			return READ_FAILED;
+		}
+	}
+
+	// Finish the read and see how it went
+	if(!GetOverlappedResult(h, &over, &hn, TRUE)) {
+		err = ::GetLastError();
+		if(err != ERROR_HANDLE_EOF) {
+			dcdebug("First overlapped read failed: %s\n", Util::translateError(::GetLastError()).c_str());
+			return READ_FAILED;
+		}
+	}
+	over.Offset = hn;
+
+	for (; hn == bufSize;) {
+		// Start a new overlapped read
+		res = ::ReadFile(h, rbuf, bufSize, NULL, &over);
 		auto err = ::GetLastError();
-		if (err == ERROR_HANDLE_EOF) {
-			hn = 0;
-		} else if(err == ERROR_IO_PENDING) {
-			// Finish the read and see how it went
-			if(!GetOverlappedResult(h, &over, &hn, TRUE)) {
-				if (::GetLastError() == ERROR_HANDLE_EOF) {
-					hn = 0;
-				} else {
-					dcdebug("First overlapped read failed: %s\n", Util::translateError(::GetLastError()).c_str());
-					return READ_FAILED;
+
+		// Process the previously read data
+		callback(hbuf, hn);
+
+		if (!res && err != ERROR_IO_PENDING) {
+			if(err != ERROR_HANDLE_EOF) {
+				throw FileException(Util::translateError(err));
+			}
+
+			rn = 0;
+		} else {
+			// Finish the new read
+			if (!GetOverlappedResult(h, &over, &rn, TRUE)) {
+				err = ::GetLastError();
+				if(err != ERROR_HANDLE_EOF) {
+					throw FileException(Util::translateError(err));
 				}
-			}
-		}
-	}
-
-	over.Offset = hn;
-
-	for (; hn > 0;) {
-		// Last read returned some bytes, start a new overlapped read
-		res = ::ReadFile(h, rbuf, buf.second, &rn, &over);
-
-		callback(hbuf, hn);
-
-		if (!res) {
-			auto err = ::GetLastError();
-			if(err == ERROR_HANDLE_EOF) {
+
 				rn = 0;
-			} else if(err == ERROR_IO_PENDING) {
-				// Finish the read
-				if (!GetOverlappedResult(h, &over, &rn, TRUE)) {
-					err = ::GetLastError();
-					if(err != ERROR_HANDLE_EOF) {
-						throw FileException(Util::translateError(err));
-					}
-
-					rn = 0;
-				}
-			} else {
-				throw FileException(Util::translateError(::GetLastError()));
 			}
 		}
 
@@ -153,11 +161,64 @@
 		swap(rn, hn);
 	}
 
+	if(hn != 0) {
+		// Process leftovers
+		callback(hbuf, hn);
+	}
+
 	return *((uint64_t*)&over.Offset);
 }
 
 size_t FileReader::readMapped(const string& file, const DataCallback& callback) {
-	return READ_FAILED;
+	auto tfile = Text::toT(file);
+
+	auto tmp = ::CreateFile(tfile.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
+		FILE_FLAG_SEQUENTIAL_SCAN, NULL);
+
+	if (tmp == INVALID_HANDLE_VALUE) {
+		dcdebug("Failed to open unbuffered file: %s\n", Util::translateError(::GetLastError()).c_str());
+		return READ_FAILED;
+	}
+
+	Handle h(tmp);
+
+	LARGE_INTEGER size = { 0 };
+	if(!::GetFileSizeEx(h, &size)) {
+		dcdebug("Couldn't get file size: %s\n", Util::translateError(::GetLastError()).c_str());
+		return READ_FAILED;
+	}
+
+	if(!(tmp = ::CreateFileMapping(h, NULL, PAGE_READONLY, 0, 0, NULL))) {
+		dcdebug("Couldn't create file mapping: %s\n", Util::translateError(::GetLastError()).c_str());
+		return READ_FAILED;
+	}
+
+	Handle hmap(tmp);
+
+	SYSTEM_INFO si = { 0 };
+	::GetSystemInfo(&si);
+
+	auto blockSize = getBlockSize(si.dwPageSize);
+
+	LARGE_INTEGER total = { 0 };
+	while(size.QuadPart > 0) {
+		auto n = min(size.QuadPart, (int64_t)blockSize);
+		auto p = ::MapViewOfFile(hmap, FILE_MAP_READ, total.HighPart, total.LowPart, static_cast<DWORD>(n));
+		if(!p) {
+			throw FileException(Util::translateError(::GetLastError()));
+		}
+
+		callback(p, n);
+
+		if(!::UnmapViewOfFile(p)) {
+			throw FileException(Util::translateError(::GetLastError()));
+		}
+
+		size.QuadPart -= n;
+		total.QuadPart += n;
+	}
+
+	return total.QuadPart;
 }
 
 #else

=== modified file 'dcpp/FileReader.h'
--- dcpp/FileReader.h	2011-12-31 11:50:24 +0000
+++ dcpp/FileReader.h	2011-12-31 15:13:51 +0000
@@ -71,7 +71,8 @@
 	vector<uint8_t> buffer;
 
 	/** Return an aligned buffer which is at least twice the size of ret.second */
-	pair<void*, size_t> getBuffer(size_t alignment);
+	size_t getBlockSize(size_t alignment);
+	void* align(void* buf, size_t alignment);
 
 	size_t readDirect(const string& file, const DataCallback& callback);
 	size_t readMapped(const string& file, const DataCallback& callback);

=== modified file 'utils/xsum.cpp'
--- utils/xsum.cpp	2011-12-31 11:50:24 +0000
+++ utils/xsum.cpp	2011-12-31 15:13:51 +0000
@@ -3,6 +3,8 @@
 #include <dcpp/stdinc.h>
 #include <dcpp/FileReader.h>
 #include <dcpp/Util.h>
+#include <dcpp/MerkleTree.h>
+#include <stdlib.h>
 
 #include <boost/date_time/posix_time/ptime.hpp>
 using namespace boost::posix_time;
@@ -12,28 +14,33 @@
 
 int main(int argc, char** argv)
 {
-	if(argc != 2) {
+	if(argc < 2) {
 		cout << "You need to supply a file name" << endl;
 		return 1;
 	}
 
 	char x[_MAX_PATH] = { 0 };
-	char * tmp;
-	if(!(tmp = _fullpath(x, argv[1], _MAX_PATH))) {
+	if(!_fullpath(x, argv[1], _MAX_PATH)) {
 		cout << "Can't get full path" << endl;
 		return 1;
 	}
+
 	try {
 		auto start = microsec_clock::universal_time();
-		FileReader fr(true, 0);
+		FileReader fr(argc == 2 ? true : argv[2][0] == '0', 0);
 
+		TigerTree tt;
 		size_t total = 0;
-		fr.read(tmp, [&](void* x, size_t n) {
+		fr.read(x, [&](void* x, size_t n) {
+			tt.update(x, n);
 			total += n;
 			if(total % (1024*1024) == 0) {
 				std::cout << ".";
 			}
 		});
+
+		cout << endl << Encoder::toBase32(tt.finalize(), TigerTree::BYTES);
+
 		auto diff = (microsec_clock::universal_time() - start).total_microseconds();
 		auto s = diff / 1000000.0;
 		if(s == 0) s = 1;