Package org.apache.hadoop.hdfs

Source Code of org.apache.hadoop.hdfs.TestLookasideCache

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

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.URI;
import java.util.Random;
import java.util.zip.CRC32;

import org.apache.commons.logging.impl.Log4JLogger;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.permission.FsPermission;
import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.util.Progressable;
import org.apache.hadoop.hdfs.metrics.LookasideMetrics.LocalMetrics;
import org.apache.log4j.Level;

/**
* This class tests the lookaside cache.
*/
public class TestLookasideCache extends junit.framework.TestCase {
  final static Log LOG = LogFactory.getLog("org.apache.hadoop.hdfs.TestLookasideCache");
  final static String TEST_DIR = new File(System.getProperty("test.build.data",
      "build/lookasidecache/test/data")).getAbsolutePath();
  final static int NUM_DATANODES = 3;

  {
    ((Log4JLogger)LookasideCache.LOG).getLogger().setLevel(Level.ALL);
    ((Log4JLogger)LookasideCacheFileSystem.LOG).getLogger().setLevel(Level.ALL);
  }

  public void testCache() throws IOException {
    Configuration conf = new Configuration();
    long maxSize = 5 * 1024;
    long evictPercent = 20;
    conf.setLong(LookasideCache.CACHESIZE, maxSize);
    conf.setLong(LookasideCache.CACHEEVICT_PERCENT,  evictPercent);
    LookasideCache cache = new LookasideCache(conf);
    LocalMetrics metrics = LookasideCache.getLocalMetrics();
    metrics.reset();

    assertTrue(cache.getCacheMaxSize() == maxSize);
    assertTrue(cache.getCacheSize() == 0);
    assertTrue(cache.getCacheEvictPercent() == evictPercent);

    // insert five elements into the cache, each of size 1024
    cache.addCache(new Path("one"), new Path("one"), 1024);
    cache.addCache(new Path("two"), new Path("two"), 1024);
    cache.addCache(new Path("three"), new Path("three"), 1024);
    cache.addCache(new Path("four"), new Path("four"), 1024);
    cache.addCache(new Path("five"), new Path("five"), 1024);
    assertTrue(cache.getCacheSize() == 5 * 1024);
    assertTrue(metrics.numAdd == 5);
    assertTrue(metrics.numAddNew == 5);
    assertTrue(metrics.numAddExisting == 0);

    // the cache is now full. If we add one more element, the oldest
    // two should be evicted
    cache.addCache(new Path("six"), new Path("six"), 512);
    assertTrue("cachesize is " + cache.getCacheSize(),
               cache.getCacheSize() == 3 * 1024 + 512);

    // verify that first two are not there. and the rest is there
    assertTrue(cache.getCache(new Path("one")) == null);
    assertTrue(cache.getCache(new Path("two")) == null);
    assertTrue(cache.getCache(new Path("three")) != null);
    assertTrue(cache.getCache(new Path("four")) != null);
    assertTrue(cache.getCache(new Path("five")) != null);
    assertTrue(cache.getCache(new Path("six")) != null);
    assertTrue(metrics.numEvict == 2);

    // make three the most recently used
    assertTrue(cache.getCache(new Path("three")) != null);
    assertTrue(metrics.numGetAttempts == 7);
    assertTrue(metrics.numGetHits == 5);

    // now we insert seven.
    cache.addCache(new Path("seven"), new Path("seven"), 512);
    assertTrue(cache.getCacheSize() == 4 * 1024);

    assertTrue(cache.getCache(new Path("one")) == null);
    assertTrue(cache.getCache(new Path("two")) == null);
    assertTrue(cache.getCache(new Path("three")) != null);
    assertTrue(cache.getCache(new Path("four")) != null);
    assertTrue(cache.getCache(new Path("five")) != null);
    assertTrue(cache.getCache(new Path("six")) != null);
    assertTrue(cache.getCache(new Path("seven")) != null);
  }

