001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.regionserver.wal; 019 020import static org.junit.Assert.assertEquals; 021 022import java.util.NavigableMap; 023import java.util.TreeMap; 024import org.apache.hadoop.conf.Configuration; 025import org.apache.hadoop.fs.FileSystem; 026import org.apache.hadoop.fs.Path; 027import org.apache.hadoop.hbase.HBaseClassTestRule; 028import org.apache.hadoop.hbase.HBaseTestingUtility; 029import org.apache.hadoop.hbase.HConstants; 030import org.apache.hadoop.hbase.KeyValue; 031import org.apache.hadoop.hbase.TableName; 032import org.apache.hadoop.hbase.client.RegionInfo; 033import org.apache.hadoop.hbase.client.RegionInfoBuilder; 034import org.apache.hadoop.hbase.regionserver.MultiVersionConcurrencyControl; 035import org.apache.hadoop.hbase.testclassification.RegionServerTests; 036import org.apache.hadoop.hbase.testclassification.SmallTests; 037import org.apache.hadoop.hbase.util.Bytes; 038import org.apache.hadoop.hbase.util.CommonFSUtils; 039import org.apache.hadoop.hbase.wal.WAL; 040import org.apache.hadoop.hbase.wal.WALEdit; 041import org.apache.hadoop.hbase.wal.WALFactory; 042import org.apache.hadoop.hbase.wal.WALKeyImpl; 043import org.junit.After; 044import org.junit.Before; 045import org.junit.BeforeClass; 046import org.junit.ClassRule; 047import org.junit.Test; 048import org.junit.experimental.categories.Category; 049 050/** 051 * Test that the actions are called while playing with an WAL 052 */ 053@Category({RegionServerTests.class, SmallTests.class}) 054public class TestWALActionsListener { 055 056 @ClassRule 057 public static final HBaseClassTestRule CLASS_RULE = 058 HBaseClassTestRule.forClass(TestWALActionsListener.class); 059 060 private final static HBaseTestingUtility TEST_UTIL = 061 new HBaseTestingUtility(); 062 063 private final static byte[] SOME_BYTES = Bytes.toBytes("t"); 064 private static Configuration conf; 065 private static Path rootDir; 066 private static Path walRootDir; 067 private static FileSystem fs; 068 private static FileSystem logFs; 069 070 @BeforeClass 071 public static void setUpBeforeClass() throws Exception { 072 conf = TEST_UTIL.getConfiguration(); 073 conf.setInt("hbase.regionserver.maxlogs", 5); 074 rootDir = TEST_UTIL.createRootDir(); 075 walRootDir = TEST_UTIL.createWALRootDir(); 076 fs = CommonFSUtils.getRootDirFileSystem(conf); 077 logFs = CommonFSUtils.getWALFileSystem(conf); 078 } 079 080 @Before 081 public void setUp() throws Exception { 082 fs.delete(rootDir, true); 083 logFs.delete(new Path(walRootDir, HConstants.HREGION_LOGDIR_NAME), true); 084 logFs.delete(new Path(walRootDir, HConstants.HREGION_OLDLOGDIR_NAME), true); 085 } 086 087 @After 088 public void tearDown() throws Exception { 089 setUp(); 090 } 091 092 /** 093 * Add a bunch of dummy data and roll the logs every two insert. We 094 * should end up with 10 rolled files (plus the roll called in 095 * the constructor). Also test adding a listener while it's running. 096 */ 097 @Test 098 public void testActionListener() throws Exception { 099 DummyWALActionsListener observer = new DummyWALActionsListener(); 100 final WALFactory wals = new WALFactory(conf, "testActionListener"); 101 wals.getWALProvider().addWALActionsListener(observer); 102 DummyWALActionsListener laterobserver = new DummyWALActionsListener(); 103 RegionInfo hri = RegionInfoBuilder.newBuilder(TableName.valueOf(SOME_BYTES)) 104 .setStartKey(SOME_BYTES).setEndKey(SOME_BYTES).build(); 105 final WAL wal = wals.getWAL(hri); 106 MultiVersionConcurrencyControl mvcc = new MultiVersionConcurrencyControl(); 107 for (int i = 0; i < 20; i++) { 108 byte[] b = Bytes.toBytes(i + ""); 109 KeyValue kv = new KeyValue(b, b, b); 110 WALEdit edit = new WALEdit(); 111 edit.add(kv); 112 NavigableMap<byte[], Integer> scopes = new TreeMap<>(Bytes.BYTES_COMPARATOR); 113 scopes.put(b, 0); 114 long txid = wal.appendData(hri, 115 new WALKeyImpl(hri.getEncodedNameAsBytes(), TableName.valueOf(b), 0, mvcc, scopes), edit); 116 wal.sync(txid); 117 if (i == 10) { 118 wal.registerWALActionsListener(laterobserver); 119 } 120 if (i % 2 == 0) { 121 wal.rollWriter(); 122 } 123 } 124 125 wal.close(); 126 127 assertEquals(11, observer.preLogRollCounter); 128 assertEquals(11, observer.postLogRollCounter); 129 assertEquals(5, laterobserver.preLogRollCounter); 130 assertEquals(5, laterobserver.postLogRollCounter); 131 assertEquals(1, observer.closedCount); 132 } 133 134 135 /** 136 * Just counts when methods are called 137 */ 138 public static class DummyWALActionsListener implements WALActionsListener { 139 public int preLogRollCounter = 0; 140 public int postLogRollCounter = 0; 141 public int closedCount = 0; 142 143 @Override 144 public void preLogRoll(Path oldFile, Path newFile) { 145 preLogRollCounter++; 146 } 147 148 @Override 149 public void postLogRoll(Path oldFile, Path newFile) { 150 postLogRollCounter++; 151 } 152 153 @Override 154 public void logCloseRequested() { 155 closedCount++; 156 } 157 } 158 159} 160