/** * 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.fs; import junit.framework.TestCase; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.lang.reflect.Field; import java.util.Random; import java.util.concurrent.ConcurrentMap; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.DU.NamespaceSliceDU; import org.apache.hadoop.util.Shell; import org.apache.hadoop.util.Shell.ExitCodeException; /** This test makes sure that "DU" does not get to run on each call to getUsed */ public class TestDU extends TestCase { final static private File DU_DIR = new File( System.getProperty("test.build.data","/tmp"), "dutmp"); public void setUp() throws IOException { FileUtil.fullyDelete(DU_DIR); assertTrue(DU_DIR.mkdirs()); } public void tearDown() throws IOException { FileUtil.fullyDelete(DU_DIR); } private void createFile(File newFile, int size) throws IOException { // write random data so that filesystems with compression enabled (e.g., ZFS) // can't compress the file Random random = new Random(); byte[] data = new byte[size]; random.nextBytes(data); newFile.createNewFile(); RandomAccessFile file = new RandomAccessFile(newFile, "rws"); file.write(data); file.getFD().sync(); file.close(); } /** * Verify that du returns expected used space for a file. * We assume here that if a file system crates a file of size * that is a multiple of the block size in this file system, * then the used size for the file will be exactly that size. * This is true for most file systems. * * @throws IOException * @throws InterruptedException * @throws NoSuchFieldException * @throws SecurityException * @throws IllegalAccessException * @throws IllegalArgumentException */ @SuppressWarnings("unchecked") public void testDU() throws IOException, InterruptedException, SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException { int writtenSize = 32*1024; // writing 32K File file = DU_DIR; File file0 = new File(DU_DIR, "NS-0"); File file1 = new File(DU_DIR, "NS-1"); createFile(file0, writtenSize); createFile(file1, writtenSize); Configuration conf = new Configuration(); Thread.sleep(5000); // let the metadata updater catch up DU du = new DU(file, 1000); NamespaceSliceDU nsdu0 = du.addNamespace(0, file0, conf); NamespaceSliceDU nsdu1 = du.addNamespace(1, file1, conf); du.start(); long duSize0 = nsdu0.getUsed(); long duSize1 = nsdu1.getUsed(); assertEquals(writtenSize, duSize0); assertEquals(writtenSize, duSize1); // delete the file, expect it throws exception file0.delete(); file1.delete(); Thread.sleep(2000); try { duSize0 = nsdu0.getUsed(); assertTrue(false); } catch (IOException ex) { } try { duSize1 = nsdu1.getUsed(); assertTrue(false); } catch (IOException ex) { } //change the size createFile(file0, writtenSize - 4096); createFile(file1, writtenSize + 4096); Thread.sleep(5000); duSize0 = nsdu0.getUsed(); duSize1 = nsdu1.getUsed(); du.shutdown(); assertEquals(writtenSize - 4096, duSize0); assertEquals(writtenSize + 4096, duSize1); //test with 0 interval, will not launch thread du = new DU(file, 0); nsdu0 = du.addNamespace(0, file0, conf); nsdu1 = du.addNamespace(1, file1, conf); du.start(); duSize0 = nsdu0.getUsed(); duSize1 = nsdu1.getUsed(); du.shutdown(); assertEquals(writtenSize - 4096, duSize0); assertEquals(writtenSize + 4096, duSize1); //test without launching thread du = new DU(file, 10000); nsdu0 = du.addNamespace(0, file0, new Configuration()); duSize0 = nsdu0.getUsed(); assertEquals(writtenSize - 4096, duSize0); // test processErrorOutput Field namespaceSliceDUMapField = DU.class.getDeclaredField("namespaceSliceDUMap"); namespaceSliceDUMapField.setAccessible(true); ConcurrentMap<Integer, NamespaceSliceDU> namespaceSliceDUMap = (ConcurrentMap<Integer, NamespaceSliceDU>) namespaceSliceDUMapField .get(du); NamespaceSliceDU nssd = namespaceSliceDUMap.get(0); // Throw when exit code is not 1 boolean thrown = false; try { nssd.processErrorOutput(new ExitCodeException(1, "du: cannot access `a1.txt': No such file or directory")); } catch(ExitCodeException ece) { thrown = true; } TestCase.assertTrue(thrown); Field exitCodeField = Shell.class.getDeclaredField("exitCode"); exitCodeField.setAccessible(true); exitCodeField.set(nssd, 1); // One single file fails to be accessed. nssd.processErrorOutput(new ExitCodeException(1, "du: cannot access `a1.txt': No such file or directory")); // Two files fail to be accessed nssd.processErrorOutput(new ExitCodeException(1, "du: cannot access `a2.txt': No such file or directory\ndu: cannot access `a3.txt': No such file or directory")); // Two files fail to be accessed, one is the same as the previous one thrown = false; try { nssd.processErrorOutput(new ExitCodeException( 1, "du: cannot access `a4.txt': No such file or directory\ndu: cannot access `a3.txt': No such file or directory")); } catch (IOException ioe) { thrown = true; } TestCase.assertTrue(thrown); // Two files fail to be accessed, one is the same as a previous one thrown = false; try { nssd.processErrorOutput(new ExitCodeException( 1, "du: cannot access `a2.txt': No such file or directory\ndu: cannot access `a5.txt': No such file or directory")); } catch (IOException ioe) { thrown = true; } TestCase.assertTrue(thrown); // Two files fail to be accessed nssd.processErrorOutput(new ExitCodeException(1, "du: cannot access `a6.txt': No such file or directory")); } }