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

Source Code of org.apache.hadoop.hdfs.server.namenode.FSEditLog

/**
* 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;

import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ConcurrentNavigableMap;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.zip.Checksum;

import org.apache.hadoop.hdfs.protocol.Block;
import org.apache.hadoop.hdfs.server.common.HdfsConstants;
import org.apache.hadoop.hdfs.server.common.Storage.StorageDirectory;
import org.apache.hadoop.hdfs.server.namenode.FSEditLogOp.*;
import org.apache.hadoop.hdfs.server.namenode.FSImage.NameNodeDirType;
import org.apache.hadoop.hdfs.server.namenode.metrics.NameNodeMetrics;
import org.apache.hadoop.hdfs.util.Holder;
import org.apache.hadoop.io.*;
import org.apache.hadoop.ipc.Server;
import org.apache.hadoop.util.PureJavaCrc32;
import org.apache.hadoop.fs.ChecksumException;
import org.apache.hadoop.fs.permission.*;

/**
* FSEditLog maintains a log of the namespace modifications.
*
*/
public class FSEditLog {
  static int sizeFlushBuffer = HdfsConstants.DEFAULT_EDIT_BUFFER_SIZE;
  static long preallocateSize= HdfsConstants.DEFAULT_EDIT_PREALLOCATE_SIZE;
  static long maxBufferedTransactions= HdfsConstants.DEFAULT_MAX_BUFFERED_TRANSACTIONS;
  private final ConcurrentSkipListMap<Long, List<Long>> delayedSyncs =
    new ConcurrentSkipListMap<Long, List<Long>>();
  private Thread syncThread;
  private SyncThread syncer;

  private ArrayList<EditLogOutputStream> editStreams = null;
  private FSImage fsimage = null;

  // a monotonically increasing counter that represents transactionIds.
  private long txid = 0;

  // stores the last synced transactionId.
  private long synctxid = 0;

  // the time of printing the statistics to the log file.
  private long lastPrintTime;

  // is a sync currently running?
  private volatile boolean isSyncRunning;

  // these are statistics counters.
  private long numTransactions;        // number of transactions
  private long numTransactionsBatchedInSync;
  private long totalTimeTransactions;  // total time for all transactions
  private NameNodeMetrics metrics;
 
  private static ThreadLocal<Checksum> localChecksumForRead =
    new ThreadLocal<Checksum>() {
    protected Checksum initialValue() {
        return new PureJavaCrc32();
    }
  };

  private static ThreadLocal<Checksum> localChecksumForWrite =
    new ThreadLocal<Checksum>() {
    protected Checksum initialValue() {
        return new PureJavaCrc32();
    }
  };

  /** Get a thread local checksum for read */
  static Checksum getChecksumForRead() {
    return localChecksumForRead.get();
  }
 
  /** Get a thread local checksum for read */
  static Checksum getChecksumForWrite() {
    return localChecksumForWrite.get();
  }

  /**
   * Sets the current transaction id of the edit log. This is used when we load
   * the FSImage and FSEdits and read the last transaction id from disk and then
   * we continue logging transactions to the edit log from that id onwards.
   *
   * @param txid
   *          the last transaction id
   */
  public void setStartTransactionId(long txid) {
    this.txid = txid;
  }

  private static class TransactionId {
    public long txid;

    TransactionId(long value) {
      this.txid = value;
    }
  }

  // stores the most current transactionId of this thread.
  private static final ThreadLocal<TransactionId> myTransactionId = new ThreadLocal<TransactionId>() {
    protected synchronized TransactionId initialValue() {
      return new TransactionId(-1L);
    }
  };



  FSEditLog(FSImage image) {
    fsimage = image;
    isSyncRunning = false;
    metrics = NameNode.getNameNodeMetrics();
    lastPrintTime = FSNamesystem.now();
  }
 
  private File getEditFile(StorageDirectory sd) {
    return fsimage.getEditFile(sd);
  }
 
  private File getEditNewFile(StorageDirectory sd) {
    return fsimage.getEditNewFile(sd);
  }
 
  private int getNumStorageDirs() {
int numStorageDirs = 0;
for (Iterator<StorageDirectory> it =
       fsimage.dirIterator(NameNodeDirType.EDITS); it.hasNext(); it.next())
   numStorageDirs++;
    return numStorageDirs;
  }
 
