Package org.apache.hadoop.hdfs.server.namenode.bookkeeper.metadata

Source Code of org.apache.hadoop.hdfs.server.namenode.bookkeeper.metadata.CurrentInProgressMetadata

/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.hdfs.server.namenode.bookkeeper.metadata;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.hdfs.server.namenode.bookkeeper.metadata.proto.CurrentInProgressMetadataWritable;
import org.apache.hadoop.hdfs.server.namenode.bookkeeper.metadata.proto.WritableUtil;
import org.apache.hadoop.hdfs.server.namenode.bookkeeper.zk.RecoveringZooKeeper;
import org.apache.hadoop.hdfs.server.namenode.bookkeeper.zk.ZooKeeperIface;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.data.Stat;

import java.io.IOException;
import java.net.InetAddress;
import java.util.concurrent.atomic.AtomicInteger;

import static org.apache.hadoop.hdfs.server.namenode.bookkeeper.zk.ZkUtil.interruptedException;
import static org.apache.hadoop.hdfs.server.namenode.bookkeeper.zk.ZkUtil.keeperException;

/**
* Used by {@link BookKeeperJournalMetadataManager} to point to the
* ledger metadata for the ledger holding the in-progress edit log
* segment
*/
public class CurrentInProgressMetadata {

  private static final Log LOG = LogFactory.getLog(CurrentInProgressMetadata.class);

  // Keep a thread local Writable for serialization as to avoid allocating
  // a new object each time we write
  private static final ThreadLocal<CurrentInProgressMetadataWritable>
      localWritable = new ThreadLocal<CurrentInProgressMetadataWritable>() {
    @Override
    protected CurrentInProgressMetadataWritable initialValue() {
      return new CurrentInProgressMetadataWritable();
    }
  };

  private final ZooKeeperIface zooKeeper;
  // Full path to znode storing the information about the current in-progress
  // ledger
  private final String fullyQualifiedZNode;
  // The version we've last read from the ZNode to make sure we don't
  // update the in-progress ledger without reading the existing one first
  private final AtomicInteger expectedZNodeVersion;
  // Identifiers the process that last updated the ZNode
  private final String hostname;

  /**
   * Creates and initialized an instance that will point to the metadata about
   * ledger containing the current in-progress edit log segment in a specified
   * ZNode. If the ZNode does not exist, the ZNode will be created and set to
   * null.
   * @param zooKeeper The {@link ZooKeeperIface} implementation. Use
   *                  {@link RecoveringZooKeeper} in order to handle
   *                  transient ZooKeeper issues
   * @param fullyQualifiedZNode The path to the ZNode that will be used
   *                            by this instance to point to the ledger
   *                            metadata for the ledger containing the
   *                            current in-progress log segment
   * @throws IOException
   */
  public CurrentInProgressMetadata(ZooKeeperIface zooKeeper,
      String fullyQualifiedZNode) throws IOException {
    this.zooKeeper = zooKeeper;
    this.fullyQualifiedZNode = fullyQualifiedZNode;
    this.expectedZNodeVersion = new AtomicInteger(-1);
    // Hostname is used as part of the human-readable identifier
    // for the process that last updated the in-progress ZNode
    hostname = InetAddress.getLocalHost().toString();
  }

