Beispiel #1
0
    public String toString() {

      final IRootBlockView tmp = HALogFile.this.getOpeningRootBlock();

      final long seq = m_nextSequence;

      return getClass().getName()
          + "{"
          + ((!isOpen())
              ? "closed"
              : "commitCounter=" + tmp.getCommitCounter() + ",nextSequence=" + seq)
          + "}";
    }
Beispiel #2
0
  private void writeRootBlock(final boolean isRootBlock0, final IRootBlockView rootBlock)
      throws IOException {

    if (rootBlock == null) throw new IllegalArgumentException();

    final long position = isRootBlock0 ? OFFSET_ROOT_BLOCK0 : OFFSET_ROOT_BLOCK1;

    FileChannelUtility.writeAll(m_reopener, rootBlock.asReadOnlyBuffer(), position);

    if (log.isDebugEnabled()) log.debug("wrote root block: " + rootBlock);
  }
Beispiel #3
0
  /**
   * This constructor is called by the log manager to create the file. A writer is created at the
   * same time, and its presence indicates that the file is open for writing.
   *
   * @throws IOException
   */
  public HALogFile(final IRootBlockView rbv, final IHALogManagerCallback callback)
      throws IOException {
    m_callback = callback;
    m_haLogFile = getHALogFileName(m_callback.getHALogDir(), rbv.getCommitCounter());

    if (m_haLogFile.exists())
      throw new IllegalStateException("File already exists: " + m_haLogFile.getAbsolutePath());

    final File parentDir = m_haLogFile.getParentFile();

    // Make sure the parent directory(ies) exist.
    if (!parentDir.exists())
      if (!parentDir.mkdirs()) throw new IOException("Could not create directory: " + parentDir);

    m_raf = new RandomAccessFile(m_haLogFile, "rw");
    m_channel = m_raf.getChannel();
    m_storeType = rbv.getStoreType();

    m_openRootBlock = rbv;
    m_closeRootBlock = null; // file NOT closed

    m_magic = MAGIC;
    m_version = VERSION1;

    /*
     * Write the MAGIC and version on the file.
     */
    m_raf.seek(0);
    m_raf.writeInt(m_magic);
    m_raf.writeInt(m_version);

    // Write opening rootblock as both BLOCK0 and BLOCK1
    writeRootBlock(true, rbv); // as BLOCK0
    writeRootBlock(false, rbv); // as BLOCK1

    m_writePosition = START_DATA;

    m_writer = new HALogWriter();

    if (log.isInfoEnabled()) log.info("Opening HALogFile: " + m_haLogFile.getAbsolutePath());
  }
Beispiel #4
0
  /**
   * Called by the HALogWriter to close the log file with the committing rootblock.
   *
   * @param rbv
   * @throws IOException
   */
  private void close(final IRootBlockView rbv) throws IOException {
    m_writeLock.lock();
    try {
      if (m_closeRootBlock != null) throw new IllegalStateException("LogFile is already closed");

      writeRootBlock(rbv.isRootBlock0(), rbv);

      m_closeRootBlock = rbv;

      m_callback.release(this);

      m_fileChange.signalAll();

    } finally {
      m_writeLock.unlock();
    }
  }
Beispiel #5
0
 public long getCommitCounter() {
   return m_openRootBlock.getCommitCounter();
 }
Beispiel #6
0
 /** @return true if the file is complete and its size indicates no content */
 public boolean isEmpty() {
   return (m_closeRootBlock != null)
       && (m_openRootBlock.getCommitCounter() == m_closeRootBlock.getCommitCounter());
 }
