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.wal; 019 020import static org.junit.jupiter.api.Assertions.assertEquals; 021import static org.junit.jupiter.api.Assertions.assertNotNull; 022import static org.junit.jupiter.api.Assertions.assertNotSame; 023import static org.junit.jupiter.api.Assertions.assertNull; 024import static org.junit.jupiter.api.Assertions.assertThrows; 025import static org.junit.jupiter.api.Assertions.assertTrue; 026 027import java.io.IOException; 028import java.util.NavigableSet; 029import org.apache.hadoop.conf.Configuration; 030import org.apache.hadoop.fs.FSDataOutputStream; 031import org.apache.hadoop.fs.FileSystem; 032import org.apache.hadoop.fs.Path; 033import org.apache.hadoop.hbase.HBaseTestingUtil; 034import org.apache.hadoop.hbase.HConstants; 035import org.apache.hadoop.hbase.KeyValueTestUtil; 036import org.apache.hadoop.hbase.ServerName; 037import org.apache.hadoop.hbase.TableName; 038import org.apache.hadoop.hbase.testclassification.RegionServerTests; 039import org.apache.hadoop.hbase.testclassification.SmallTests; 040import org.apache.hadoop.hbase.util.Bytes; 041import org.apache.hadoop.hbase.util.CommonFSUtils; 042import org.apache.hadoop.hbase.util.EnvironmentEdgeManager; 043import org.apache.hadoop.hbase.wal.WALSplitter.PipelineController; 044import org.junit.jupiter.api.Tag; 045import org.junit.jupiter.api.Test; 046 047/** 048 * Simple testing of a few WAL methods. 049 */ 050@Tag(RegionServerTests.TAG) 051@Tag(SmallTests.TAG) 052public class TestWALMethods { 053 054 private static final byte[] TEST_REGION = Bytes.toBytes("test_region"); 055 private static final TableName TEST_TABLE = TableName.valueOf("test_table"); 056 057 private final HBaseTestingUtil util = new HBaseTestingUtil(); 058 059 @Test 060 public void testServerNameFromWAL() throws Exception { 061 Path walPath = new Path("/hbase/WALs/regionserver-2.example.com,22101,1487767381290", 062 "regionserver-2.example.com%2C22101%2C1487767381290.null0.1487785392316"); 063 ServerName name = AbstractFSWALProvider.getServerNameFromWALDirectoryName(walPath); 064 assertEquals(ServerName.valueOf("regionserver-2.example.com", 22101, 1487767381290L), name); 065 } 066 067 @Test 068 public void testServerNameFromTestWAL() throws Exception { 069 Path walPath = new Path( 070 "/user/example/test-data/12ff1404-68c6-4715-a4b9-775e763842bc/WALs/TestWALRecordReader", 071 "TestWALRecordReader.default.1487787939118"); 072 ServerName name = AbstractFSWALProvider.getServerNameFromWALDirectoryName(walPath); 073 assertNull(name); 074 } 075 076 /** 077 * Assert that getSplitEditFilesSorted returns files in expected order and that it skips 078 * moved-aside files. 079 */ 080 @Test 081 public void testGetSplitEditFilesSorted() throws IOException { 082 FileSystem fs = FileSystem.get(util.getConfiguration()); 083 Path regiondir = util.getDataTestDir("regiondir"); 084 fs.delete(regiondir, true); 085 fs.mkdirs(regiondir); 086 Path recoverededits = WALSplitUtil.getRegionDirRecoveredEditsDir(regiondir); 087 String first = WALSplitUtil.formatRecoveredEditsFileName(-1); 088 createFile(fs, recoverededits, first); 089 createFile(fs, recoverededits, WALSplitUtil.formatRecoveredEditsFileName(0)); 090 createFile(fs, recoverededits, WALSplitUtil.formatRecoveredEditsFileName(1)); 091 createFile(fs, recoverededits, WALSplitUtil.formatRecoveredEditsFileName(11)); 092 createFile(fs, recoverededits, WALSplitUtil.formatRecoveredEditsFileName(2)); 093 createFile(fs, recoverededits, WALSplitUtil.formatRecoveredEditsFileName(50)); 094 String last = WALSplitUtil.formatRecoveredEditsFileName(Long.MAX_VALUE); 095 createFile(fs, recoverededits, last); 096 createFile(fs, recoverededits, 097 Long.toString(Long.MAX_VALUE) + "." + EnvironmentEdgeManager.currentTime()); 098 099 final Configuration walConf = new Configuration(util.getConfiguration()); 100 CommonFSUtils.setRootDir(walConf, regiondir); 101 (new WALFactory(walConf, "dummyLogName")).getWAL(null); 102 103 NavigableSet<Path> files = WALSplitUtil.getSplitEditFilesSorted(fs, regiondir); 104 assertEquals(7, files.size()); 105 assertEquals(files.pollFirst().getName(), first); 106 assertEquals(files.pollLast().getName(), last); 107 assertEquals(files.pollFirst().getName(), WALSplitUtil.formatRecoveredEditsFileName(0)); 108 assertEquals(files.pollFirst().getName(), WALSplitUtil.formatRecoveredEditsFileName(1)); 109 assertEquals(files.pollFirst().getName(), WALSplitUtil.formatRecoveredEditsFileName(2)); 110 assertEquals(files.pollFirst().getName(), WALSplitUtil.formatRecoveredEditsFileName(11)); 111 } 112 113 private void createFile(final FileSystem fs, final Path testdir, final String name) 114 throws IOException { 115 FSDataOutputStream fdos = fs.create(new Path(testdir, name), true); 116 fdos.close(); 117 } 118 119 @Test 120 public void testRegionEntryBuffer() throws Exception { 121 EntryBuffers.RegionEntryBuffer reb = 122 new EntryBuffers.RegionEntryBuffer(TEST_TABLE, TEST_REGION); 123 assertEquals(0, reb.heapSize()); 124 125 reb.appendEntry(createTestLogEntry(1)); 126 assertTrue(reb.heapSize() > 0); 127 } 128 129 @Test 130 public void testEntrySink() throws Exception { 131 EntryBuffers sink = new EntryBuffers(new PipelineController(), 1 * 1024 * 1024); 132 for (int i = 0; i < 1000; i++) { 133 WAL.Entry entry = createTestLogEntry(i); 134 sink.appendEntry(entry); 135 } 136 137 assertTrue(sink.totalBuffered > 0); 138 long amountInChunk = sink.totalBuffered; 139 // Get a chunk 140 EntryBuffers.RegionEntryBuffer chunk = sink.getChunkToWrite(); 141 assertEquals(chunk.heapSize(), amountInChunk); 142 143 // Make sure it got marked that a thread is "working on this" 144 assertTrue(sink.isRegionCurrentlyWriting(TEST_REGION)); 145 146 // Insert some more entries 147 for (int i = 0; i < 500; i++) { 148 WAL.Entry entry = createTestLogEntry(i); 149 sink.appendEntry(entry); 150 } 151 // Asking for another chunk shouldn't work since the first one 152 // is still writing 153 assertNull(sink.getChunkToWrite()); 154 155 // If we say we're done writing the first chunk, then we should be able 156 // to get the second 157 sink.doneWriting(chunk); 158 159 EntryBuffers.RegionEntryBuffer chunk2 = sink.getChunkToWrite(); 160 assertNotNull(chunk2); 161 assertNotSame(chunk, chunk2); 162 long amountInChunk2 = sink.totalBuffered; 163 // The second chunk had fewer rows than the first 164 assertTrue(amountInChunk2 < amountInChunk); 165 166 sink.doneWriting(chunk2); 167 assertEquals(0, sink.totalBuffered); 168 } 169 170 private WAL.Entry createTestLogEntry(int i) { 171 long seq = i; 172 long now = i * 1000; 173 174 WALEdit edit = new WALEdit(); 175 edit.add(KeyValueTestUtil.create("row", "fam", "qual", 1234, "val")); 176 WALKeyImpl key = 177 new WALKeyImpl(TEST_REGION, TEST_TABLE, seq, now, HConstants.DEFAULT_CLUSTER_ID); 178 WAL.Entry entry = new WAL.Entry(key, edit); 179 return entry; 180 } 181 182 @Test 183 public void testParseServerNameFromWALName() { 184 assertEquals(ServerName.valueOf("abc,123,123"), 185 AbstractFSWALProvider.parseServerNameFromWALName("abc,123,123.1.12345.meta")); 186 assertEquals(ServerName.valueOf("abc,123,123"), 187 AbstractFSWALProvider.parseServerNameFromWALName("abc,123,123.12345")); 188 assertEquals(ServerName.valueOf("abc,123,123"), 189 AbstractFSWALProvider.parseServerNameFromWALName("abc,123,123")); 190 assertThrows(IllegalArgumentException.class, 191 () -> AbstractFSWALProvider.parseServerNameFromWALName("test,abc,123,123.12345")); 192 assertThrows(IllegalArgumentException.class, 193 () -> AbstractFSWALProvider.parseServerNameFromWALName("abc")); 194 } 195}