Index: src/test/java/org/apache/hadoop/hbase/master/TestClockSkewDetection.java =================================================================== --- src/test/java/org/apache/hadoop/hbase/master/TestClockSkewDetection.java (revision 0) +++ src/test/java/org/apache/hadoop/hbase/master/TestClockSkewDetection.java (revision 0) @@ -0,0 +1,87 @@ +/** + * Copyright 2010 The Apache Software Foundation + * + * 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.hbase.master; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.hbase.MiniHBaseCluster; +import org.apache.hadoop.hbase.HBaseTestingUtility; +import org.apache.hadoop.hbase.util.Bytes; +import org.apache.hadoop.conf.Configuration; + +import java.io.IOException; +import junit.framework.Assert; +import org.apache.hadoop.hbase.ClockOutOfSyncException; +import org.apache.hadoop.hbase.HServerAddress; +import org.apache.hadoop.hbase.HServerInfo; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + + + +public class TestClockSkewDetection { + private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility(); + private static final Log LOG = LogFactory.getLog(TestClockSkewDetection.class); + private static final byte[] TABLENAME = Bytes.toBytes("TestMaster"); + private static final byte[] FAMILYNAME = Bytes.toBytes("fam"); + + @BeforeClass + public static void beforeAllTests() throws Exception { + // Start a cluster of 1 regionservers. + TEST_UTIL.startMiniCluster(1); + } + + @AfterClass + public static void afterAllTests() throws IOException { + TEST_UTIL.shutdownMiniCluster(); + } + + @Test + public void testClockSkewDetection() throws Exception { + MiniHBaseCluster cluster = TEST_UTIL.getHBaseCluster(); + HMaster m = cluster.getMaster(); + + ServerManager sm = m.getServerManager(); + + //there should be no exception + LOG.debug("regionServerStartup 1"); + HServerInfo hsi1 = new HServerInfo(new HServerAddress("example.org:1234"), + System.currentTimeMillis(), -1, "example.com"); + sm.regionServerStartup(hsi1); + sm.expireServer(hsi1); + + Configuration c = TEST_UTIL.getConfiguration(); + long maxSkew = c.getInt("hbase.master.regionserver.maxClockSkewMS", 30000); + + try { + LOG.debug("regionServerStartup 2"); + HServerInfo hsi2 = new HServerInfo(new HServerAddress("example.org:1235"), + System.currentTimeMillis() - maxSkew * 2, -1, "example.com"); + sm.regionServerStartup(hsi2); + sm.expireServer(hsi2); + Assert.assertTrue("HMaster should have thrown an ClockOutOfSyncException but didn't.", false); + } catch(ClockOutOfSyncException e) { + //we want an exception + LOG.info("Recieved expected exception: "+e); + } + } +} \ No newline at end of file Index: src/main/java/org/apache/hadoop/hbase/master/ServerManager.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/master/ServerManager.java (revision 1029785) +++ src/main/java/org/apache/hadoop/hbase/master/ServerManager.java (working copy) @@ -32,6 +32,7 @@ import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.Chore; +import org.apache.hadoop.hbase.ClockOutOfSyncException; import org.apache.hadoop.hbase.HMsg; import org.apache.hadoop.hbase.HRegionInfo; import org.apache.hadoop.hbase.HServerAddress; @@ -161,6 +162,7 @@ HServerInfo info = new HServerInfo(serverInfo); checkIsDead(info.getServerName(), "STARTUP"); checkAlreadySameHostPort(info); + checkClockSkew(info); recordNewServer(info, false, null); } @@ -199,6 +201,26 @@ } /** + * Checks if the clock skew between the server and the master. If the clock + * skew is too much it will throw an Exception. + * @param + * @throws LeaseStillHeldException + */ + private void checkClockSkew(final HServerInfo serverInfo) + throws ClockOutOfSyncException { + Configuration c = master.getConfiguration(); + long skew = System.currentTimeMillis() - serverInfo.getStartCode(); + long maxSkew = c.getInt("hbase.master.regionserver.maxClockSkewMS", 30000); + if (skew > maxSkew) + { + String message = "Server " + serverInfo.getServerName() + " rejected; Server system time is " + + "too far out of sync with master. Time difference: "+skew+"ms > "+maxSkew+"ms"; + LOG.debug(message); + throw new ClockOutOfSyncException(message); + } + } + + /** * If this server is on the dead list, reject it with a LeaseStillHeldException * @param serverName Server name formatted as host_port_startcode. * @param what START or REPORT Index: src/main/java/org/apache/hadoop/hbase/ClockOutOfSyncException.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/ClockOutOfSyncException.java (revision 0) +++ src/main/java/org/apache/hadoop/hbase/ClockOutOfSyncException.java (revision 0) @@ -0,0 +1,33 @@ +/** + * Copyright 2010 The Apache Software Foundation + * + * 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.hbase; + +import java.io.IOException; + +/** + * This exception is thrown by the master when a region server clock skew is + * too high. + */ +@SuppressWarnings("serial") +public class ClockOutOfSyncException extends IOException { + public ClockOutOfSyncException(String message) { + super(message); + } +} \ No newline at end of file