View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.regionserver.wal;
19  
20  import static org.junit.Assert.assertTrue;
21  import static org.junit.Assert.assertFalse;
22  
23  import java.util.List;
24  import java.util.ArrayList;
25  
26  import org.apache.commons.logging.Log;
27  import org.apache.commons.logging.LogFactory;
28  import org.apache.hadoop.fs.Path;
29  import org.apache.hadoop.hbase.HBaseTestingUtility;
30  import org.apache.hadoop.hbase.HColumnDescriptor;
31  import org.apache.hadoop.hbase.HRegionInfo;
32  import org.apache.hadoop.hbase.HTableDescriptor;
33  import org.apache.hadoop.hbase.MediumTests;
34  import org.apache.hadoop.hbase.TableName;
35  import org.apache.hadoop.hbase.client.HTable;
36  import org.apache.hadoop.hbase.client.Put;
37  import org.apache.hadoop.hbase.regionserver.HRegionServer;
38  import org.apache.hadoop.hbase.regionserver.wal.HLog;
39  import org.apache.hadoop.hbase.util.Bytes;
40  import org.apache.hadoop.hbase.util.FSUtils;
41  import org.apache.hadoop.hdfs.MiniDFSCluster;
42  import org.junit.AfterClass;
43  import org.junit.BeforeClass;
44  import org.junit.Test;
45  import org.junit.experimental.categories.Category;
46  
47  /**
48   * Tests that verifies that the log is forced to be rolled every "hbase.regionserver.logroll.period"
49   */
50  @Category(MediumTests.class)
51  public class TestLogRollPeriod {
52    private static final Log LOG = LogFactory.getLog(TestLogRolling.class);
53  
54    private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
55  
56    private final static long LOG_ROLL_PERIOD = 4000;
57  
58    @BeforeClass
59    public static void setUpBeforeClass() throws Exception {
60      // disable the ui
61      TEST_UTIL.getConfiguration().setInt("hbase.regionsever.info.port", -1);
62  
63      TEST_UTIL.getConfiguration().setLong("hbase.regionserver.logroll.period", LOG_ROLL_PERIOD);
64  
65      TEST_UTIL.startMiniCluster();
66    }
67  
68    @AfterClass
69    public static void tearDownAfterClass() throws Exception {
70      TEST_UTIL.shutdownMiniCluster();
71    }
72  
73    /**
74     * Tests that the LogRoller perform the roll even if there are no edits
75     */
76    @Test
77    public void testNoEdits() throws Exception {
78      final String tableName = "TestLogRollPeriodNoEdits";
79  
80      TEST_UTIL.createTable(tableName, "cf");
81      try {
82        HTable table = new HTable(TEST_UTIL.getConfiguration(), tableName);
83        try {
84          HRegionServer server = TEST_UTIL.getRSForFirstRegionInTable(Bytes.toBytes(tableName));
85          HLog log = server.getWAL();
86          checkMinLogRolls(log, 5);
87        } finally {
88          table.close();
89        }
90      } finally {
91        TEST_UTIL.deleteTable(tableName);
92      }
93    }
94  
95    /**
96     * Tests that the LogRoller perform the roll with some data in the log
97     */
98    @Test(timeout=60000)
99    public void testWithEdits() throws Exception {
100     final String tableName = "TestLogRollPeriodWithEdits";
101     final String family = "cf";
102 
103     TEST_UTIL.createTable(tableName, family);
104     try {
105       HRegionServer server = TEST_UTIL.getRSForFirstRegionInTable(Bytes.toBytes(tableName));
106       HLog log = server.getWAL();
107       final HTable table = new HTable(TEST_UTIL.getConfiguration(), tableName);
108 
109       Thread writerThread = new Thread("writer") {
110         @Override
111         public void run() {
112           try {
113             long row = 0;
114             while (!interrupted()) {
115               Put p = new Put(Bytes.toBytes(String.format("row%d", row)));
116               p.add(Bytes.toBytes(family), Bytes.toBytes("col"), Bytes.toBytes(row));
117               table.put(p);
118               row++;
119 
120               Thread.sleep(LOG_ROLL_PERIOD / 16);
121             }
122           } catch (Exception e) {
123             LOG.warn(e);
124           } 
125         }
126       };
127 
128       try {
129         writerThread.start();
130         checkMinLogRolls(log, 5);
131       } finally {
132         writerThread.interrupt();
133         writerThread.join();
134         table.close();
135       }  
136     } finally {
137       TEST_UTIL.deleteTable(tableName);
138     }
139   }
140 
141   private void checkMinLogRolls(final HLog log, final int minRolls)
142       throws Exception {
143     final List<Path> paths = new ArrayList<Path>();
144     log.registerWALActionsListener(new WALActionsListener() {
145       @Override
146       public void preLogRoll(Path oldFile, Path newFile)  {}
147       @Override
148       public void postLogRoll(Path oldFile, Path newFile) {
149         LOG.debug("postLogRoll: oldFile="+oldFile+" newFile="+newFile);
150         paths.add(newFile);
151       }
152       @Override
153       public void preLogArchive(Path oldFile, Path newFile) {}
154       @Override
155       public void postLogArchive(Path oldFile, Path newFile) {}
156       @Override
157       public void logRollRequested() {}
158       @Override
159       public void logCloseRequested() {}
160       @Override
161       public void visitLogEntryBeforeWrite(HRegionInfo info, HLogKey logKey, WALEdit logEdit) {}
162       @Override
163       public void visitLogEntryBeforeWrite(HTableDescriptor htd, HLogKey logKey, WALEdit logEdit) {}
164     });
165 
166     // Sleep until we should get at least min-LogRoll events
167     long wtime = System.currentTimeMillis();
168     Thread.sleep((minRolls + 1) * LOG_ROLL_PERIOD);
169     // Do some extra sleep in case the machine is slow,
170     // and the log-roll is not triggered exactly on LOG_ROLL_PERIOD.
171     final int NUM_RETRIES = 1 + 8 * (minRolls - paths.size());
172     for (int retry = 0; paths.size() < minRolls && retry < NUM_RETRIES; ++retry) {
173       Thread.sleep(LOG_ROLL_PERIOD / 4);
174     }
175     wtime = System.currentTimeMillis() - wtime;
176     LOG.info(String.format("got %d rolls after %dms (%dms each) - expected at least %d rolls",
177                            paths.size(), wtime, wtime / paths.size(), minRolls));
178     assertFalse(paths.size() < minRolls);
179   }
180 }