/**
* 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.notifier.server;
import java.util.Date;
import java.util.LinkedList;
import java.util.Queue;
import junit.framework.Assert;
import org.apache.commons.logging.impl.Log4JLogger;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hdfs.MiniDFSCluster;
import org.apache.hadoop.hdfs.notifier.ClientHandlerImpl;
import org.apache.hadoop.hdfs.notifier.EventType;
import org.apache.hadoop.hdfs.notifier.NamespaceEvent;
import org.apache.hadoop.hdfs.notifier.NamespaceNotification;
import org.apache.hadoop.hdfs.notifier.TransactionIdTooOldException;
import org.apache.log4j.Level;
import org.junit.BeforeClass;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TestServerHistory {
static private Logger LOG = LoggerFactory.getLogger(TestServerHistory.class);
static Configuration conf;
{
((Log4JLogger)ServerLogReaderTransactional.LOG).getLogger().setLevel(Level.ALL);
((Log4JLogger)ClientHandlerImpl.LOG).getLogger().setLevel(Level.ALL);
((Log4JLogger)ServerHistory.LOG).getLogger().setLevel(Level.ALL);
}
@BeforeClass
public static void initConf() {
conf = NotifierTestUtil.initGenericConf();
}
/**
* Check that the ramp up phase runs for the (at least) configured
* amount of time.
* @throws Exception
*/
@Test
public void testRampUp() throws Exception {
DummyServerCore core = new DummyServerCore();
ServerHistory history = new ServerHistory(core, true);
long initialTime = new Date().getTime();
long historyLength = 100;
history.setHistoryLength(historyLength);
new Thread(history).start();
while (history.isRampUp())
Thread.sleep(1);
core.shutdown();
Assert.assertTrue(System.currentTimeMillis() - initialTime > historyLength);
}
@Test
public void testBasicQueueNotification() throws Exception {
// Starting without a ramp-up phase
DummyServerCore core = new DummyServerCore();
ServerHistory history = new ServerHistory(core, false);
long historyLength = 100;
history.setHistoryLength(historyLength);
Queue<NamespaceNotification> historyNotifications;
new Thread(history).start();
// Step 1 - test with FILE_ADDED
history.storeNotification(new NamespaceNotification("/a/b",
EventType.FILE_ADDED.getByteValue(), 10));
history.storeNotification(new NamespaceNotification("/a/c",
EventType.FILE_ADDED.getByteValue(), 11));
historyNotifications = new LinkedList<NamespaceNotification>();
history.addNotificationsToQueue(new NamespaceEvent("/a",
EventType.FILE_ADDED.getByteValue()), 10, historyNotifications);
Assert.assertEquals(1, historyNotifications.size());
Assert.assertEquals(11, historyNotifications.peek().txId);
Assert.assertEquals("/a/c", historyNotifications.peek().path);
// Step 2 - test with FILE_CLOSED
history.storeNotification(new NamespaceNotification("/a/d",
EventType.FILE_CLOSED.getByteValue(), 12));
history.storeNotification(new NamespaceNotification("/a/e",
EventType.FILE_CLOSED.getByteValue(), 13));
historyNotifications = new LinkedList<NamespaceNotification>();
history.addNotificationsToQueue(new NamespaceEvent("/a",
EventType.FILE_CLOSED.getByteValue()), 12, historyNotifications);
Assert.assertEquals(1, historyNotifications.size());
Assert.assertEquals(13, historyNotifications.peek().txId);
Assert.assertEquals("/a/e", historyNotifications.peek().path);
// test the sub directories
historyNotifications = new LinkedList<NamespaceNotification>();
history.addNotificationsToQueue(new NamespaceEvent("/",
EventType.FILE_ADDED.getByteValue()), 10, historyNotifications);
Assert.assertEquals(1, historyNotifications.size());
history.addNotificationsToQueue(new NamespaceEvent("/",
EventType.FILE_CLOSED.getByteValue()), 10, historyNotifications);
Assert.assertEquals(3, historyNotifications.size());
core.shutdown();
}
@Test
public void testTransactionIdTooOldDoesentHappen() throws Exception {
// Starting without a ramp-up phase
DummyServerCore core = new DummyServerCore();
ServerHistory history = new ServerHistory(core, false);
long historyLength = 350;
history.setHistoryLength(historyLength);
Queue<NamespaceNotification> historyNotifications;
new Thread(history).start();
// Step 1 - test with FILE_ADDED
history.storeNotification(new NamespaceNotification("/a/b",
EventType.FILE_ADDED.getByteValue(), 10));
history.storeNotification(new NamespaceNotification("/a/c",
EventType.FILE_ADDED.getByteValue(), 11));
historyNotifications = new LinkedList<NamespaceNotification>();
try {
Thread.sleep(historyLength - 30);
history.addNotificationsToQueue(new NamespaceEvent("/a",
EventType.FILE_ADDED.getByteValue()), 10, historyNotifications);
} catch (TransactionIdTooOldException e) {
Assert.fail();
}
core.shutdown();
}
@Test
public void testTransactionIdTooOldDoesHappen() throws Exception {
// Starting without a ramp-up phase
DummyServerCore core = new DummyServerCore();
ServerHistory history = new ServerHistory(core, false);
long historyLength = 100;
history.setHistoryLength(historyLength);
Queue<NamespaceNotification> historyNotifications;
history.loopSleepTime = 10;
new Thread(history).start();
// Step 1 - test with FILE_ADDED
history.storeNotification(new NamespaceNotification("/a/b",
EventType.FILE_ADDED.getByteValue(), 10));
history.storeNotification(new NamespaceNotification("/a/c",
EventType.FILE_ADDED.getByteValue(), 11));
historyNotifications = new LinkedList<NamespaceNotification>();
try {
Thread.sleep(historyLength + 50);
history.addNotificationsToQueue(new NamespaceEvent("/a",
EventType.FILE_ADDED.getByteValue()), 10, historyNotifications);
Assert.fail(); // should receive the exception
} catch (TransactionIdTooOldException e) {}
core.shutdown();
}
@Test
public void testHistoryMemoryCleanup1() throws Exception {
// Starting without a ramp-up phase
DummyServerCore core = new DummyServerCore();
ServerHistory history = new ServerHistory(core, false);
long historyLength = 100;
history.setHistoryLength(historyLength);
history.loopSleepTime = 10;
new Thread(history).start();
history.storeNotification(new NamespaceNotification("/a/b",
EventType.FILE_ADDED.getByteValue(), 10));
history.storeNotification(new NamespaceNotification("/a/c",
EventType.FILE_ADDED.getByteValue(), 11));
Thread.sleep(historyLength + 50);
Assert.assertEquals(0, history.orderedHistoryList.size());
Assert.assertEquals(0, history.historyTree.children.size());
core.shutdown();
}
@Test
public void testHistoryMemoryCleanup2() throws Exception {
// Starting without a ramp-up phase
DummyServerCore core = new DummyServerCore();
ServerHistory history = new ServerHistory(core, false);
long historyLength = 10000;
history.setHistoryLength(historyLength);
history.setHistoryLimit(1000);
history.loopSleepTime = 10;
Thread historyThread = new Thread(history);
historyThread.start();
for (int i = 0; i < 1500; i ++) {
history.storeNotification(new NamespaceNotification("/a/b" + i,
EventType.FILE_ADDED.getByteValue(), i));
}
Thread.sleep(500);
core.shutdown();
historyThread.join();
Assert.assertEquals(1000, history.orderedHistoryList.size());
}
@Test
public void testQueueNotificationAdvanced() throws Exception {
// Starting without a ramp-up phase
DummyServerCore core = new DummyServerCore();
ServerHistory history = new ServerHistory(core, false);
long historyLength = 10000;
history.setHistoryLength(historyLength);
Queue<NamespaceNotification> historyNotifications;
long txCount = 1001;
new Thread(history).start();
for (long txId = 0; txId < txCount; txId ++) {
history.storeNotification(new NamespaceNotification("/a/" + txId,
EventType.FILE_ADDED.getByteValue(), txId));
}
// Part 1 - Get all notifications
historyNotifications = new LinkedList<NamespaceNotification>();
history.addNotificationsToQueue(new NamespaceEvent("/a",
EventType.FILE_ADDED.getByteValue()), 0, historyNotifications);
Assert.assertEquals(1000, historyNotifications.size());
for (long txId = 1; txId < txCount; txId ++) {
NamespaceNotification n = historyNotifications.poll();
Assert.assertEquals(txId, n.txId);
Assert.assertEquals("/a/" + txId, n.path);
Assert.assertEquals(EventType.FILE_ADDED.getByteValue(), n.type);
}
// Part 2 - Get half of the notifications
historyNotifications = new LinkedList<NamespaceNotification>();
history.addNotificationsToQueue(new NamespaceEvent("/a",
EventType.FILE_ADDED.getByteValue()), 500, historyNotifications);
Assert.assertEquals(500, historyNotifications.size());
for (long txId = 501; txId < txCount; txId ++) {
NamespaceNotification n = historyNotifications.poll();
Assert.assertEquals(txId, n.txId);
Assert.assertEquals("/a/" + txId, n.path);
Assert.assertEquals(EventType.FILE_ADDED.getByteValue(), n.type);
}
core.shutdown();
}
class DummyServerCore extends EmptyServerCore {
@Override
public Configuration getConfiguration() {
return conf;
}
}
}