blob: c01844d63a774ba980cade8868150d6d8e3960aa [file] [log] [blame]
/**
* 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.startupprogress;
import static org.apache.hadoop.hdfs.server.namenode.startupprogress.Phase.*;
import static org.apache.hadoop.hdfs.server.namenode.startupprogress.StartupProgressTestHelper.*;
import static org.apache.hadoop.hdfs.server.namenode.startupprogress.Status.*;
import static org.apache.hadoop.hdfs.server.namenode.startupprogress.StepType.*;
import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import org.junit.Before;
import org.junit.Test;
public class TestStartupProgress {
private StartupProgress startupProgress;
@Before
public void setUp() {
startupProgress = new StartupProgress();
}
@Test(timeout=10000)
public void testCounter() {
startupProgress.beginPhase(LOADING_FSIMAGE);
Step loadingFsImageInodes = new Step(INODES);
startupProgress.beginStep(LOADING_FSIMAGE, loadingFsImageInodes);
incrementCounter(startupProgress, LOADING_FSIMAGE, loadingFsImageInodes,
100L);
startupProgress.endStep(LOADING_FSIMAGE, loadingFsImageInodes);
Step loadingFsImageDelegationKeys = new Step(DELEGATION_KEYS);
startupProgress.beginStep(LOADING_FSIMAGE, loadingFsImageDelegationKeys);
incrementCounter(startupProgress, LOADING_FSIMAGE,
loadingFsImageDelegationKeys, 200L);
startupProgress.endStep(LOADING_FSIMAGE, loadingFsImageDelegationKeys);
startupProgress.endPhase(LOADING_FSIMAGE);
startupProgress.beginPhase(LOADING_EDITS);
Step loadingEditsFile = new Step("file", 1000L);
startupProgress.beginStep(LOADING_EDITS, loadingEditsFile);
incrementCounter(startupProgress, LOADING_EDITS, loadingEditsFile, 5000L);
StartupProgressView view = startupProgress.createView();
assertNotNull(view);
assertEquals(100L, view.getCount(LOADING_FSIMAGE, loadingFsImageInodes));
assertEquals(200L, view.getCount(LOADING_FSIMAGE,
loadingFsImageDelegationKeys));
assertEquals(5000L, view.getCount(LOADING_EDITS, loadingEditsFile));
assertEquals(0L, view.getCount(SAVING_CHECKPOINT,
new Step(INODES)));
// Increment a counter again and check that the existing view was not
// modified, but a new view shows the updated value.
incrementCounter(startupProgress, LOADING_EDITS, loadingEditsFile, 1000L);
startupProgress.endStep(LOADING_EDITS, loadingEditsFile);
startupProgress.endPhase(LOADING_EDITS);
assertEquals(5000L, view.getCount(LOADING_EDITS, loadingEditsFile));
view = startupProgress.createView();
assertNotNull(view);
assertEquals(6000L, view.getCount(LOADING_EDITS, loadingEditsFile));
}
@Test(timeout=10000)
public void testElapsedTime() throws Exception {
startupProgress.beginPhase(LOADING_FSIMAGE);
Step loadingFsImageInodes = new Step(INODES);
startupProgress.beginStep(LOADING_FSIMAGE, loadingFsImageInodes);
Thread.sleep(50L); // brief sleep to fake elapsed time
startupProgress.endStep(LOADING_FSIMAGE, loadingFsImageInodes);
Step loadingFsImageDelegationKeys = new Step(DELEGATION_KEYS);
startupProgress.beginStep(LOADING_FSIMAGE, loadingFsImageDelegationKeys);
Thread.sleep(50L); // brief sleep to fake elapsed time
startupProgress.endStep(LOADING_FSIMAGE, loadingFsImageDelegationKeys);
startupProgress.endPhase(LOADING_FSIMAGE);
startupProgress.beginPhase(LOADING_EDITS);
Step loadingEditsFile = new Step("file", 1000L);
startupProgress.beginStep(LOADING_EDITS, loadingEditsFile);
startupProgress.setTotal(LOADING_EDITS, loadingEditsFile, 10000L);
incrementCounter(startupProgress, LOADING_EDITS, loadingEditsFile, 5000L);
Thread.sleep(50L); // brief sleep to fake elapsed time
StartupProgressView view = startupProgress.createView();
assertNotNull(view);
assertTrue(view.getElapsedTime() > 0);
assertTrue(view.getElapsedTime(LOADING_FSIMAGE) > 0);
assertTrue(view.getElapsedTime(LOADING_FSIMAGE,
loadingFsImageInodes) > 0);
assertTrue(view.getElapsedTime(LOADING_FSIMAGE,
loadingFsImageDelegationKeys) > 0);
assertTrue(view.getElapsedTime(LOADING_EDITS) > 0);
assertTrue(view.getElapsedTime(LOADING_EDITS, loadingEditsFile) > 0);
assertTrue(view.getElapsedTime(SAVING_CHECKPOINT) == 0);
assertTrue(view.getElapsedTime(SAVING_CHECKPOINT,
new Step(INODES)) == 0);
// Brief sleep, then check that completed phases/steps have the same elapsed
// time, but running phases/steps have updated elapsed time.
long totalTime = view.getElapsedTime();
long loadingFsImageTime = view.getElapsedTime(LOADING_FSIMAGE);
long loadingFsImageInodesTime = view.getElapsedTime(LOADING_FSIMAGE,
loadingFsImageInodes);
long loadingFsImageDelegationKeysTime = view.getElapsedTime(LOADING_FSIMAGE,
loadingFsImageInodes);
long loadingEditsTime = view.getElapsedTime(LOADING_EDITS);
long loadingEditsFileTime = view.getElapsedTime(LOADING_EDITS,
loadingEditsFile);
Thread.sleep(50L);
assertTrue(totalTime < view.getElapsedTime());
assertEquals(loadingFsImageTime, view.getElapsedTime(LOADING_FSIMAGE));
assertEquals(loadingFsImageInodesTime, view.getElapsedTime(LOADING_FSIMAGE,
loadingFsImageInodes));
assertTrue(loadingEditsTime < view.getElapsedTime(LOADING_EDITS));
assertTrue(loadingEditsFileTime < view.getElapsedTime(LOADING_EDITS,
loadingEditsFile));
}
@Test(timeout=10000)
public void testFrozenAfterStartupCompletes() {
// Do some updates and counter increments.
startupProgress.beginPhase(LOADING_FSIMAGE);
startupProgress.setFile(LOADING_FSIMAGE, "file1");
startupProgress.setSize(LOADING_FSIMAGE, 1000L);
Step step = new Step(INODES);
startupProgress.beginStep(LOADING_FSIMAGE, step);
startupProgress.setTotal(LOADING_FSIMAGE, step, 10000L);
incrementCounter(startupProgress, LOADING_FSIMAGE, step, 100L);
startupProgress.endStep(LOADING_FSIMAGE, step);
startupProgress.endPhase(LOADING_FSIMAGE);
StartupProgressView beforePhaseUpdate = startupProgress.createView();
// LOADING_FSIMAGE phase has been completed, but attempt more updates to it
Step fsimageStep2 = new Step(INODES);
startupProgress.beginStep(LOADING_FSIMAGE, fsimageStep2);
incrementCounter(startupProgress, LOADING_FSIMAGE, fsimageStep2, 1000000L);
startupProgress.endStep(LOADING_FSIMAGE, fsimageStep2);
// Force completion of phases, so that entire startup process is completed.
for (Phase phase: EnumSet.allOf(Phase.class)) {
if (startupProgress.getStatus(phase) != Status.COMPLETE) {
startupProgress.beginPhase(phase);
startupProgress.endPhase(phase);
}
}
StartupProgressView before = startupProgress.createView();
// Attempt more updates and counter increments.
startupProgress.beginPhase(LOADING_FSIMAGE);
startupProgress.setFile(LOADING_FSIMAGE, "file2");
startupProgress.setSize(LOADING_FSIMAGE, 2000L);
startupProgress.beginStep(LOADING_FSIMAGE, step);
startupProgress.setTotal(LOADING_FSIMAGE, step, 20000L);
incrementCounter(startupProgress, LOADING_FSIMAGE, step, 100L);
startupProgress.endStep(LOADING_FSIMAGE, step);
startupProgress.endPhase(LOADING_FSIMAGE);
// Also attempt a whole new step that wasn't used last time.
startupProgress.beginPhase(LOADING_EDITS);
Step newStep = new Step("file1");
startupProgress.beginStep(LOADING_EDITS, newStep);
incrementCounter(startupProgress, LOADING_EDITS, newStep, 100L);
startupProgress.endStep(LOADING_EDITS, newStep);
startupProgress.endPhase(LOADING_EDITS);
StartupProgressView after = startupProgress.createView();
// Expect that data was frozen after completion of entire startup process, so
// second set of updates and counter increments should have had no effect.
assertViewEquals(before, after, LOADING_FSIMAGE, step, fsimageStep2);
assertEquals(before.getElapsedTime(), after.getElapsedTime());
// After the phase was completed but before startup was completed,
// everything should be equal, except for the total elapsed time
assertViewEquals(beforePhaseUpdate, after, LOADING_FSIMAGE,
step, fsimageStep2);
assertFalse(after.getSteps(LOADING_EDITS).iterator().hasNext());
}
private void assertViewEquals(StartupProgressView view1,
StartupProgressView view2, Phase phaseToVerify, Step... stepsToVerify) {
assertEquals(view1.getCount(phaseToVerify),
view2.getCount(phaseToVerify));
assertEquals(view1.getElapsedTime(phaseToVerify),
view2.getElapsedTime(phaseToVerify));
assertEquals(view1.getFile(phaseToVerify),
view2.getFile(phaseToVerify));
assertEquals(view1.getSize(phaseToVerify),
view2.getSize(phaseToVerify));
assertEquals(view1.getTotal(phaseToVerify),
view2.getTotal(phaseToVerify));
for (Step step : stepsToVerify) {
assertEquals(view1.getCount(phaseToVerify, step),
view2.getCount(phaseToVerify, step));
assertEquals(view1.getElapsedTime(phaseToVerify, step),
view2.getElapsedTime(phaseToVerify, step));
assertEquals(view1.getTotal(phaseToVerify, step),
view2.getTotal(phaseToVerify, step));
}
}
@Test(timeout=10000)
public void testInitialState() {
StartupProgressView view = startupProgress.createView();
assertNotNull(view);
assertEquals(0L, view.getElapsedTime());
assertEquals(0.0f, view.getPercentComplete(), 0.001f);
List<Phase> phases = new ArrayList<Phase>();
for (Phase phase: view.getPhases()) {
phases.add(phase);
assertEquals(0L, view.getElapsedTime(phase));
assertNull(view.getFile(phase));
assertEquals(0.0f, view.getPercentComplete(phase), 0.001f);
assertEquals(Long.MIN_VALUE, view.getSize(phase));
assertEquals(PENDING, view.getStatus(phase));
assertEquals(0L, view.getTotal(phase));
for (Step step: view.getSteps(phase)) {
fail(String.format("unexpected step %s in phase %s at initial state",
step, phase));
}
}
assertArrayEquals(EnumSet.allOf(Phase.class).toArray(), phases.toArray());
}
@Test(timeout=10000)
public void testPercentComplete() {
startupProgress.beginPhase(LOADING_FSIMAGE);
Step loadingFsImageInodes = new Step(INODES);
startupProgress.beginStep(LOADING_FSIMAGE, loadingFsImageInodes);
startupProgress.setTotal(LOADING_FSIMAGE, loadingFsImageInodes, 1000L);
incrementCounter(startupProgress, LOADING_FSIMAGE, loadingFsImageInodes,
100L);
Step loadingFsImageDelegationKeys = new Step(DELEGATION_KEYS);
startupProgress.beginStep(LOADING_FSIMAGE, loadingFsImageDelegationKeys);
startupProgress.setTotal(LOADING_FSIMAGE, loadingFsImageDelegationKeys,
800L);
incrementCounter(startupProgress, LOADING_FSIMAGE,
loadingFsImageDelegationKeys, 200L);
startupProgress.beginPhase(LOADING_EDITS);
Step loadingEditsFile = new Step("file", 1000L);
startupProgress.beginStep(LOADING_EDITS, loadingEditsFile);
startupProgress.setTotal(LOADING_EDITS, loadingEditsFile, 10000L);
incrementCounter(startupProgress, LOADING_EDITS, loadingEditsFile, 5000L);
StartupProgressView view = startupProgress.createView();
assertNotNull(view);
assertEquals(0.167f, view.getPercentComplete(), 0.001f);
assertEquals(0.167f, view.getPercentComplete(LOADING_FSIMAGE), 0.001f);
assertEquals(0.10f, view.getPercentComplete(LOADING_FSIMAGE,
loadingFsImageInodes), 0.001f);
assertEquals(0.25f, view.getPercentComplete(LOADING_FSIMAGE,
loadingFsImageDelegationKeys), 0.001f);
assertEquals(0.5f, view.getPercentComplete(LOADING_EDITS), 0.001f);
assertEquals(0.5f, view.getPercentComplete(LOADING_EDITS, loadingEditsFile),
0.001f);
assertEquals(0.0f, view.getPercentComplete(SAVING_CHECKPOINT), 0.001f);
assertEquals(0.0f, view.getPercentComplete(SAVING_CHECKPOINT,
new Step(INODES)), 0.001f);
// End steps/phases, and confirm that they jump to 100% completion.
startupProgress.endStep(LOADING_FSIMAGE, loadingFsImageInodes);
startupProgress.endStep(LOADING_FSIMAGE, loadingFsImageDelegationKeys);
startupProgress.endPhase(LOADING_FSIMAGE);
startupProgress.endStep(LOADING_EDITS, loadingEditsFile);
startupProgress.endPhase(LOADING_EDITS);
view = startupProgress.createView();
assertNotNull(view);
assertEquals(0.5f, view.getPercentComplete(), 0.001f);
assertEquals(1.0f, view.getPercentComplete(LOADING_FSIMAGE), 0.001f);
assertEquals(1.0f, view.getPercentComplete(LOADING_FSIMAGE,
loadingFsImageInodes), 0.001f);
assertEquals(1.0f, view.getPercentComplete(LOADING_FSIMAGE,
loadingFsImageDelegationKeys), 0.001f);
assertEquals(1.0f, view.getPercentComplete(LOADING_EDITS), 0.001f);
assertEquals(1.0f, view.getPercentComplete(LOADING_EDITS, loadingEditsFile),
0.001f);
assertEquals(0.0f, view.getPercentComplete(SAVING_CHECKPOINT), 0.001f);
assertEquals(0.0f, view.getPercentComplete(SAVING_CHECKPOINT,
new Step(INODES)), 0.001f);
}
@Test(timeout=10000)
public void testStatus() {
startupProgress.beginPhase(LOADING_FSIMAGE);
startupProgress.endPhase(LOADING_FSIMAGE);
startupProgress.beginPhase(LOADING_EDITS);
StartupProgressView view = startupProgress.createView();
assertNotNull(view);
assertEquals(COMPLETE, view.getStatus(LOADING_FSIMAGE));
assertEquals(RUNNING, view.getStatus(LOADING_EDITS));
assertEquals(PENDING, view.getStatus(SAVING_CHECKPOINT));
}
@Test(timeout=10000)
public void testStepSequence() {
// Test that steps are returned in the correct sort order (by file and then
// sequence number) by starting a few steps in a randomly shuffled order and
// then asserting that they are returned in the expected order.
Step[] expectedSteps = new Step[] {
new Step(INODES, "file1"),
new Step(DELEGATION_KEYS, "file1"),
new Step(INODES, "file2"),
new Step(DELEGATION_KEYS, "file2"),
new Step(INODES, "file3"),
new Step(DELEGATION_KEYS, "file3")
};
List<Step> shuffledSteps = new ArrayList<Step>(Arrays.asList(expectedSteps));
Collections.shuffle(shuffledSteps);
startupProgress.beginPhase(SAVING_CHECKPOINT);
for (Step step: shuffledSteps) {
startupProgress.beginStep(SAVING_CHECKPOINT, step);
}
List<Step> actualSteps = new ArrayList<Step>(expectedSteps.length);
StartupProgressView view = startupProgress.createView();
assertNotNull(view);
for (Step step: view.getSteps(SAVING_CHECKPOINT)) {
actualSteps.add(step);
}
assertArrayEquals(expectedSteps, actualSteps.toArray());
}
@Test(timeout=10000)
public void testThreadSafety() throws Exception {
// Test for thread safety by starting multiple threads that mutate the same
// StartupProgress instance in various ways. We expect no internal
// corruption of data structures and no lost updates on counter increments.
int numThreads = 100;
// Data tables used by each thread to determine values to pass to APIs.
Phase[] phases = { LOADING_FSIMAGE, LOADING_FSIMAGE, LOADING_EDITS,
LOADING_EDITS };
Step[] steps = new Step[] { new Step(INODES), new Step(DELEGATION_KEYS),
new Step(INODES), new Step(DELEGATION_KEYS) };
String[] files = { "file1", "file1", "file2", "file2" };
long[] sizes = { 1000L, 1000L, 2000L, 2000L };
long[] totals = { 10000L, 20000L, 30000L, 40000L };
ExecutorService exec = Executors.newFixedThreadPool(numThreads);
try {
for (int i = 0; i < numThreads; ++i) {
final Phase phase = phases[i % phases.length];
final Step step = steps[i % steps.length];
final String file = files[i % files.length];
final long size = sizes[i % sizes.length];
final long total = totals[i % totals.length];
exec.submit(new Callable<Void>() {
@Override
public Void call() {
startupProgress.beginPhase(phase);
startupProgress.setFile(phase, file);
startupProgress.setSize(phase, size);
startupProgress.setTotal(phase, step, total);
incrementCounter(startupProgress, phase, step, 100L);
startupProgress.endStep(phase, step);
return null;
}
});
}
} finally {
exec.shutdown();
assertTrue(exec.awaitTermination(10000L, TimeUnit.MILLISECONDS));
}
// Once a phase ends, future modifications to the steps in that phase are
// ignored. Thus do not end the phases until after the other ops are done.
for (Phase phase : phases) {
startupProgress.endPhase(phase);
}
StartupProgressView view = startupProgress.createView();
assertNotNull(view);
assertEquals("file1", view.getFile(LOADING_FSIMAGE));
assertEquals(1000L, view.getSize(LOADING_FSIMAGE));
assertEquals(10000L, view.getTotal(LOADING_FSIMAGE, new Step(INODES)));
assertEquals(2500L, view.getCount(LOADING_FSIMAGE, new Step(INODES)));
assertEquals(20000L, view.getTotal(LOADING_FSIMAGE,
new Step(DELEGATION_KEYS)));
assertEquals(2500L, view.getCount(LOADING_FSIMAGE,
new Step(DELEGATION_KEYS)));
assertEquals("file2", view.getFile(LOADING_EDITS));
assertEquals(2000L, view.getSize(LOADING_EDITS));
assertEquals(30000L, view.getTotal(LOADING_EDITS, new Step(INODES)));
assertEquals(2500L, view.getCount(LOADING_EDITS, new Step(INODES)));
assertEquals(40000L, view.getTotal(LOADING_EDITS,
new Step(DELEGATION_KEYS)));
assertEquals(2500L, view.getCount(LOADING_EDITS, new Step(DELEGATION_KEYS)));
}
@Test(timeout=10000)
public void testTotal() {
startupProgress.beginPhase(LOADING_FSIMAGE);
Step loadingFsImageInodes = new Step(INODES);
startupProgress.beginStep(LOADING_FSIMAGE, loadingFsImageInodes);
startupProgress.setTotal(LOADING_FSIMAGE, loadingFsImageInodes, 1000L);
startupProgress.endStep(LOADING_FSIMAGE, loadingFsImageInodes);
Step loadingFsImageDelegationKeys = new Step(DELEGATION_KEYS);
startupProgress.beginStep(LOADING_FSIMAGE, loadingFsImageDelegationKeys);
startupProgress.setTotal(LOADING_FSIMAGE, loadingFsImageDelegationKeys,
800L);
startupProgress.endStep(LOADING_FSIMAGE, loadingFsImageDelegationKeys);
startupProgress.endPhase(LOADING_FSIMAGE);
startupProgress.beginPhase(LOADING_EDITS);
Step loadingEditsFile = new Step("file", 1000L);
startupProgress.beginStep(LOADING_EDITS, loadingEditsFile);
startupProgress.setTotal(LOADING_EDITS, loadingEditsFile, 10000L);
startupProgress.endStep(LOADING_EDITS, loadingEditsFile);
startupProgress.endPhase(LOADING_EDITS);
StartupProgressView view = startupProgress.createView();
assertNotNull(view);
assertEquals(1000L, view.getTotal(LOADING_FSIMAGE, loadingFsImageInodes));
assertEquals(800L, view.getTotal(LOADING_FSIMAGE,
loadingFsImageDelegationKeys));
assertEquals(10000L, view.getTotal(LOADING_EDITS, loadingEditsFile));
}
}