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

Source Code of org.apache.hadoop.hdfs.server.namenode.TestEditLog2$Transactions

/**
* 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 junit.framework.TestCase;
import java.io.*;
import java.util.Iterator;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.permission.*;

import org.apache.hadoop.hdfs.MiniDFSCluster;
import org.apache.hadoop.hdfs.server.namenode.EditLogFileInputStream;
import org.apache.hadoop.hdfs.server.common.Storage.StorageDirectory;

/**
* This class tests the creation and validation of a checkpoint.
*/
public class TestEditLog2 extends TestCase {
 
  static final Log LOG = LogFactory.getLog(TestEditLog.class);
 
  static final int NUM_DATA_NODES = 0;

  // This test creates NUM_THREADS threads and each thread does
  // 2 * NUM_TRANSACTIONS Transactions concurrently.
  static final int NUM_TRANSACTIONS = 10;
  static final int NUM_THREADS = 10;
 

  //
  // an object that does a bunch of transactions
  //
  static class Transactions implements Runnable {
    FSNamesystem namesystem;
    int numTransactions;
    short replication = 3;
    long blockSize = 64;
    int id;

    Transactions(FSNamesystem ns, int num, int i) {
      namesystem = ns;
      numTransactions = num;
      id = i;
    }

    // add a bunch of transactions.
    public void run() {
      PermissionStatus p = namesystem.createFsOwnerPermissions(
                                          new FsPermission((short)0777));
      FSEditLog editLog = namesystem.getEditLog();

      try {
        for (int i = 0; i < numTransactions; i++) {
          INode inodeDir = new INodeDirectory("/hadoop."+i+"_"+id, p);
          editLog.logMkDir("/hadoop1."+i+"_"+id, inodeDir);
         
         
          INodeFileUnderConstruction inode1 = new INodeFileUnderConstruction(
                              p, replication, blockSize, 0, "", "", null);
          editLog.logOpenFile("/filename1." + i+"_"+id, inode1);
          editLog.logCloseFile("/filename1." + i+"_"+id, inode1);
         
          INodeFileUnderConstruction inode2 = new INodeFileUnderConstruction(
              p, replication, blockSize, 0, "", "", null);
          editLog.logOpenFile("/filename2." + i+"_"+id, inode2);
          editLog.logCloseFile("/filename2." + i+"_"+id, inode2);
         
          editLog.logGenerationStamp(i);
          editLog.logSetOwner("/filename1." + i+"_"+id, "hadoop2", "hadoop2");
          editLog.logSetPermissions("/filename1." + i+"_"+id, p.getPermission());
          editLog.logSetQuota("/hadoop1." + i+"_"+id, 100 + i, 100 + i);
          editLog.logSetReplication("/filename1." + i+"_"+id, (short)2);
          editLog.logTimes("/filename1." + i+"_"+id, i, i);
          editLog.logRename("/hadoop1."+i+"_"+id, "/hadoop2."+i+"_"+id, i);
         
          editLog.logConcat("/filename1." + i+"_"+id, new String[] {"/filename1." + i+"_"+id, "/filename2." + i+"_"+id}, i);
          editLog.logDelete("/filename1." + i+"_"+id, i+1);
          editLog.logDelete("/hadoop1." + i+"_"+id, i+1);
          editLog.logSync();
        }
      } catch (Exception e) {
        throw new RuntimeException(e);
      }
    }
  }

  /**
   * Simple test for writing to and rolling the edit log.
   */
  public void testSimpleEditLog() throws IOException {
    // start a cluster
    Configuration conf = new Configuration();
    MiniDFSCluster cluster = null;
    FileSystem fileSys = null;
    try {
      cluster = new MiniDFSCluster(conf, NUM_DATA_NODES, true, null);
      cluster.waitActive();
      fileSys = cluster.getFileSystem();
      final FSNamesystem namesystem = cluster.getNameNode().getNamesystem();
      FSImage fsimage = namesystem.getFSImage();
      final FSEditLog editLog = fsimage.getEditLog();

      editLog.logSetReplication("fakefile", (short) 1);
      editLog.logSync();
      editLog.rollEditLog();
      editLog.logSetReplication("fakefile", (short) 2);
      editLog.logSync();
     
      editLog.close();
    } finally {
      if(fileSys != null) fileSys.close();
      if(cluster != null) cluster.shutdown();
    }
  }