  synchronized int getNumEditStreams() {
    return editStreams == null ? 0 : editStreams.size();
  }

  boolean isOpen() {
    return getNumEditStreams() > 0;
  }

  /**
   * Create empty edit log files.
   * Initialize the output stream for logging.
   *
   * @throws IOException
   */
  public synchronized void open() throws IOException {
    if (syncer == null) {
      syncer = new SyncThread();
      syncThread = new Thread(syncer);
      syncThread.start();
    }
    numTransactions = totalTimeTransactions = numTransactionsBatchedInSync = 0;
    if (editStreams == null)
      editStreams = new ArrayList<EditLogOutputStream>();
    for (Iterator<StorageDirectory> it =
           fsimage.dirIterator(NameNodeDirType.EDITS); it.hasNext();) {
      StorageDirectory sd = it.next();
      File eFile = getEditFile(sd);
      try {
        EditLogOutputStream eStream = new EditLogFileOutputStream(eFile, metrics);
        editStreams.add(eStream);
      } catch (IOException e) {
        FSNamesystem.LOG.warn("Unable to open edit log file " + eFile);
        // Remove the directory from list of storage directories
        fsimage.removedStorageDirs.add(sd);
        it.remove();
      }
    }
  }

  public synchronized void createEditLogFile(File name) throws IOException {
    EditLogOutputStream eStream = new EditLogFileOutputStream(name, metrics);
    eStream.create();
    eStream.close();
  }
 
  public synchronized void close() throws IOException {
    close(false);
  }

  /**
   * Shutdown the file store.
   */
  public synchronized void close(boolean shutdown) throws IOException {
    while (isSyncRunning) {
      try {
        wait(1000);
      } catch (InterruptedException ie) {
      }
    }
   
    if (shutdown && syncThread != null) {
      syncer.stop();
      syncThread.interrupt();
    }

    if (editStreams == null) {
      return;
    }
    printStatistics(true);
    numTransactions = totalTimeTransactions = numTransactionsBatchedInSync = 0;

    for (int idx = 0; idx < editStreams.size(); idx++) {
      EditLogOutputStream eStream = editStreams.get(idx);
      try {
        eStream.setReadyToFlush();
        eStream.flush();
        eStream.close();
      } catch (IOException e) {
        FSNamesystem.LOG.warn("FSEditLog:close - failed to close stream "
            + eStream.getName(), e);
        processIOError(idx);
        idx--;
      }
    }
    editStreams.clear();
  }

  /**
   * If there is an IO Error on any log operations, remove that
   * directory from the list of directories.
   * If no more directories remain, then exit.
   */
  synchronized void processIOError(int index) {
    if (editStreams == null || editStreams.size() <= 1) {
      FSNamesystem.LOG.fatal(
      "Fatal Error : All storage directories are inaccessible.");
      Runtime.getRuntime().exit(-1);
    }
    assert(index < getNumStorageDirs());
    assert(getNumStorageDirs() == editStreams.size());
   
    EditLogFileOutputStream eStream = (EditLogFileOutputStream)editStreams.get(index);
    File parentStorageDir = ((EditLogFileOutputStream)editStreams
                                      .get(index)).getFile()
                                      .getParentFile().getParentFile();
   
    try {
      eStream.close();
    } catch (Exception e) {}
   
    editStreams.remove(index);
    //
    // Invoke the ioerror routine of the fsimage
    //
    fsimage.processIOError(parentStorageDir);
  }
 
  /**
   * If there is an IO Error on any log operations on storage directory,
   * remove any stream associated with that directory
   */
  synchronized void processIOError(StorageDirectory sd) {
    // Try to remove stream only if one should exist
    if (!sd.getStorageDirType().isOfType(NameNodeDirType.EDITS))
      return;
    if (editStreams == null || editStreams.size() <= 1) {
      FSNamesystem.LOG.fatal(
          "Fatal Error : All storage directories are inaccessible.");
      Runtime.getRuntime().exit(-1);
    }
    for (int idx = 0; idx < editStreams.size(); idx++) {
      File parentStorageDir = ((EditLogFileOutputStream)editStreams
                                       .get(idx)).getFile()
                                       .getParentFile().getParentFile();
      if (parentStorageDir.getName().equals(sd.getRoot().getName()))
        editStreams.remove(idx);
}
  }
 