Beispiel #7
0
  /**
   * Private method called by the HALogWriter to write a new message
   *
   * @param msg
   * @param data
   * @throws IOException
   */
  private void write(final IHAWriteMessage msg, final ByteBuffer data) throws IOException {
    m_writeLock.lock();
    try {

      /*
       * Check if this really is a valid message for this file. If it is
       * not, then close the file and return immediately
       */
      if (m_openRootBlock.getCommitCounter() != msg.getCommitCounter())
        throw new IllegalStateException(
            "commitCounter=" + m_openRootBlock.getCommitCounter() + ", but msg=" + msg);

      if (m_openRootBlock.getLastCommitTime() != msg.getLastCommitTime())
        throw new IllegalStateException(
            "lastCommitTime=" + m_openRootBlock.getLastCommitTime() + ", but msg=" + msg);

      if (m_sequence != msg.getSequence())
        throw new IllegalStateException("nextSequence=" + m_sequence + ", but msg=" + msg);

      if (log.isInfoEnabled()) log.info("msg=" + msg + ", position=" + m_writePosition);

      if (m_writePosition < headerSize0)
        throw new AssertionError("position=" + m_writePosition + ", but headerSize=" + headerSize0);

      /*
       * Write the HAWriteMessage onto the channel.
       */
      {
        // serialized message object (pos=0; limit=nbytes)
        final ByteBuffer tmp = bufferObject(msg);

        final int nbytes = tmp.limit();

        FileChannelUtility.writeAll(m_reopener, tmp, m_writePosition);

        m_writePosition += nbytes;
      }

      switch (m_openRootBlock.getStoreType()) {
        case RW:
          {
            /*
             * Write the WriteCache block on the channel.
             */
            final int nbytes = msg.getSize();
            assert data.position() == 0;
            assert data.limit() == nbytes;
            // Note: duplicate() to avoid side effects on ByteBuffer!!!
            FileChannelUtility.writeAll(m_reopener, data.duplicate(), m_writePosition);
            m_writePosition += nbytes;
            break;
          }
        case WORM:
          {
            /*
             * We will use the HA failover read API to recover the block
             * from a node in the quorum when we need to replay the HA log.
             */
            break;
          }
        default:
          throw new AssertionError();
      }

      m_sequence++;

      m_fileChange.signalAll();

    } finally {
      m_writeLock.unlock();
    }
  }
Beispiel #8
0
  /**
   * This constructor creates a read only view of the log file and can be used independently of the
   * HALogManager.
   *
   * <p>The opening and closing root blocks are examined to confirm the file has fully committed
   * writes and can be opened for read only access.
   *
   * @param readonlyLog
   * @throws FileNotFoundException
   */
  public HALogFile(final File file) {
    if (file == null || !file.exists()) throw new IllegalStateException();

    m_callback = null;
    m_writer = null;
    m_haLogFile = file;
    try {
      m_raf = new RandomAccessFile(m_haLogFile, "r");
    } catch (FileNotFoundException e) {
      // this should have been caught above and thrown
      // IllegalStateException
      throw new RuntimeException(e);
    }
    m_channel = m_raf.getChannel();

    try {
      /**
       * Must determine whether the file has consistent open and committed rootBlocks, using the
       * commitCounter to determine which rootBlock is which.
       *
       * <p>Note: Both root block should exist (they are both written on startup). If they are
       * identical, then the log is empty (the closing root block has not been written and the data
       * in the log is useless).
       *
       * <p>We figure out which root block is the opening root block based on standard logic.
       */
      /*
       * Read the MAGIC and VERSION.
       */
      m_raf.seek(0L);
      try {
        /*
         * Note: this next line will throw IOException if there is a
         * file lock contention.
         */
        m_magic = m_raf.readInt();
      } catch (IOException ex) {
        throw new RuntimeException("Can not read magic. Is file locked by another process?", ex);
      }
      if (m_magic != MAGIC)
        throw new RuntimeException("Bad journal magic: expected=" + MAGIC + ", actual=" + m_magic);
      m_version = m_raf.readInt();
      if (m_version != VERSION1)
        throw new RuntimeException(
            "Bad journal version: expected=" + VERSION1 + ", actual=" + m_version);

      final RootBlockUtility tmp =
          new RootBlockUtility(
              m_reopener,
              file,
              true /* validateChecksum */,
              false /* alternateRootBlock */,
              false /* ignoreBadRootBlock */);

      m_closeRootBlock = tmp.chooseRootBlock();

      m_openRootBlock = tmp.rootBlock0 == m_closeRootBlock ? tmp.rootBlock1 : tmp.rootBlock0;

      final long cc0 = m_openRootBlock.getCommitCounter();

      final long cc1 = m_closeRootBlock.getCommitCounter();

      if ((cc0 + 1) != cc1 && (cc0 != cc1)) {
        /*
         * Counters are inconsistent with either an empty log file or a
         * single transaction scope.
         */
        throw new IllegalStateException("Incompatible rootblocks: cc0=" + cc0 + ", cc1=" + cc1);
      }

      m_channel.position(START_DATA);

      m_storeType = m_openRootBlock.getStoreType();

    } catch (Throwable t) {

      try {
        close();
      } catch (IOException e) {
        log.warn(e);
      }

      throw new RuntimeException(t);
    }
  }