  /**
   * Tests transaction logging in dfs.
   */
  public void testMultiThreadedEditLog() throws IOException {
    testEditLog(2048);
    // force edit buffer to automatically sync on each log of edit log entry
    testEditLog(1);
  }
 
  /**
   * Test edit log with different initial buffer size
   *
   * @param initialSize initial edit log buffer size
   * @throws IOException
   */
  private void testEditLog(int initialSize) throws IOException {

    // start a cluster
    Configuration conf = new Configuration();
    MiniDFSCluster cluster = null;
    FileSystem fileSys = null;

    try {
      cluster = new MiniDFSCluster(conf, NUM_DATA_NODES, true, null);
      cluster.waitActive();
      fileSys = cluster.getFileSystem();
      final FSNamesystem namesystem = cluster.getNameNode().getNamesystem();
           
      namesystem.saveNamespace(true, true)
      FSImage fsimage = namesystem.getFSImage();
      FSEditLog editLog = fsimage.getEditLog();
 
      // set small size of flush buffer
      FSEditLog.setBufferCapacity(initialSize);
     
      // Roll log so new output buffer size takes effect
      fsimage.rollEditLog();
      namesystem.saveNamespace(true, true);
   
      // Create threads and make them run transactions concurrently.
      Thread threadId[] = new Thread[NUM_THREADS];
      for (int i = 0; i < NUM_THREADS; i++) {
        Transactions trans = new Transactions(namesystem, NUM_TRANSACTIONS, i);
        threadId[i] = new Thread(trans, "TransactionThread-" + i);
        threadId[i].start();
      }
 
      // wait for all transactions to get over
      for (int i = 0; i < NUM_THREADS; i++) {
        try {
          threadId[i].join();
        } catch (InterruptedException e) {
          i--;      // retry
        }
      }
     
      namesystem.rollEditLog();
     
     
     
      long expectedTxns = (NUM_THREADS * NUM_TRANSACTIONS * 15);
  
      // Verify that we can read in all the transactions that we have written.
      // If there were any corruptions, it is likely that the reading in
      // of these transactions will throw an exception.
      //
      for (Iterator<StorageDirectory> it =
              fsimage.dirIterator(); it.hasNext();) {
        StorageDirectory sd = it.next();     
        File editFile = namesystem.getFSImage().getEditFile(sd);
        if(editFile == null)
          continue;
       
        cluster.getNameNode().getFSImage().getEditLog().setStartTransactionId(0);
       
        System.out.println("Verifying file: " + editFile);
        EditLogInputStream is = new EditLogFileInputStream(editFile);
        FSEditLogLoader loader = new FSEditLogLoader(namesystem);
        int numEdits = loader.loadFSEdits(is, namesystem.getEditLog().getCurrentTxId());
        int numLeases = namesystem.leaseManager.countLease();
        System.out.println("Number of outstanding leases " + numLeases);
        assertEquals(0, numLeases);
        assertTrue("Verification for " + editFile + " failed. " +
                   "Expected " + expectedTxns + " transactions. "+
                   "Found " + numEdits + " transactions.",
                   numEdits == expectedTxns);
 
      }
    } finally {
      try {
        if(fileSys != null) fileSys.close();
        if(cluster != null) cluster.shutdown();
      } catch (Throwable t) {
        LOG.error("Couldn't shut down cleanly", t);
      }
    }
  }

  private void doLogEdit(ExecutorService exec, final FSEditLog log,
    final String filename) throws Exception
  {
    exec.submit(new Callable<Void>() {
      public Void call() {
        log.logSetReplication(filename, (short)1);
        return null;
      }
    }).get();
  }
 