  /**
   * The specified streams have IO errors. Remove them from logging
   * new transactions.
   */
  private void processIOError(ArrayList<EditLogOutputStream> errorStreams) {
    if (errorStreams == null) {
      return;                       // nothing to do
    }
    for (int idx = 0; idx < errorStreams.size(); idx++) {
      EditLogOutputStream eStream = errorStreams.get(idx);
      int j = 0;
      int numEditStreams = editStreams.size();
      for (j = 0; j < numEditStreams; j++) {
        if (editStreams.get(j) == eStream) {
          break;
        }
      }
      if (j == numEditStreams) {
          FSNamesystem.LOG.error("Unable to find sync log on which " +
                                 " IO error occured. " +
                                 "Fatal Error.");
          Runtime.getRuntime().exit(-1);
      }
      processIOError(j);
    }
    fsimage.incrementCheckpointTime();
  }

  /**
   * check if ANY edits.new log exists
   */
  boolean existsNew() throws IOException {
    for (Iterator<StorageDirectory> it =
           fsimage.dirIterator(NameNodeDirType.EDITS); it.hasNext();) {
      if (getEditNewFile(it.next()).exists()) {
        return true;
      }
    }
    return false;
 

  /**
   * Validate a transaction's checksum
   */
  static void validateChecksum(boolean supportChecksum,
      DataInputStream rawStream, Checksum checksum, int tid)
  throws IOException {
    if (supportChecksum) {
      int expectedChecksum = rawStream.readInt()// read in checksum
      int calculatedChecksum = (int)checksum.getValue();
      if (expectedChecksum != calculatedChecksum) {
        throw new ChecksumException(
            "Transaction " + tid + " is corrupt.", tid);
      }
    }
  }
 
  // a place holder for reading a long
  private static final LongWritable longWritable = new LongWritable();

  /**
   * Write an operation to the edit log. Do not sync to persistent
   * store yet.
   */
  synchronized void logEdit(final FSEditLogOp op) {
    op.setTransactionId(txid);
    assert this.getNumEditStreams() > 0 : "no editlog streams";
    long start = FSNamesystem.now();
    for (int idx = 0; idx < editStreams.size(); idx++) {
      EditLogOutputStream eStream = editStreams.get(idx);
      try {
        eStream.write(op);
      } catch (IOException ie) {
        FSImage.LOG.warn("logEdit: removing "+ eStream.getName(), ie);
        processIOError(idx);        
        // processIOError will remove the idx's stream
        // from the editStreams collection, so we need to update idx
        idx--;
      }
    }
    // get a new transactionId
    txid++;

    //
    // record the transactionId when new data was written to the edits log
    //
    TransactionId id = myTransactionId.get();
    id.txid = txid;

    // update statistics
    long end = FSNamesystem.now();
    numTransactions++;
    totalTimeTransactions += (end-start);
    if (metrics != null) { // Metrics is non-null only when used inside name node
      metrics.transactions.inc((end-start));
      metrics.numBufferedTransactions.set((int)(txid-synctxid));
    }
  }

  /**
   * Syncs all pending transactions from all threads.
   */
  synchronized void logSyncAll() throws IOException {
    // stores in the Thread local variable of current threads
    TransactionId id = myTransactionId.get();
    id.txid = txid;
    logSync();
  }

  /**
   * if there are too many transactions that are yet to be synced,
   * then sync them. Otherwise, the in-memory buffer that keeps
   * the transactions would grow to be very very big. This can happen
   * when there are a large number of listStatus calls which update
   * the access time of files.
   */
  public void logSyncIfNeeded() throws IOException {
    boolean doSync = false;
    synchronized (this) {
      if (txid > synctxid + maxBufferedTransactions) {
        FSNamesystem.LOG.info("Out of band log sync triggered " +
                              " because there are " +
                              (txid-synctxid) +
                              " buffered transactions which " +
                              " is more than the configured limit of " +
                              maxBufferedTransactions);
        doSync = true;
      }  
    }
    if (doSync) {
      logSync();
    }
  }
 
  public void logSync() throws IOException {
    logSync(true);
  }

  //
  // Sync all modifications done by this thread.
  //
  public void logSync(boolean doWait) throws IOException {
   
    long syncStart = 0;

    final int numEditStreams;
    synchronized (this) {
      // Fetch the transactionId of this thread.
      long mytxid = myTransactionId.get().txid;
      myTransactionId.get().txid = -1L;
      if (mytxid == -1) {
        mytxid = txid;
      }
      numEditStreams = editStreams.size();
      assert numEditStreams > 0 : "no editlog streams";
      printStatistics(false);

      // if somebody is already syncing, then wait
      while (mytxid > synctxid && isSyncRunning) {
        if (!doWait) {
          long delayedId = Server.delayResponse();
          List<Long> responses = delayedSyncs.get(mytxid);
          if (responses == null) {
            responses = new LinkedList<Long>();
            delayedSyncs.put(mytxid, responses);
          }
          responses.add(delayedId);
          return;
        }
        try {
          wait(1000);
        } catch (InterruptedException ie) { }
      }

      //
      // If this transaction was already flushed, then nothing to do
      //
      if (mytxid <= synctxid) {
        numTransactionsBatchedInSync++;
        if (metrics != null) // Metrics is non-null only when used inside name node
          metrics.transactionsBatchedInSync.inc();
        return;
      }
  
      // now, this thread will do the sync
      syncStart = txid;
      isSyncRunning = true;  

      // swap buffers
      for (int idx = 0; idx < numEditStreams; idx++) {
        editStreams.get(idx).setReadyToFlush();
      }
    }
    sync(syncStart);

    synchronized (this) {
       synctxid = syncStart;
       isSyncRunning = false;
       this.notifyAll();
    }
    endDelay(syncStart);
  }
 
  private void sync(long syncStart) {
    ArrayList<EditLogOutputStream> errorStreams = null;
    // do the sync
    long start = FSNamesystem.now();
    final int numEditStreams;
    synchronized (this) {
      numEditStreams = editStreams.size();
      assert numEditStreams > 0: "no editlog streams";
    }
    for (int idx = 0; idx < numEditStreams; idx++) {
      EditLogOutputStream eStream = editStreams.get(idx);
      try {
        eStream.flush();
      } catch (IOException ie) {
        //
        // remember the streams that encountered an error.
        //
        if (errorStreams == null) {
          errorStreams = new ArrayList<EditLogOutputStream>(1);
        }
        errorStreams.add(eStream);
        FSNamesystem.LOG.error("Unable to sync edit log. " +
                               "Fatal Error.", ie);
      }
    }
    long elapsed = FSNamesystem.now() - start;
    if (metrics != null) // Metrics is non-null only when used inside name node
      metrics.syncs.inc(elapsed);

    synchronized (this) {
      processIOError(errorStreams);
    }
  }
 
  private void endDelay(long synced) {
    ConcurrentNavigableMap<Long, List<Long>> syncs = delayedSyncs.headMap(synced, true);
    for (Iterator<List<Long>> iter = syncs.values().iterator();
            iter.hasNext();) {
      List<Long> responses = iter.next();
      for (Long responseId : responses) {
        try {
          Server.sendDelayedResponse(responseId);
        } catch (IOException ex) {
        }
      }
      iter.remove();
    }
   
  }
 
  private class SyncThread implements Runnable {

    private volatile boolean isRunning = true;

    public void stop() {
      isRunning = false;
    }

    @Override
    public void run() {
      long syncStart = 0;
      int numEditStreams;
      while (isRunning) {
        synchronized (FSEditLog.this) {
          numEditStreams = editStreams.size();
          assert numEditStreams > 0 : "no editlog streams";

          while (isSyncRunning || (isRunning && delayedSyncs.size() == 0)) {
            try {
              FSEditLog.this.wait();
            } catch (InterruptedException iex) {
            }
          }
          if (!isRunning) {
            // Shutting down the edits log
            return;
          }

          // There are delayed transactions waiting to be synced and
          // nobody to sync them
          syncStart = txid;
          isSyncRunning = true;

          for (int idx = 0; idx < numEditStreams; idx++) {
            try {
              editStreams.get(idx).setReadyToFlush();
            } catch (IOException ex) {
              FSNamesystem.LOG.error(ex);
              isSyncRunning = false;
              continue;
            }
          }

        }
        sync(syncStart);
        synchronized (FSEditLog.this) {
          synctxid = syncStart;
          isSyncRunning = false;
          FSEditLog.this.notifyAll();
        }
        endDelay(syncStart);
      }
    }
   
    public String toString() {
      return "SyncThread";
    }
  }

  //
  // print statistics every 1 minute.
  //
  private void printStatistics(boolean force) {
    long now = FSNamesystem.now();
    if (lastPrintTime + 60000 > now && !force) {
      return;
    }
    if (editStreams == null || editStreams.size()==0) {
      return;
    }
    lastPrintTime = now;
    StringBuilder buf = new StringBuilder();
    buf.append("Number of transactions: ");
    buf.append(numTransactions);
    buf.append(" Total time for transactions(ms): ");
    buf.append(totalTimeTransactions);
    buf.append(" Number of transactions batched in Syncs: ");
    buf.append(numTransactionsBatchedInSync);
    buf.append(" Number of syncs: ");
    buf.append(editStreams.get(0).getNumSync());
    buf.append(" SyncTimes(ms): ");

    int numEditStreams = editStreams.size();
    for (int idx = 0; idx < numEditStreams; idx++) {
      EditLogOutputStream eStream = editStreams.get(idx);
      buf.append(" " + eStream.getName() + ":");
      buf.append(eStream.getTotalSyncTime());
      buf.append(" ");
    }
    FSNamesystem.LOG.info(buf);
  }

  /**
   * Add open lease record to edit log.
   * Records the block locations of the last block.
   */
  public void logOpenFile(String path, INodeFileUnderConstruction newNode
                   throws IOException {
    AddOp op = AddOp.getInstance()
    op.set(path,
        newNode.getReplication(),
        newNode.getModificationTime(),
        newNode.getAccessTime(),
        newNode.getPreferredBlockSize(),
        newNode.getBlocks(),
        newNode.getPermissionStatus(),
        newNode.getClientName(),
        newNode.getClientMachine());  
    logEdit(op);
  }

  /**
   * Add close lease record to edit log.
   */
  public void logCloseFile(String path, INodeFile newNode) {
    CloseOp op = CloseOp.getInstance();
    op.set(path,
        newNode.getReplication(),
        newNode.getModificationTime(),
        newNode.getAccessTime(),
        newNode.getPreferredBlockSize(),
        newNode.getBlocks(),
        newNode.getPermissionStatus(),
        null,
        null);
    logEdit(op);
  }
 
  /**
   * Add create directory record to edit log
   */
  public void logMkDir(String path, INode newNode) {
    MkdirOp op = MkdirOp.getInstance();
    op.set(path, newNode.getModificationTime(),
        newNode.getPermissionStatus());
    logEdit(op);
  }
 
  /**
   * Add rename record to edit log
   */
  public void logRename(String src, String dst, long timestamp) {
    RenameOp op = RenameOp.getInstance();
    op.set(src, dst, timestamp);
    logEdit(op);
  }
 
  /**
   * Add set replication record to edit log
   */
  public void logSetReplication(String src, short replication) {
    SetReplicationOp op = SetReplicationOp.getInstance();
    op.set(src, replication);
    logEdit(op);
  }
 
  /** Add set namespace quota record to edit log
   *
   * @param src the string representation of the path to a directory
   * @param quota the directory size limit
   */
  public void logSetQuota(String src, long nsQuota, long dsQuota) {
    SetQuotaOp op = SetQuotaOp.getInstance();
    op.set(src, nsQuota, dsQuota);
    logEdit(op);
  }

  /**  Add set permissions record to edit log */
  public void logSetPermissions(String src, FsPermission permissions) {
    SetPermissionsOp op = SetPermissionsOp.getInstance();
    op.set(src, permissions);
    logEdit(op);
  }

  /**  Add set owner record to edit log */
  public void logSetOwner(String src, String username, String groupname) {
    SetOwnerOp op = SetOwnerOp.getInstance();
    op.set(src, username, groupname);
    logEdit(op);
  }

  /**
   * concat(trg,src..) log
   */
  public void logConcat(String trg, String [] srcs, long timestamp) {
    ConcatDeleteOp op = ConcatDeleteOp.getInstance();
    op.set(trg, srcs, timestamp);
    logEdit(op);
  }
 
  /**
   * Add delete file record to edit log
   */
  public void logDelete(String src, long timestamp) {
    DeleteOp op = DeleteOp.getInstance();
    op.set(src, timestamp);
    logEdit(op);
  }

  /**
   * Add generation stamp record to edit log
   */
  public void logGenerationStamp(long genstamp) {
    SetGenstampOp op = SetGenstampOp.getInstance();
    op.set(genstamp);
    logEdit(op);
  }

  /**
   * Add access time record to edit log
   */
  public void logTimes(String src, long mtime, long atime) {
    TimesOp op = TimesOp.getInstance();
    op.set(src, mtime, atime);
    logEdit(op);
  }

  /**
   * Return the size of the current EditLog
   */
  synchronized long getEditLogSize() throws IOException {
    assert(getNumStorageDirs() == editStreams.size());
    long size = 0;
    for (int idx = 0; idx < editStreams.size(); idx++) {
      EditLogOutputStream es = editStreams.get(idx);
      try {
        long curSize = es.length();
        assert (size == 0 || size == curSize) : "All streams must be the same";
        size = curSize;
      } catch (IOException e) {
        FSImage.LOG.warn("getEditLogSize: editstream.length failed. removing editlog (" +
            idx + ") " + es.getName(), e);
        processIOError(idx);
      }
    }
    return size;
  }

  /**
   * Closes the current edit log and opens edits.new.
   * Returns the lastModified time of the edits log.
   */
  synchronized void rollEditLog() throws IOException {
    //
    // If edits.new already exists in some directory, verify it
    // exists in all directories.
    //
    if (existsNew()) {
      for (Iterator<StorageDirectory> it =
               fsimage.dirIterator(NameNodeDirType.EDITS); it.hasNext();) {
        File editsNew = getEditNewFile(it.next());
     if (!editsNew.exists()) {
          throw new IOException("Inconsistent existance of edits.new " +
                                editsNew);
        }
      }
      return; // nothing to do, edits.new exists!
    }

    close();                     // close existing edit log

    fsimage.attemptRestoreRemovedStorage();
   
    //
    // Open edits.new
    //
    boolean failedSd = false;
    for (Iterator<StorageDirectory> it =
           fsimage.dirIterator(NameNodeDirType.EDITS); it.hasNext();) {
      StorageDirectory sd = it.next();
      try {
        EditLogFileOutputStream eStream =
             new EditLogFileOutputStream(getEditNewFile(sd), metrics);
        eStream.create();
        editStreams.add(eStream);
      } catch (IOException e) {
        failedSd = true;
        // remove stream and this storage directory from list
        FSImage.LOG.warn("rollEdidLog: removing storage " + sd.getRoot().getPath(), e);
        sd.unlock();
        fsimage.removedStorageDirs.add(sd);
        it.remove();
      }
    }
    if(failedSd)
      fsimage.incrementCheckpointTime()// update time for the valid ones
  }
 
  /**
   * Removes the old edit log and renamed edits.new as edits.
   * Reopens the edits file.
   */
  synchronized void purgeEditLog() throws IOException {
    //
    // If edits.new does not exists, then return error.
    //
    if (!existsNew()) {
      throw new IOException("Attempt to purge edit log " +
                            "but edits.new does not exist.");
    }
    close();

    //
    // Delete edits and rename edits.new to edits.
    //
    for (Iterator<StorageDirectory> it =
           fsimage.dirIterator(NameNodeDirType.EDITS); it.hasNext();) {
      StorageDirectory sd = it.next();

      if (!getEditNewFile(sd).renameTo(getEditFile(sd))) {
        //
        // renameTo() fails on Windows if the destination
        // file exists.
        //
        getEditFile(sd).delete();
        if (!getEditNewFile(sd).renameTo(getEditFile(sd))) {
          // Should we also remove from edits
          NameNode.LOG.warn("purgeEditLog: removing failed storage " + sd.getRoot().getPath());
          fsimage.removedStorageDirs.add(sd);
          it.remove();
        }
      }
    }
    //
    // Reopen all the edits logs.
    //
    open();
  }

  /**
   * Return the name of the edit file
   */
  synchronized File getFsEditName() throws IOException {
    StorageDirectory sd = null;
    for (Iterator<StorageDirectory> it =
        fsimage.dirIterator(NameNodeDirType.EDITS); it.hasNext();) {
      sd = it.next();
      File fsEdit = getEditFile(sd);
      if (sd.getRoot().canRead() && fsEdit.exists()) {
        return fsEdit;
      }
    }
    return null;
  }
 
  /**
   * Return the name of the edit.new file
   */
  synchronized File getFsEditNewName() throws IOException {
    StorageDirectory sd = null;
    for (Iterator<StorageDirectory> it =
        fsimage.dirIterator(NameNodeDirType.EDITS); it.hasNext();) {
      sd = it.next();
      File fsEdit = getEditNewFile(sd);
      if (sd.getRoot().canRead() && fsEdit.exists()) {
        return fsEdit;
      }
    }
    return null;
  }

  /**
   * Returns the timestamp of the edit log
   */
  synchronized long getFsEditTime() {
    Iterator<StorageDirectory> it = fsimage.dirIterator(NameNodeDirType.EDITS);
    if(it.hasNext())
      return getEditFile(it.next()).lastModified();
    return 0;
  }

  // sets the initial capacity of the flush buffer.
  static void setBufferCapacity(int size) {
    sizeFlushBuffer = size;
  }
  //
  // maximum number of transactions to be buffered in memory
  static void setMaxBufferedTransactions(int num) {
    maxBufferedTransactions = num;
  }

  // sets the preallocate trigger of the edits log.
  static void setPreallocateSize(long size) {
    preallocateSize = size;
  }

  /**
   * Return the current transaction ID for the edit log.
   * This is the transaction ID that would be issued to the next transaction.
   */
  public synchronized long getCurrentTxId() {
    return txid;
  }

  /**
   * Return the transaction ID for the transaction that was written last.
   */
  synchronized long getLastWrittenTxId() {
    return getCurrentTxId() - 1;
  }
 
  synchronized long getLastSyncedTxId() {
    return synctxid;
  }

  /**
   * A class to read in blocks stored in the old format. The only two
   * fields in the block were blockid and length.
   */
  static class BlockTwo implements Writable {
    long blkid;
    long len;

    static {                                      // register a ctor
      WritableFactories.setFactory
        (BlockTwo.class,
         new WritableFactory() {
           public Writable newInstance() { return new BlockTwo(); }
         });
    }


    BlockTwo() {
      blkid = 0;
      len = 0;
    }
    /////////////////////////////////////
    // Writable
    /////////////////////////////////////
    public void write(DataOutput out) throws IOException {
      out.writeLong(blkid);
      out.writeLong(len);
    }

    public void readFields(DataInput in) throws IOException {
      this.blkid = in.readLong();
      this.len = in.readLong();
    }
  }

  /** This method is defined for compatibility reason. */
  static private DatanodeDescriptor[] readDatanodeDescriptorArray(DataInput in
      ) throws IOException {
    DatanodeDescriptor[] locations = new DatanodeDescriptor[in.readInt()];
    for (int i = 0; i < locations.length; i++) {
      locations[i] = new DatanodeDescriptor();
      locations[i].readFieldsFromFSEditLog(in);
    }
    return locations;
  }

  static private Block[] readBlocks(DataInputStream in) throws IOException {
    int numBlocks = in.readInt();
    Block[] blocks = new Block[numBlocks];
    for (int i = 0; i < numBlocks; i++) {
      blocks[i] = new Block();
      blocks[i].readFields(in);
    }
    return blocks;
  }
 
  private static void incrOpCount(FSEditLogOpCodes opCode,
      EnumMap<FSEditLogOpCodes, Holder<Integer>> opCounts) {
    Holder<Integer> holder = opCounts.get(opCode);
    if (holder == null) {
      holder = new Holder<Integer>(1);
      opCounts.put(opCode, holder);
    } else {
      holder.held++;
    }
  }
 
  public static void dumpOpCounts(
      EnumMap<FSEditLogOpCodes, Holder<Integer>> opCounts) {
    StringBuilder sb = new StringBuilder();
    sb.append("Summary of operations loaded from edit log:\n  ");
    sb.append(opCounts);
    FSImage.LOG.debug(sb.toString());
  }

}
TOP

Related Classes of org.apache.hadoop.hdfs.server.namenode.FSEditLog

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.