  public void testCacheFileSystem() throws IOException {

    // configure a cached filessytem, cache size is 10 KB.
    mySetup(10*1024L);

    try {
      // create a 5K file using the LookasideCache. This write
      // should be cached in the cache.
      Path file = new Path("/hdfs/testRead");
      long crc = createTestFile(lfs, file, 1, 5, 1024L);
      FileStatus stat = lfs.getFileStatus(file);
      LOG.info("Created " + file + ", crc=" + crc + ", len=" + stat.getLen());
      assertTrue(lfs.lookasideCache.getCacheSize() == 5 * 1024);

      // Test that readFully via the Lookasidecache fetches correct data
      // from the cache.
      FSDataInputStream stm = lfs.open(file);
      byte[] filebytes = new byte[(int)stat.getLen()];
      stm.readFully(0, filebytes);
      assertEquals(crc, bufferCRC(filebytes));
      stm.close();

      // assert that there is one element of size 5K in the cache
      assertEquals(5*1024, lfs.lookasideCache.getCacheSize());

      // create a 6K file using the LookasideCache. This is an
      // overwrite of the earlier file, so the cache should reflect
      // the new size of the file.
      crc = createTestFile(lfs, file, 1, 6, 1024L);
      stat = lfs.getFileStatus(file);
      LOG.info("Created " + file + ", crc=" + crc + ", len=" + stat.getLen());

      // assert that there is one element of size 6K in the cache
      assertEquals(6*1024, lfs.lookasideCache.getCacheSize());

      // verify reading file2 from the cache
      stm = lfs.open(file);
      filebytes = new byte[(int)stat.getLen()];
      stm.readFully(0, filebytes);
      assertEquals(crc, bufferCRC(filebytes));
      stm.close();

      // add a 5 KB file to the cache. This should start eviction of
      // the earlier file.
      Path file2 = new Path("/hdfs/testRead2");
      crc = createTestFile(lfs, file2, 1, 5, 1024L);
      stat = lfs.getFileStatus(file2);
      LOG.info("Created " + file2 + ", crc=" + crc + ", len=" + stat.getLen());
      assertEquals(5*1024, lfs.lookasideCache.getCacheSize());

      // move file2 to file3
      Path file3 = new Path("/hdfs/testRead3");
      assertTrue(lfs.rename(file2, file3));

      // delete file3. This should clear out the cache.
      lfs.delete(file3, false);
      assertEquals(0, lfs.lookasideCache.getCacheSize());

    } finally {
      myTearDown();
    }
  }

  private MiniDFSCluster dfs;
  private FileSystem fileSys;
  private LookasideCacheFileSystem lfs;
  private String namenode;
  private String hftp;

  // setup a LookasideCachedFileSystem
  private void mySetup(long cacheSize) throws IOException {
    Configuration conf = new Configuration();

    // create a HDFS cluster
    dfs = new MiniDFSCluster(conf, NUM_DATANODES, true, null);
    dfs.waitActive();
    fileSys = dfs.getFileSystem();
    namenode = fileSys.getUri().toString();
    hftp = "hftp://localhost.localdomain:" + dfs.getNameNodePort();
    FileSystem.setDefaultUri(conf, namenode);

    // create a client-side layered filesystem.
    // The cache size is 10 KB.
    lfs = getCachedHdfs(fileSys, conf, cacheSize);
  }

  private void myTearDown() throws IOException {
    if (dfs != null) { dfs.shutdown(); }
  }


  /**
   * Returns a cached filesystem layered on top of the HDFS cluster
   */
  private LookasideCacheFileSystem getCachedHdfs(FileSystem fileSys,
                        Configuration conf, long cacheSize) throws IOException {
    DistributedFileSystem dfs = (DistributedFileSystem)fileSys;
    Configuration clientConf = new Configuration(conf);

    clientConf.setLong(LookasideCache.CACHESIZE, cacheSize);
    clientConf.set("fs.lookasidecache.dir", TEST_DIR);
    clientConf.set("fs.hdfs.impl", "org.apache.hadoop.hdfs.LookasideCacheFileSystem");
    clientConf.set("fs.lookasidecache.underlyingfs.impl",
                   "org.apache.hadoop.hdfs.DistributedFileSystem");
    URI dfsUri = dfs.getUri();
    FileSystem.closeAll();
    FileSystem lfs = FileSystem.get(dfsUri, clientConf);
    assertTrue("lfs not an instance of LookasideCacheFileSystem",
               lfs instanceof LookasideCacheFileSystem);
    return (LookasideCacheFileSystem)lfs;
  }

  //
  // creates a file and populate it with random data. Returns its crc.
  //
  private static long createTestFile(FileSystem fileSys, Path name, int repl,
                        int numBlocks, long blocksize)
    throws IOException {
    CRC32 crc = new CRC32();
    Random rand = new Random();
    FSDataOutputStream stm = fileSys.create(name, true,
                        fileSys.getConf().getInt("io.file.buffer.size", 4096),
                        (short)repl, blocksize);
    // fill random data into file
    final byte[] b = new byte[(int)blocksize];
    for (int i = 0; i < numBlocks; i++) {
      rand.nextBytes(b);
      stm.write(b);
      crc.update(b);
    }
    stm.close();
    return crc.getValue();
  }

  /**
   * returns the CRC32 of the buffer
   */
  private long bufferCRC(byte[] buf) {
    CRC32 crc = new CRC32();
    crc.update(buf, 0, buf.length);
    return crc.getValue();
  }
}
TOP

Related Classes of org.apache.hadoop.hdfs.TestLookasideCache

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.