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.HBaseTestingUtil; 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 HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil(); 061 062 private final static byte[] SOME_BYTES = Bytes.toBytes("t"); 063 private static Configuration conf; 064 private static Path rootDir; 065 private static Path walRootDir; 066 private static FileSystem fs; 067 private static FileSystem logFs; 068 069 @BeforeClass 070 public static void setUpBeforeClass() throws Exception { 071 conf = TEST_UTIL.getConfiguration(); 072 conf.setInt("hbase.regionserver.maxlogs", 5); 073 rootDir = TEST_UTIL.createRootDir(); 074 walRootDir = TEST_UTIL.createWALRootDir(); 075 fs = CommonFSUtils.getRootDirFileSystem(conf); 076 logFs = CommonFSUtils.getWALFileSystem(conf); 077 } 078 079 @Before 080 public void setUp() throws Exception { 081 fs.delete(rootDir, true); 082 logFs.delete(new Path(walRootDir, HConstants.HREGION_LOGDIR_NAME), true); 083 logFs.delete(new Path(walRootDir, HConstants.HREGION_OLDLOGDIR_NAME), true); 084 } 085 086 @After 087 public void tearDown() throws Exception { 088 setUp(); 089 } 090 091 /** 092 * Add a bunch of dummy data and roll the logs every two insert. We should end up with 10 rolled 093 * files (plus the roll called in the constructor). Also test adding a listener while it's 094 * running. 095 */ 096 @Test 097 public void testActionListener() throws Exception { 098 DummyWALActionsListener observer = new DummyWALActionsListener(); 099 final WALFactory wals = new WALFactory(conf, "testActionListener"); 100 wals.getWALProvider().addWALActionsListener(observer); 101 DummyWALActionsListener laterobserver = new DummyWALActionsListener(); 102 RegionInfo hri = RegionInfoBuilder.newBuilder(TableName.valueOf(SOME_BYTES)) 103 .setStartKey(SOME_BYTES).setEndKey(SOME_BYTES).build(); 104 final WAL wal = wals.getWAL(hri); 105 MultiVersionConcurrencyControl mvcc = new MultiVersionConcurrencyControl(); 106 for (int i = 0; i < 20; i++) { 107 byte[] b = Bytes.toBytes(i + ""); 108 KeyValue kv = new KeyValue(b, b, b); 109 WALEdit edit = new WALEdit(); 110 edit.add(kv); 111 NavigableMap<byte[], Integer> scopes = new TreeMap<>(Bytes.BYTES_COMPARATOR); 112 scopes.put(b, 0); 113 long txid = wal.appendData(hri, 114 new WALKeyImpl(hri.getEncodedNameAsBytes(), TableName.valueOf(b), 0, mvcc, scopes), edit); 115 wal.sync(txid); 116 if (i == 10) { 117 wal.registerWALActionsListener(laterobserver); 118 } 119 if (i % 2 == 0) { 120 wal.rollWriter(); 121 } 122 } 123 124 wal.close(); 125 126 assertEquals(11, observer.preLogRollCounter); 127 assertEquals(11, observer.postLogRollCounter); 128 assertEquals(5, laterobserver.preLogRollCounter); 129 assertEquals(5, laterobserver.postLogRollCounter); 130 assertEquals(1, observer.closedCount); 131 } 132 133 /** 134 * Just counts when methods are called 135 */ 136 public static class DummyWALActionsListener implements WALActionsListener { 137 public int preLogRollCounter = 0; 138 public int postLogRollCounter = 0; 139 public int closedCount = 0; 140 141 @Override 142 public void preLogRoll(Path oldFile, Path newFile) { 143 preLogRollCounter++; 144 } 145 146 @Override 147 public void postLogRoll(Path oldFile, Path newFile) { 148 postLogRollCounter++; 149 } 150 151 @Override 152 public void logCloseRequested() { 153 closedCount++; 154 } 155 } 156 157}