  public void init() throws IOException {
    boolean alreadyExists = false;
    try {
      // Check whether or not the specified ZNode already exists
      Stat stat = zooKeeper.exists(this.fullyQualifiedZNode,
          false);
      if (stat == null) {
        try { // If the specified ZNode does not exist, create it
          zooKeeper.create(this.fullyQualifiedZNode, null,
              ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
          LOG.info("Created ZNode " + fullyQualifiedZNode);
        } catch (KeeperException.NodeExistsException e) {
          LOG.warn(fullyQualifiedZNode + " created by another process. " +
              "Ignoring " + e);
          alreadyExists = true;
        }
      } else {
        alreadyExists = true;
      }
    } catch (KeeperException e) {
      keeperException("Unrecoverable ZooKeeper error creating " +
          fullyQualifiedZNode, e);
    } catch (InterruptedException e) {
      interruptedException("Interrupted while creating " + fullyQualifiedZNode,
          e);
    }
    if (alreadyExists) {
      // If the znode already exists, read it, print the owner information and
      // update the version number from znode's stat
      CurrentInProgressMetadataWritable owner = localWritable.get();
      if (readAndUpdateVersion(owner)) {
        LOG.info(fullyQualifiedZNode + " held by " + owner.getId() +
            " and points to " + owner.getPath());
      } else {
        LOG.info(fullyQualifiedZNode + " is currently clear.");
      }
    }
  }

  /**
   * Update the data in the ZNode to point to a the ZNode containing the
   * metadata for the ledger containing the current in-progress edit log
   * segment.
   * @param newPath Path to the metadata for the current ledger
   * @throws StaleVersionException If path read is out of date compared to the
   *                               version in ZooKeeper
   * @throws IOException If there is an error talking to ZooKeeper
   */
  public void update(String newPath) throws IOException {
    String id = hostname + Thread.currentThread().getId();
    CurrentInProgressMetadataWritable cip = localWritable.get();
    cip.set(id, newPath);
    byte[] data = WritableUtil.writableToByteArray(cip);
    try {
      zooKeeper.setData(fullyQualifiedZNode, data, expectedZNodeVersion.get());
      if (LOG.isDebugEnabled()) {
        LOG.debug("Set " + fullyQualifiedZNode + " to point to " + newPath);
      }
    } catch (KeeperException.BadVersionException e) {
      // Throw an exception if we try to update without having read the
      // current version
      LOG.error(fullyQualifiedZNode + " has been updated by another process",
          e);
      throw new StaleVersionException(fullyQualifiedZNode +
          "has been updated by another process!");
    } catch (KeeperException e) {
      keeperException("Unrecoverable ZooKeeper error updating " +
          fullyQualifiedZNode, e);
    } catch (InterruptedException e) {
      interruptedException("Interrupted updating " + fullyQualifiedZNode, e);
    }
  }

  /**
   * Read the full path to the ZNode holding the metadata for the ledger
   * containing the current in-progress edit log segment or null if no segment
   * is currently in-progress
   * @return Full path to the ledger's metadata ZNode or null if no
   *         segment is in progress
   * @throws IOException If there is an error talking to ZooKeeper
   */
  public String read() throws IOException {
    CurrentInProgressMetadataWritable cip = localWritable.get();
    if (readAndUpdateVersion(cip)) {
      return cip.getPath();
    } else {
      if (LOG.isDebugEnabled()) {
        LOG.debug(fullyQualifiedZNode + " is currently clear.");
      }
    }
    return null;
  }

  /**
   * Reads the ZNode specified in constructor into an existing
   * {@link CurrentInProgressMetadataWritable} instance and sets expected
   * ZNode version (for next update) the the current version of the
   * specified ZNode
   * @param target The writable instance to read into
   * @return True if there is a log segment is current in-progress, false
   *         otherwise
   * @throws IOException If there is an unrecoverable error talking to
   *                     ZooKeeper
   */
  private boolean readAndUpdateVersion(CurrentInProgressMetadataWritable target)
      throws IOException {
    Stat stat = new Stat();
    try {
      byte[] data = zooKeeper.getData(fullyQualifiedZNode, false, stat);
      expectedZNodeVersion.set(stat.getVersion());
      if (data != null) {
        WritableUtil.readWritableFromByteArray(data, target);
        return true;
      }
    } catch (KeeperException e) {
      keeperException("Unrecoverable ZooKeeper error reading from " +
          fullyQualifiedZNode, e);
    } catch (InterruptedException e) {
      interruptedException("Interrupted reading from " + fullyQualifiedZNode,
          e);
    }
    return false;
  }

  /**
   * Clear out the data in the ZNode specified in the constructor to indicate
   * that no segment is currently in progress. This does not delete the
   * actual ZNode.
   * @throws IOException If there is an unrecoverable error talking to
   *                     ZooKeeper
   */
  public void clear() throws IOException {
    try {
      zooKeeper.setData(fullyQualifiedZNode, null, expectedZNodeVersion.get());
    } catch (KeeperException.BadVersionException e) {
      LOG.error(fullyQualifiedZNode + " has been updated by another process",
          e);
      throw new StaleVersionException(fullyQualifiedZNode +
          "has been updated by another process!");
    } catch (KeeperException e) {
      keeperException("Unrecoverable ZooKeeper error clearing " +
          fullyQualifiedZNode, e);
    } catch (InterruptedException e) {
      interruptedException("Interrupted clearing " + fullyQualifiedZNode, e);
    }
  }

}
TOP

Related Classes of org.apache.hadoop.hdfs.server.namenode.bookkeeper.metadata.CurrentInProgressMetadata

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.