#include "config.h" #include #include #include #include #include #include #ifndef __FreeBSD__ #include #endif #include #ifdef HAVE_MALLOC_H #include #else #include #endif #ifdef __FreeBSD__ #define lseek64 lseek #else extern "C" __int64 lseek64(int fd, __int64 offset, int); #endif //#include //#include #include "FastReadStream.h" class FastReadStreamHeader { public: __int64 i64BlockNo; long fAccessedBits; long lBytes; long lAge; long lHistoryVal; }; FastReadStream::FastReadStream(HANDLE hFile, long lBlockCount, long lBlockSize) { this->hFile = hFile; this->iFile = -1; _Init(lBlockCount, lBlockSize); } FastReadStream::FastReadStream(int iFile, long lBlockCount, long lBlockSize) { this->hFile = INVALID_HANDLE_VALUE; this->iFile = iFile; _Init(lBlockCount, lBlockSize); } void FastReadStream::_Init(long lBlockCount, long lBlockSize) { this->lBlockCount = lBlockCount; this->lBlockSize = (lBlockSize + 4095) & -4096; this->pHeaders = new FastReadStreamHeader[this->lBlockCount]; this->pBuffer = malloc(this->lBlockCount * this->lBlockSize); if (!this->pHeaders || !this->pBuffer) { delete this->pHeaders; if (this->pBuffer) free(this->pBuffer); this->pHeaders = NULL; this->pBuffer = NULL; } else { Flush(); } lHistory = 0; } bool FastReadStream::Ready() { return pHeaders && pBuffer; } FastReadStream::~FastReadStream() { delete pHeaders; if (pBuffer) free(pBuffer); } /////////////////////////////////////////////////////////////////////////// #pragma function(memcpy) long FastReadStream::Read(int stream, __int64 i64Pos, void *pDest, long lBytes) { long lOffset, lActual = 0, lToCopy; __int64 i64BlockNo; char *pBuffer2 = (char *)pDest; int iCacheBlock; // First block number and offset... i64BlockNo = i64Pos / lBlockSize; lOffset = i64Pos % lBlockSize; // _RPT3(0,"Read request: %ld bytes, pos %I64x, first block %I64d\n", lBytes, i64Pos, i64BlockNo); while(lBytes) { long lInBlock; lToCopy = lBlockSize - lOffset; if (lToCopy > lBytes) lToCopy = lBytes; iCacheBlock = _Commit(stream, i64BlockNo); lInBlock = pHeaders[iCacheBlock].lBytes - lOffset; // _RPT4(0,"(%ld) Reading %ld from cache block %d, offset %ld\n", stream, lToCopy, iCacheBlock, lOffset); if (lInBlock < lToCopy) { if (lInBlock > 0) { memcpy(pBuffer2, (char *)pBuffer + iCacheBlock * lBlockSize + lOffset, lInBlock); lActual += lInBlock; } break; } else memcpy(pBuffer2, (char *)pBuffer + iCacheBlock * lBlockSize + lOffset, lToCopy); pBuffer2 += lToCopy; lBytes -= lToCopy; lActual += lToCopy; ++i64BlockNo; lOffset = 0; } return lActual; } void FastReadStream::Flush() { for(int i=0; i NotLone bits fStreamNotLoneBits |= fStreamEncounteredBits & pHeaders[i].fAccessedBits; fStreamEncounteredBits |= pHeaders[i].fAccessedBits; } // Look at the histories, and choose a few candidates. for(i=0; i pHeaders[iOurLowest].lAge) iOurLowest = i; // Global oldest block if (iGlobalLowest<0 || lThisHistory > pHeaders[iGlobalLowest].lAge) iGlobalLowest = i; // Preferred lowest block if (pHeaders[i].fAccessedBits & fStreamMask && !(pHeaders[i].fAccessedBits & ~fStreamNotLoneBits)) if (iPreferred<0 || lThisHistory > pHeaders[iPreferred].lAge) iPreferred = i; } return iPreferred>=0 ? iPreferred : iOurLowest>=0 ? iOurLowest : iGlobalLowest; } int FastReadStream::_Commit(int stream, __int64 i64BlockNo) { int iCacheBlock; int i; // Already have the block? for(i=0; i= 0) { int iActual; if (-1 == lseek64(iFile, i64BlockNo * lBlockSize, SEEK_SET)) return -1; // throw MyError("FastRead seek error: %s.", strerror(errno)); iActual = read(iFile, (char *)pBuffer + iCacheBlock * lBlockSize, lBlockSize); if (iActual < 0) return -1; // throw MyError("FastRead read error: %s.", strerror(errno)); pHeaders[iCacheBlock].lBytes = iActual; // } /* else { LONG lLow = (LONG)i64BlockNo*lBlockSize; LONG lHigh = (LONG)((i64BlockNo*lBlockSize) >> 32); DWORD err, dwActual; if (0xFFFFFFFF == SetFilePointer(hFile, lLow, &lHigh, FILE_BEGIN)) if ((err = GetLastError()) != NO_ERROR) return -1; // throw MyWin32Error("FastRead seek error: %%s", GetLastError()); if (!ReadFile(hFile, (char *)pBuffer + iCacheBlock * lBlockSize, lBlockSize, &dwActual, NULL)) throw MyWin32Error("FastRead read error: %%s", GetLastError()); pHeaders[iCacheBlock].lBytes = dwActual; } */ pHeaders[iCacheBlock].i64BlockNo = i64BlockNo; pHeaders[iCacheBlock].fAccessedBits = 1L<