// ********************************************************************** // // Copyright (c) 2003-2010 ZeroC, Inc. All rights reserved. // // This copy of Ice is licensed to you under the terms described in the // ICE_LICENSE file included in this distribution. // // ********************************************************************** #include #include #include #include #include #include using namespace std; using namespace IceGrid; FileCache::FileCache(const Ice::CommunicatorPtr& com) : _messageSizeMax(com->getProperties()->getPropertyAsIntWithDefault("Ice.MessageSizeMax", 1024) * 1024 - 256) { } Ice::Long FileCache::getOffsetFromEnd(const string& file, int originalCount) { IceUtilInternal::ifstream is(file); // file is a UTF-8 string if(is.fail()) { throw FileNotAvailableException("failed to open file `" + file + "'"); } if(originalCount < 0) { return 0; } is.seekg(0, ios::end); streampos endOfFile = is.tellg(); if(originalCount == 0) { return endOfFile; } streamoff blockSize = 16 * 1024; // Start reading a block of 16K from the end of the file. streampos lastBlockOffset = endOfFile; int totalCount = 0; string line; deque > lines; do { lines.clear(); // // Move the current position of the stream to the new block to // read. // is.clear(); if(lastBlockOffset - blockSize > streamoff(0)) { is.seekg(lastBlockOffset - blockSize); getline(is, line); // Ignore the first line as it's most likely not complete. } else { is.seekg(0, ios::beg); // We've reach the begining of the file. } // // Read the block and count the number of lines in the block // If we found the "first last N lines", we start throwing out // the lines read at the begining of the file. // int count = originalCount - totalCount; // Number of lines left to find. while(is.good() && is.tellg() <= streamoff(lastBlockOffset)) { streampos beg = is.tellg(); getline(is, line); if(is.eof() && line.empty()) // Don't count the last line if it's empty. { continue; } lines.push_back(make_pair(beg, line)); ++totalCount; if(lines.size() == static_cast(count + 1)) { --totalCount; lines.pop_front(); } } if(lastBlockOffset - blockSize < streamoff(0)) { break; // We're done if the block started at the begining of the file. } else if(totalCount < originalCount) { // // Otherwise, it we still didn't find the required number of lines, // read another block of text before this block. // lastBlockOffset -= blockSize; // Position of the block we just read. blockSize *= 2; // Read a bigger block. } } while(totalCount < originalCount && !is.bad()); if(is.bad()) { throw FileNotAvailableException("unrecoverable error occured while reading file `" + file + "'"); } if(lines.empty()) { return 0; } else { return lines[0].first; } } bool FileCache::read(const string& file, Ice::Long offset, int size, Ice::Long& newOffset, Ice::StringSeq& lines) { assert(size > 0); if(size > _messageSizeMax) { size = _messageSizeMax; } if(size <= 5) { throw FileNotAvailableException("maximum bytes per read request is too low"); } IceUtilInternal::ifstream is(file); // file is a UTF-8 string if(is.fail()) { throw FileNotAvailableException("failed to open file `" + file + "'"); } // // Check if the requested offset is past the end of the file, if // that's the case return an empty sequence of lines and indicate // the EOF. // is.seekg(0, ios::end); if(offset >= is.tellg()) { newOffset = is.tellg(); lines = Ice::StringSeq(); return true; } // // Read lines from the file until we read enough or reached EOF. // newOffset = offset; lines = Ice::StringSeq(); #if defined(_MSC_VER) && (_MSC_VER < 1300) is.seekg(static_cast(offset)); #else is.seekg(static_cast(offset), ios::beg); #endif int totalSize = 0; string line; for(int i = 0; is.good(); ++i) { getline(is, line); int lineSize = static_cast(line.size()) + 5; // 5 bytes for the encoding of the string size (worst case) if(lineSize + totalSize > size) { if(totalSize + 5 < size) { // There's some room left for a part of the string, return a partial string line = line.substr(0, size - totalSize - 5); lines.push_back(line); newOffset += line.size(); } else { lines.push_back(""); } return false; // We didn't reach the end of file, we've just reached the size limit! } totalSize += lineSize; lines.push_back(line); #if defined(_MSC_VER) && (_MSC_VER < 1300) if(is.eof()) { newOffset += line.size(); } else #else if(!is.fail()) #endif { newOffset = is.tellg(); } } if(is.bad()) { throw FileNotAvailableException("unrecoverable error occured while reading file `" + file + "'"); } return is.eof(); }