@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 best effort current position
 // for info purposes
 public long currentPos() {
   return fis.position();
 }