private void reportProblem(Exception e) { StringBuilder sb = new StringBuilder(); sb.append("Halted log file reading at file 0x") .append(Long.toHexString(window.currentFileNum())) .append(" offset 0x") .append(Long.toHexString(nextEntryOffset)) .append(" offset(decimal)=") .append(nextEntryOffset) .append(" prev=0x") .append(Long.toHexString(currentEntryPrevOffset)); if (currentEntryHeader != null) { LogEntryType problemType = LogEntryType.findType(currentEntryHeader.getType()); sb.append(":\nentry=") .append(problemType) .append("type=") .append(currentEntryHeader.getType()) .append(",version=") .append(currentEntryHeader.getVersion()) .append(")\nprev=0x") .append(Long.toHexString(currentEntryPrevOffset)) .append("\nsize=") .append(currentEntryHeader.getItemSize()) .append("\nNext entry should be at 0x") .append( Long.toHexString( nextEntryOffset + currentEntryHeader.getSize() + currentEntryHeader.getItemSize())); } LoggerUtils.traceAndLogException(envImpl, "FileReader", "readNextEntry", sb.toString(), e); }
/** Copy the required number of bytes into the save buffer. */ private void copyToSaveBuffer(int bytesNeeded) { /* How much can we get from this current read buffer? */ int bytesFromThisBuffer; if (bytesNeeded <= window.remaining()) { bytesFromThisBuffer = bytesNeeded; } else { bytesFromThisBuffer = window.remaining(); } /* Gather it all into this save buffer. */ ByteBuffer temp; /* Make sure the save buffer is big enough. */ if (saveBuffer.capacity() - threadSafeBufferPosition(saveBuffer) < bytesFromThisBuffer) { /* Grow the save buffer. */ temp = ByteBuffer.allocate(saveBuffer.capacity() + bytesFromThisBuffer); threadSafeBufferFlip(saveBuffer); temp.put(saveBuffer); saveBuffer = temp; } /* * Bulk copy only the required section from the read buffer into the * save buffer. We need from readBuffer.position() to * readBuffer.position() + bytesFromThisBuffer */ temp = window.getBuffer().slice(); temp.limit(bytesFromThisBuffer); saveBuffer.put(temp); window.incrementBufferPosition(bytesFromThisBuffer); }
/** * Try to read a specified number of bytes. * * @param amountToRead is the number of bytes we need * @param collectData is true if we need to actually look at the data. If false, we know we're * skipping this entry, and all we need to do is to count until we get to the right spot. * @return a byte buffer positioned at the head of the desired portion, or null if we reached eof. */ private ByteBuffer readData(int amountToRead, boolean collectData) throws ChecksumException, EOFException, FileNotFoundException, DatabaseException { int alreadyRead = 0; ByteBuffer completeBuffer = null; saveBuffer.clear(); while ((alreadyRead < amountToRead) && !eof) { int bytesNeeded = amountToRead - alreadyRead; if (window.hasRemaining()) { /* There's data in the window, process it. */ if (collectData) { /* * Save data in a buffer for processing. */ if ((alreadyRead > 0) || (window.remaining() < bytesNeeded)) { /* We need to piece an entry together. */ copyToSaveBuffer(bytesNeeded); alreadyRead = threadSafeBufferPosition(saveBuffer); completeBuffer = saveBuffer; } else { /* A complete entry is available in this buffer. */ completeBuffer = window.getBuffer(); alreadyRead = amountToRead; } } else { /* * We're not processing the data, so need to save it. just * move buffer positions. */ int positionIncrement = (window.remaining() > bytesNeeded) ? bytesNeeded : window.remaining(); alreadyRead += positionIncrement; window.incrementBufferPosition(positionIncrement); completeBuffer = window.getBuffer(); } } else { /* * Look for more data. */ if (window.fillNext(singleFile, bytesNeeded)) { /* This call to fillNext slid the window to a new file. */ nextEntryOffset = 0; } } } /* Flip the save buffer just in case we've been accumulating in it. */ threadSafeBufferFlip(saveBuffer); return completeBuffer; }
void startSwitchingToReadMode(ReadWindow window) { readCacheStatus = READ_CACHE_STATUS.SWITCHINGTOREADMODE; i2cDevice.enableI2cReadMode(window.getIregFirst(), window.getCreg()); enabledReadMode = true; // Remember what we actually told the controller readWindowSentToController = window; readWindowSentToControllerInitialized = true; setActionFlag = true; // causes an I2C read to happen queueFullWrite = true; // for just the mode bytes queueRead = true; // read the mode byte so we can tell when the switch is done dirtyModeCacheStatus(); }
/** Helper for determining the starting position and opening up a file at the desired location. */ protected void initStartingPosition(long endOfFileLsn, Long ignoreSingleFileNumber) { eof = false; if (forward) { /* * Start off at the startLsn. If that's null, start at the * beginning of the log. If there are no log files, set eof. */ if (startLsn != DbLsn.NULL_LSN) { window.initAtFileStart(startLsn); } else { Long firstNum = fileManager.getFirstFileNum(); if (firstNum == null) { eof = true; } else { window.initAtFileStart(DbLsn.makeLsn(firstNum, 0)); } } /* * After we read the first entry, the currentEntry will point here. */ nextEntryOffset = window.getEndOffset(); } else { /* * Make the read buffer look like it's positioned off the end of * the file. Initialize the first LSN we want to read. When * traversing the log backwards, we always start at the very end. */ assert startLsn != DbLsn.NULL_LSN; window.initAtFileStart(endOfFileLsn); /* * currentEntryPrevOffset points to the entry we want to start out * reading when going backwards. If it's 0, the entry we want to * read is in a different file. */ if (DbLsn.getFileNumber(startLsn) == DbLsn.getFileNumber(endOfFileLsn)) { currentEntryPrevOffset = DbLsn.getFileOffset(startLsn); } else { currentEntryPrevOffset = 0; } currentEntryOffset = DbLsn.getFileOffset(endOfFileLsn); } }
/** TBW */ protected void handleGapInBackwardsScan(long prevFileNum) { throw new EnvironmentFailureException( envImpl, EnvironmentFailureReason.LOG_INTEGRITY, "Cannot read backward over cleaned file" + " from " + window.currentFileNum() + " to " + prevFileNum); }
/** * Ensure that the next target is in the window. The default behavior is that the next target is * the next, following entry, so we can assume that it's in the window. All we have to do is to * check if we've gone past the specified end point. * * @throws DatabaseException * @throws FileNotFoundException * @throws ChecksumException */ protected void setForwardPosition() throws EOFException, DatabaseException, ChecksumException, FileNotFoundException { if (finishLsn != DbLsn.NULL_LSN) { /* The next log entry has passed the end LSN. */ long nextLsn = DbLsn.makeLsn(window.currentFileNum(), nextEntryOffset); if (DbLsn.compareTo(nextLsn, finishLsn) >= 0) { throw new EOFException(); } } }
/** * Add the entry bytes to the checksum and check the value. This method must be called with the * buffer positioned at the start of the entry. */ private void validateChecksum(ByteBuffer dataBuffer, boolean isChecksumTarget) throws ChecksumException { if (!doChecksumOnRead) { return; } if (!isChecksumTarget) { return; } cksumValidator.update(dataBuffer, currentEntryHeader.getItemSize()); cksumValidator.validate( currentEntryHeader.getChecksum(), window.currentFileNum(), currentEntryOffset); }
/** Set the set of registers that we will read and read and read again on every hardware cycle */ @Override public void setReadWindow(ReadWindow newWindow) { synchronized (this.concurrentClientLock) { synchronized (this.callbackLock) { if (this.readWindow == null || !this.readWindow.isOkToRead() || !this.readWindow.sameAsIncludingMode(newWindow)) { // Remember the new window, but get a fresh copy so we can implement the read mode policy this.readWindow = newWindow.freshCopy(); assertTrue(!BuildConfig.DEBUG || this.readWindow.isOkToRead()); // Let others know of the update this.readWindowChanged = true; } } } }
/** Returns the number of reads since the last time this method was called. */ public int getAndResetNReads() { return window.getAndResetNReads(); }
/** * Ensure that the next target is in the window. The default behavior is that the next target is * the next previous entry. * * @throws DatabaseException */ protected void setBackwardPosition() throws ChecksumException, FileNotFoundException, EOFException, DatabaseException { /* * currentEntryPrevOffset is the entry before the current entry. * currentEntryOffset is the entry we just read (or the end of the * file if we're starting out. */ if ((currentEntryPrevOffset != 0) && window.containsOffset(currentEntryPrevOffset)) { /* The next log entry has passed the start LSN. */ long nextLsn = DbLsn.makeLsn(window.currentFileNum(), currentEntryPrevOffset); if (finishLsn != DbLsn.NULL_LSN) { if (DbLsn.compareTo(nextLsn, finishLsn) == -1) { throw new EOFException( "finish=" + DbLsn.getNoFormatString(finishLsn) + "next=" + DbLsn.getNoFormatString(nextLsn)); } } /* This log entry starts in this buffer, just reposition. */ window.positionBuffer(currentEntryPrevOffset); } else { /* * The start of the log entry is not in this read buffer so * we must fill the buffer again. * * 1) The target log entry is in a different file from the * current window's file. Move the window to the previous * file and start the read from the target LSN. * * 2) The target log entry is the same file but the log entry * is larger than the read chunk size. Start the next read * buffer from the target LSN. It's going to take multiple * reads to get the log entry, and we might as well get as * much as possible. * * 3) In the same file, and the log entry fits within one * read buffer. Try to position the next buffer chunk so the * target entry is held within the buffer, all the way at the * end. That way, since we're reading backwards, there will be * more buffered data available for following reads. */ long nextFile; long nextWindowStart; long nextTarget; if (currentEntryPrevOffset == 0) { /* Case 1: Go to another file. */ currentEntryPrevOffset = fileManager.getFileHeaderPrevOffset(window.currentFileNum()); Long prevFileNum = fileManager.getFollowingFileNum(window.currentFileNum(), false); if (prevFileNum == null) { throw new EOFException("No file following " + window.currentFileNum()); } /* * Check finishLSN before proceeding, in case we should stop * the search before attempting to set the file reader to a * position in the previous file. In [#22407] we threw a * spurious EFE complaining that we cannot read backwards over * a cleaned file because the previous file had been cleaned * away. */ if (finishLsn != DbLsn.NULL_LSN && prevFileNum < DbLsn.getFileNumber(finishLsn)) { throw new EOFException( "finish=" + DbLsn.getNoFormatString(finishLsn) + " nextFile=0x" + Long.toHexString(prevFileNum)); } if (window.currentFileNum() - prevFileNum.longValue() != 1) { handleGapInBackwardsScan(prevFileNum); } nextFile = prevFileNum; nextWindowStart = currentEntryPrevOffset; nextTarget = currentEntryPrevOffset; } else if ((currentEntryOffset - currentEntryPrevOffset) > window.capacity()) { /* * Case 2: The entry is in the same file, but is bigger * than one buffer. Position it at the front of the buffer. */ nextFile = window.currentFileNum(); nextWindowStart = currentEntryPrevOffset; nextTarget = currentEntryPrevOffset; } else { /* * Case 3: In same file, but not in this buffer. The target * entry will fit in one buffer. */ nextFile = window.currentFileNum(); long newPosition = currentEntryOffset - window.capacity(); nextWindowStart = (newPosition < 0) ? 0 : newPosition; nextTarget = currentEntryPrevOffset; } /* The next log entry has passed the start LSN. */ long nextLsn = DbLsn.makeLsn(nextFile, currentEntryPrevOffset); if (finishLsn != DbLsn.NULL_LSN) { if (DbLsn.compareTo(nextLsn, finishLsn) == -1) { throw new EOFException( "finish=" + DbLsn.getNoFormatString(finishLsn) + " next=" + DbLsn.getNoFormatString(nextLsn)); } } window.slideAndFill(nextFile, nextWindowStart, nextTarget, forward); } /* The current entry will start at this offset. */ currentEntryOffset = currentEntryPrevOffset; }
/** Get LSN of the last entry read. */ public long getLastLsn() { return DbLsn.makeLsn(window.currentFileNum(), currentEntryOffset); }
public long getNRepeatIteratorReads() { return window.getNRepeatIteratorReads(); }