  private void doCallLogSync(ExecutorService exec, final FSEditLog log)
    throws Exception
  {
    exec.submit(new Callable<Void>() {
      public Void call() {
        try {
          log.logSyncAll();
        } catch (IOException e) {
          throw new RuntimeException(e);
        }
        return null;
      }
    }).get();
  }

  private void doCallLogSyncAll(ExecutorService exec, final FSEditLog log)
    throws Exception
  {
    exec.submit(new Callable<Void>() {
      public Void call() throws Exception {
        log.logSyncAll();
        return null;
      }
    }).get();
  }

  public void testSyncBatching() throws Exception {
    // start a cluster
    Configuration conf = new Configuration();
    MiniDFSCluster cluster = null;
    FileSystem fileSys = null;
    ExecutorService threadA = Executors.newSingleThreadExecutor();
    ExecutorService threadB = Executors.newSingleThreadExecutor();
    try {
      cluster = new MiniDFSCluster(conf, NUM_DATA_NODES, true, null);
      cluster.waitActive();
      fileSys = cluster.getFileSystem();
      final FSNamesystem namesystem = cluster.getNameNode().getNamesystem();

      FSImage fsimage = namesystem.getFSImage();
      final FSEditLog editLog = fsimage.getEditLog();
     
      // Log an edit from thread A
      doLogEdit(threadA, editLog, "thread-a 1");

      // Log an edit from thread B
      doLogEdit(threadB, editLog, "thread-b 1");
      assertEquals("logging edit without syncing should do not affect txid",
        0, editLog.getLastSyncedTxId());

      // Now ask to sync edit from B, which should sync both edits.
      doCallLogSync(threadB, editLog);
      assertEquals("logSync from second thread should bump txid up to 2",
        2, editLog.getLastSyncedTxId());

      // Now ask to sync edit from A, which was already batched in - thus
      // it should increment the batch count metric
      doCallLogSync(threadA, editLog);
      assertEquals("logSync from first thread shouldn't change txid",
        2, editLog.getLastSyncedTxId());

    } finally {
      threadA.shutdown();
      threadB.shutdown();
      if(fileSys != null) fileSys.close();
      if(cluster != null) cluster.shutdown();
    }
  }
 
  /**
   * Test what happens with the following sequence:
   *
   *  Thread A writes edit
   *  Thread B calls logSyncAll
   *           calls close() on stream
   *  Thread A calls logSync
   *
   * This sequence is legal and can occur if enterSafeMode() is closely
   * followed by saveNamespace.
   */
  public void testBatchedSyncWithClosedLogs() throws Exception {
    // start a cluster
    Configuration conf = new Configuration();
    MiniDFSCluster cluster = null;
    FileSystem fileSys = null;
    ExecutorService threadA = Executors.newSingleThreadExecutor();
    ExecutorService threadB = Executors.newSingleThreadExecutor();
    try {
      cluster = new MiniDFSCluster(conf, NUM_DATA_NODES, true, null);
      cluster.waitActive();
      fileSys = cluster.getFileSystem();
      final FSNamesystem namesystem = cluster.getNameNode().getNamesystem();

      FSImage fsimage = namesystem.getFSImage();
      final FSEditLog editLog = fsimage.getEditLog();

      // Log an edit from thread A
      doLogEdit(threadA, editLog, "thread-a 1");
      assertEquals("logging edit without syncing should do not affect txid",
        0, editLog.getLastSyncedTxId());

      // logSyncAll in Thread B
      doCallLogSyncAll(threadB, editLog);
      assertEquals("logSyncAll should sync thread A's transaction",
        1, editLog.getLastSyncedTxId());
      // Close edit log
      editLog.close();

      // Ask thread A to finish sync (which should be a no-op)
      doCallLogSync(threadA, editLog);
    } finally {
      threadA.shutdown();
      threadB.shutdown();
      if(fileSys != null) fileSys.close();
      if(cluster != null) cluster.shutdown();
    }
  }
}
TOP

Related Classes of org.apache.hadoop.hdfs.server.namenode.TestEditLog2$Transactions

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.