public FSReverseReader() throws IOException { incref(); long sz; synchronized (TransactionLog.this) { fos.flushBuffer(); sz = fos.size(); assert sz == channel.size(); } fis = new ChannelFastInputStream(channel, 0); if (sz >= 4) { // readHeader(fis); // should not be needed prevPos = sz - 4; fis.seek(prevPos); nextLength = fis.readInt(); } }
public boolean endsWithCommit() throws IOException { long size; synchronized (this) { fos.flush(); size = fos.size(); } // the end of the file should have the end message (added during a commit) plus a 4 byte size byte[] buf = new byte[END_MESSAGE.length()]; long pos = size - END_MESSAGE.length() - 4; if (pos < 0) return false; ChannelFastInputStream is = new ChannelFastInputStream(channel, pos); is.read(buf); for (int i = 0; i < buf.length; i++) { if (buf[i] != END_MESSAGE.charAt(i)) return false; } return true; }
@Override public String toString() { synchronized (TransactionLog.this) { return "LogReader{" + "file=" + tlogFile + ", position=" + fis.position() + ", end=" + fos.size() + "}"; } }
/** * Returns the next object from the log, or null if none available. * * @return The log record, or null if EOF * @throws IOException If there is a low-level I/O error. */ public Object next() throws IOException, InterruptedException { long pos = fis.position(); synchronized (TransactionLog.this) { if (trace) { log.trace("Reading log record. pos=" + pos + " currentSize=" + fos.size()); } if (pos >= fos.size()) { return null; } fos.flushBuffer(); } if (pos == 0) { readHeader(fis); // shouldn't currently happen - header and first record are currently written at the same // time synchronized (TransactionLog.this) { if (fis.position() >= fos.size()) { return null; } pos = fis.position(); } } Object o = codec.readVal(fis); // skip over record size int size = fis.readInt(); assert size == fis.position() - pos - 4; return o; }
/** * Returns the next object from the log, or null if none available. * * @return The log record, or null if EOF * @throws IOException If there is a low-level I/O error. */ public Object next() throws IOException { if (prevPos <= 0) return null; long endOfThisRecord = prevPos; int thisLength = nextLength; long recordStart = prevPos - thisLength; // back up to the beginning of the next record prevPos = recordStart - 4; // back up 4 more to read the length of the next record if (prevPos <= 0) return null; // this record is the header long bufferPos = fis.getBufferPos(); if (prevPos >= bufferPos) { // nothing to do... we're within the current buffer } else { // Position buffer so that this record is at the end. // For small records, this will cause subsequent calls to next() to be within the buffer. long seekPos = endOfThisRecord - fis.getBufferSize(); seekPos = Math.min( seekPos, prevPos); // seek to the start of the record if it's larger then the block size. seekPos = Math.max(seekPos, 0); fis.seek(seekPos); fis.peek(); // cause buffer to be filled } fis.seek(prevPos); nextLength = fis.readInt(); // this is the length of the *next* record (i.e. closer to the beginning) // TODO: optionally skip document data Object o = codec.readVal(fis); // assert fis.position() == prevPos + 4 + thisLength; // this is only true if we read all the // data (and we currently skip reading SolrInputDocument return o; }
// returns best effort current position // for info purposes public long currentPos() { return fis.position(); }