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.jupiter.api.Assertions.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.HBaseTestingUtil; 028import org.apache.hadoop.hbase.HConstants; 029import org.apache.hadoop.hbase.KeyValue; 030import org.apache.hadoop.hbase.TableName; 031import org.apache.hadoop.hbase.client.RegionInfo; 032import org.apache.hadoop.hbase.client.RegionInfoBuilder; 033import org.apache.hadoop.hbase.regionserver.MultiVersionConcurrencyControl; 034import org.apache.hadoop.hbase.testclassification.RegionServerTests; 035import org.apache.hadoop.hbase.testclassification.SmallTests; 036import org.apache.hadoop.hbase.util.Bytes; 037import org.apache.hadoop.hbase.util.CommonFSUtils; 038import org.apache.hadoop.hbase.wal.WAL; 039import org.apache.hadoop.hbase.wal.WALEdit; 040import org.apache.hadoop.hbase.wal.WALEditInternalHelper; 041import org.apache.hadoop.hbase.wal.WALFactory; 042import org.apache.hadoop.hbase.wal.WALKeyImpl; 043import org.junit.jupiter.api.AfterEach; 044import org.junit.jupiter.api.BeforeAll; 045import org.junit.jupiter.api.BeforeEach; 046import org.junit.jupiter.api.Tag; 047import org.junit.jupiter.api.Test; 048 049/** 050 * Test that the actions are called while playing with an WAL 051 */ 052@Tag(RegionServerTests.TAG) 053@Tag(SmallTests.TAG) 054public class TestWALActionsListener { 055 056 private final static HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil(); 057 058 private final static byte[] SOME_BYTES = Bytes.toBytes("t"); 059 private static Configuration conf; 060 private static Path rootDir; 061 private static Path walRootDir; 062 private static FileSystem fs; 063 private static FileSystem logFs; 064 065 @BeforeAll 066 public static void setUpBeforeClass() throws Exception { 067 conf = TEST_UTIL.getConfiguration(); 068 conf.setInt("hbase.regionserver.maxlogs", 5); 069 rootDir = TEST_UTIL.createRootDir(); 070 walRootDir = TEST_UTIL.createWALRootDir(); 071 fs = CommonFSUtils.getRootDirFileSystem(conf); 072 logFs = CommonFSUtils.getWALFileSystem(conf); 073 } 074 075 @BeforeEach 076 public void setUp() throws Exception { 077 fs.delete(rootDir, true); 078 logFs.delete(new Path(walRootDir, HConstants.HREGION_LOGDIR_NAME), true); 079 logFs.delete(new Path(walRootDir, HConstants.HREGION_OLDLOGDIR_NAME), true); 080 } 081 082 @AfterEach 083 public void tearDown() throws Exception { 084 setUp(); 085 } 086 087 /** 088 * Add a bunch of dummy data and roll the logs every two insert. We should end up with 10 rolled 089 * files (plus the roll called in the constructor). Also test adding a listener while it's 090 * running. 091 */ 092 @Test 093 public void testActionListener() throws Exception { 094 DummyWALActionsListener observer = new DummyWALActionsListener(); 095 final WALFactory wals = new WALFactory(conf, "testActionListener"); 096 wals.getWALProvider().addWALActionsListener(observer); 097 DummyWALActionsListener laterobserver = new DummyWALActionsListener(); 098 RegionInfo hri = RegionInfoBuilder.newBuilder(TableName.valueOf(SOME_BYTES)) 099 .setStartKey(SOME_BYTES).setEndKey(SOME_BYTES).build(); 100 final WAL wal = wals.getWAL(hri); 101 MultiVersionConcurrencyControl mvcc = new MultiVersionConcurrencyControl(); 102 for (int i = 0; i < 20; i++) { 103 byte[] b = Bytes.toBytes(i + ""); 104 KeyValue kv = new KeyValue(b, b, b); 105 WALEdit edit = new WALEdit(); 106 WALEditInternalHelper.addExtendedCell(edit, kv); 107 NavigableMap<byte[], Integer> scopes = new TreeMap<>(Bytes.BYTES_COMPARATOR); 108 scopes.put(b, 0); 109 long txid = wal.appendData(hri, 110 new WALKeyImpl(hri.getEncodedNameAsBytes(), TableName.valueOf(b), 0, mvcc, scopes), edit); 111 wal.sync(txid); 112 if (i == 10) { 113 wal.registerWALActionsListener(laterobserver); 114 } 115 if (i % 2 == 0) { 116 wal.rollWriter(); 117 } 118 } 119 120 wal.close(); 121 122 assertEquals(11, observer.preLogRollCounter); 123 assertEquals(11, observer.postLogRollCounter); 124 assertEquals(5, laterobserver.preLogRollCounter); 125 assertEquals(5, laterobserver.postLogRollCounter); 126 assertEquals(1, observer.closedCount); 127 } 128 129 /** 130 * Just counts when methods are called 131 */ 132 public static class DummyWALActionsListener implements WALActionsListener { 133 public int preLogRollCounter = 0; 134 public int postLogRollCounter = 0; 135 public int closedCount = 0; 136 137 @Override 138 public void preLogRoll(Path oldFile, Path newFile) { 139 preLogRollCounter++; 140 } 141 142 @Override 143 public void postLogRoll(Path oldFile, Path newFile) { 144 postLogRollCounter++; 145 } 146 147 @Override 148 public void logCloseRequested() { 149 closedCount++; 150 } 151 } 152 153}