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.hamcrest.MatcherAssert.assertThat; 021import static org.hamcrest.Matchers.hasSize; 022import static org.junit.jupiter.api.Assertions.assertEquals; 023import static org.junit.jupiter.api.Assertions.assertTrue; 024 025import java.util.Arrays; 026import java.util.List; 027import java.util.NavigableMap; 028import java.util.TreeMap; 029import org.apache.hadoop.fs.Path; 030import org.apache.hadoop.hbase.Cell; 031import org.apache.hadoop.hbase.CellBuilderType; 032import org.apache.hadoop.hbase.ExtendedCellBuilderFactory; 033import org.apache.hadoop.hbase.HBaseTestingUtil; 034import org.apache.hadoop.hbase.TableName; 035import org.apache.hadoop.hbase.client.RegionInfo; 036import org.apache.hadoop.hbase.client.RegionInfoBuilder; 037import org.apache.hadoop.hbase.regionserver.MultiVersionConcurrencyControl; 038import org.apache.hadoop.hbase.util.Bytes; 039import org.junit.jupiter.api.Test; 040 041@SuppressWarnings("checkstyle:innerassignment") 042public abstract class CompressedWALTestBase { 043 044 protected final static HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil(); 045 046 static final byte[] VALUE; 047 static { 048 // 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597 049 VALUE = 050 new byte[1 + 1 + 2 + 3 + 5 + 8 + 13 + 21 + 34 + 55 + 89 + 144 + 233 + 377 + 610 + 987 + 1597]; 051 int off = 0; 052 Arrays.fill(VALUE, off, (off += 1), (byte) 'A'); 053 Arrays.fill(VALUE, off, (off += 1), (byte) 'B'); 054 Arrays.fill(VALUE, off, (off += 2), (byte) 'C'); 055 Arrays.fill(VALUE, off, (off += 3), (byte) 'D'); 056 Arrays.fill(VALUE, off, (off += 5), (byte) 'E'); 057 Arrays.fill(VALUE, off, (off += 8), (byte) 'F'); 058 Arrays.fill(VALUE, off, (off += 13), (byte) 'G'); 059 Arrays.fill(VALUE, off, (off += 21), (byte) 'H'); 060 Arrays.fill(VALUE, off, (off += 34), (byte) 'I'); 061 Arrays.fill(VALUE, off, (off += 55), (byte) 'J'); 062 Arrays.fill(VALUE, off, (off += 89), (byte) 'K'); 063 Arrays.fill(VALUE, off, (off += 144), (byte) 'L'); 064 Arrays.fill(VALUE, off, (off += 233), (byte) 'M'); 065 Arrays.fill(VALUE, off, (off += 377), (byte) 'N'); 066 Arrays.fill(VALUE, off, (off += 610), (byte) 'O'); 067 Arrays.fill(VALUE, off, (off += 987), (byte) 'P'); 068 Arrays.fill(VALUE, off, (off += 1597), (byte) 'Q'); 069 } 070 071 @Test 072 public void test() throws Exception { 073 testForSize(1000); 074 } 075 076 @Test 077 public void testLarge() throws Exception { 078 testForSize(1024 * 1024); 079 } 080 081 private void testForSize(int size) throws Exception { 082 TableName tableName = TableName.valueOf(getClass().getSimpleName() + "_testForSize_" + size); 083 doTest(tableName, size); 084 } 085 086 public void doTest(TableName tableName, int valueSize) throws Exception { 087 NavigableMap<byte[], Integer> scopes = new TreeMap<>(Bytes.BYTES_COMPARATOR); 088 scopes.put(tableName.getName(), 0); 089 RegionInfo regionInfo = RegionInfoBuilder.newBuilder(tableName).build(); 090 final int total = 1000; 091 final byte[] row = Bytes.toBytes("row"); 092 final byte[] family = Bytes.toBytes("family"); 093 final byte[] value = new byte[valueSize]; 094 095 int offset = 0; 096 while (offset + VALUE.length < value.length) { 097 System.arraycopy(VALUE, 0, value, offset, VALUE.length); 098 offset += VALUE.length; 099 } 100 101 final WALFactory wals = 102 new WALFactory(TEST_UTIL.getConfiguration(), tableName.getNameAsString()); 103 104 // Write the WAL 105 final WAL wal = wals.getWAL(regionInfo); 106 107 MultiVersionConcurrencyControl mvcc = new MultiVersionConcurrencyControl(); 108 109 for (int i = 0; i < total; i++) { 110 WALEdit kvs = new WALEdit(); 111 kvs.add(ExtendedCellBuilderFactory.create(CellBuilderType.SHALLOW_COPY).setType(Cell.Type.Put) 112 .setRow(row).setFamily(family).setQualifier(Bytes.toBytes(i)).setValue(value).build()); 113 kvs.add(ExtendedCellBuilderFactory.create(CellBuilderType.SHALLOW_COPY) 114 .setType(Cell.Type.DeleteFamily).setRow(row).setFamily(family).build()); 115 wal.appendData(regionInfo, new WALKeyImpl(regionInfo.getEncodedNameAsBytes(), tableName, 116 System.currentTimeMillis(), mvcc, scopes), kvs); 117 wal.sync(); 118 } 119 final Path walPath = AbstractFSWALProvider.getCurrentFileName(wal); 120 wals.shutdown(); 121 122 // Confirm the WAL can be read back 123 try (WALStreamReader reader = wals.createStreamReader(TEST_UTIL.getTestFileSystem(), walPath)) { 124 int count = 0; 125 WAL.Entry entry = new WAL.Entry(); 126 while (reader.next(entry) != null) { 127 count++; 128 List<Cell> cells = entry.getEdit().getCells(); 129 assertThat("Should be two KVs per WALEdit", cells, hasSize(2)); 130 Cell putCell = cells.get(0); 131 assertEquals(Cell.Type.Put, putCell.getType()); 132 assertTrue(Bytes.equals(putCell.getRowArray(), putCell.getRowOffset(), 133 putCell.getRowLength(), row, 0, row.length), "Incorrect row"); 134 assertTrue(Bytes.equals(putCell.getFamilyArray(), putCell.getFamilyOffset(), 135 putCell.getFamilyLength(), family, 0, family.length), "Incorrect family"); 136 assertTrue(Bytes.equals(putCell.getValueArray(), putCell.getValueOffset(), 137 putCell.getValueLength(), value, 0, value.length), "Incorrect value"); 138 139 Cell deleteCell = cells.get(1); 140 assertEquals(Cell.Type.DeleteFamily, deleteCell.getType()); 141 assertTrue(Bytes.equals(deleteCell.getRowArray(), deleteCell.getRowOffset(), 142 deleteCell.getRowLength(), row, 0, row.length), "Incorrect row"); 143 assertTrue(Bytes.equals(deleteCell.getFamilyArray(), deleteCell.getFamilyOffset(), 144 deleteCell.getFamilyLength(), family, 0, family.length), "Incorrect family"); 145 } 146 assertEquals(total, count, "Should have read back as many KVs as written"); 147 } 148 } 149}