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.mob; 019 020import static org.junit.Assert.assertEquals; 021import static org.junit.Assert.assertNotNull; 022 023import java.io.IOException; 024import java.util.Date; 025import org.apache.hadoop.conf.Configuration; 026import org.apache.hadoop.fs.FileSystem; 027import org.apache.hadoop.fs.Path; 028import org.apache.hadoop.hbase.HBaseClassTestRule; 029import org.apache.hadoop.hbase.HBaseConfiguration; 030import org.apache.hadoop.hbase.HBaseTestingUtility; 031import org.apache.hadoop.hbase.HColumnDescriptor; 032import org.apache.hadoop.hbase.HRegionInfo; 033import org.apache.hadoop.hbase.HTableDescriptor; 034import org.apache.hadoop.hbase.KeyValue; 035import org.apache.hadoop.hbase.TableName; 036import org.apache.hadoop.hbase.client.RegionInfo; 037import org.apache.hadoop.hbase.client.RegionInfoBuilder; 038import org.apache.hadoop.hbase.io.hfile.CacheConfig; 039import org.apache.hadoop.hbase.regionserver.HMobStore; 040import org.apache.hadoop.hbase.regionserver.HRegion; 041import org.apache.hadoop.hbase.regionserver.StoreFileWriter; 042import org.apache.hadoop.hbase.testclassification.SmallTests; 043import org.apache.hadoop.hbase.util.Bytes; 044import org.junit.After; 045import org.junit.Before; 046import org.junit.ClassRule; 047import org.junit.Test; 048import org.junit.experimental.categories.Category; 049import org.slf4j.Logger; 050import org.slf4j.LoggerFactory; 051 052@Category(SmallTests.class) 053public class TestMobFileCache { 054 055 @ClassRule 056 public static final HBaseClassTestRule CLASS_RULE = 057 HBaseClassTestRule.forClass(TestMobFileCache.class); 058 059 static final Logger LOG = LoggerFactory.getLogger(TestMobFileCache.class); 060 private HBaseTestingUtility UTIL; 061 private HRegion region; 062 private Configuration conf; 063 private MobFileCache mobFileCache; 064 private Date currentDate = new Date(); 065 private static final String TEST_CACHE_SIZE = "2"; 066 private static final int EXPECTED_CACHE_SIZE_ZERO = 0; 067 private static final int EXPECTED_CACHE_SIZE_ONE = 1; 068 private static final int EXPECTED_CACHE_SIZE_TWO = 2; 069 private static final int EXPECTED_CACHE_SIZE_THREE = 3; 070 private static final long EXPECTED_REFERENCE_ONE = 1; 071 private static final long EXPECTED_REFERENCE_TWO = 2; 072 073 private static final String TABLE = "tableName"; 074 private static final String FAMILY1 = "family1"; 075 private static final String FAMILY2 = "family2"; 076 private static final String FAMILY3 = "family3"; 077 078 private static final byte[] ROW = Bytes.toBytes("row"); 079 private static final byte[] ROW2 = Bytes.toBytes("row2"); 080 private static final byte[] VALUE = Bytes.toBytes("value"); 081 private static final byte[] VALUE2 = Bytes.toBytes("value2"); 082 private static final byte[] QF1 = Bytes.toBytes("qf1"); 083 private static final byte[] QF2 = Bytes.toBytes("qf2"); 084 private static final byte[] QF3 = Bytes.toBytes("qf3"); 085 086 @Before 087 public void setUp() throws Exception { 088 UTIL = HBaseTestingUtility.createLocalHTU(); 089 conf = UTIL.getConfiguration(); 090 conf.set(MobConstants.MOB_FILE_CACHE_SIZE_KEY, TEST_CACHE_SIZE); 091 HTableDescriptor htd = UTIL.createTableDescriptor("testMobFileCache"); 092 HColumnDescriptor hcd1 = new HColumnDescriptor(FAMILY1); 093 hcd1.setMobEnabled(true); 094 hcd1.setMobThreshold(0); 095 HColumnDescriptor hcd2 = new HColumnDescriptor(FAMILY2); 096 hcd2.setMobEnabled(true); 097 hcd2.setMobThreshold(0); 098 HColumnDescriptor hcd3 = new HColumnDescriptor(FAMILY3); 099 hcd3.setMobEnabled(true); 100 hcd3.setMobThreshold(0); 101 htd.addFamily(hcd1); 102 htd.addFamily(hcd2); 103 htd.addFamily(hcd3); 104 RegionInfo regionInfo = RegionInfoBuilder.newBuilder(htd.getTableName()).build(); 105 mobFileCache = new MobFileCache(conf); 106 region = HBaseTestingUtility 107 .createRegionAndWAL(regionInfo, UTIL.getDataTestDir(), conf, htd, mobFileCache); 108 } 109 110 @After 111 public void tearDown() throws Exception { 112 region.close(); 113 region.getFilesystem().delete(UTIL.getDataTestDir(), true); 114 } 115 116 /** 117 * Create the mob store file. 118 */ 119 private Path createMobStoreFile(String family) throws IOException { 120 return createMobStoreFile(HBaseConfiguration.create(), family); 121 } 122 123 /** 124 * Create the mob store file 125 */ 126 private Path createMobStoreFile(Configuration conf, String family) throws IOException { 127 HColumnDescriptor hcd = new HColumnDescriptor(family); 128 hcd.setMaxVersions(4); 129 hcd.setMobEnabled(true); 130 return createMobStoreFile(hcd); 131 } 132 133 /** 134 * Create the mob store file 135 */ 136 private Path createMobStoreFile(HColumnDescriptor hcd) 137 throws IOException { 138 // Setting up a Store 139 TableName tn = TableName.valueOf(TABLE); 140 HTableDescriptor htd = new HTableDescriptor(tn); 141 htd.addFamily(hcd); 142 HMobStore mobStore = (HMobStore) region.getStore(hcd.getName()); 143 KeyValue key1 = new KeyValue(ROW, hcd.getName(), QF1, 1, VALUE); 144 KeyValue key2 = new KeyValue(ROW, hcd.getName(), QF2, 1, VALUE); 145 KeyValue key3 = new KeyValue(ROW2, hcd.getName(), QF3, 1, VALUE2); 146 KeyValue[] keys = new KeyValue[] { key1, key2, key3 }; 147 int maxKeyCount = keys.length; 148 HRegionInfo regionInfo = new HRegionInfo(tn); 149 StoreFileWriter mobWriter = mobStore.createWriterInTmp(currentDate, 150 maxKeyCount, hcd.getCompactionCompression(), regionInfo.getStartKey(), false); 151 Path mobFilePath = mobWriter.getPath(); 152 String fileName = mobFilePath.getName(); 153 mobWriter.append(key1); 154 mobWriter.append(key2); 155 mobWriter.append(key3); 156 mobWriter.close(); 157 String targetPathName = MobUtils.formatDate(currentDate); 158 Path targetPath = new Path(mobStore.getPath(), targetPathName); 159 mobStore.commitFile(mobFilePath, targetPath); 160 return new Path(targetPath, fileName); 161 } 162 163 @Test 164 public void testMobFileCache() throws Exception { 165 FileSystem fs = FileSystem.get(conf); 166 Path file1Path = createMobStoreFile(FAMILY1); 167 Path file2Path = createMobStoreFile(FAMILY2); 168 Path file3Path = createMobStoreFile(FAMILY3); 169 170 CacheConfig cacheConf = new CacheConfig(conf); 171 // Before open one file by the MobFileCache 172 assertEquals(EXPECTED_CACHE_SIZE_ZERO, mobFileCache.getCacheSize()); 173 // Open one file by the MobFileCache 174 CachedMobFile cachedMobFile1 = (CachedMobFile) mobFileCache.openFile( 175 fs, file1Path, cacheConf); 176 assertEquals(EXPECTED_CACHE_SIZE_ONE, mobFileCache.getCacheSize()); 177 assertNotNull(cachedMobFile1); 178 assertEquals(EXPECTED_REFERENCE_TWO, cachedMobFile1.getReferenceCount()); 179 180 // The evict is also managed by a schedule thread pool. 181 // And its check period is set as 3600 seconds by default. 182 // This evict should get the lock at the most time 183 mobFileCache.evict(); // Cache not full, evict it 184 assertEquals(EXPECTED_CACHE_SIZE_ONE, mobFileCache.getCacheSize()); 185 assertEquals(EXPECTED_REFERENCE_TWO, cachedMobFile1.getReferenceCount()); 186 187 mobFileCache.evictFile(file1Path.getName()); // Evict one file 188 assertEquals(EXPECTED_CACHE_SIZE_ZERO, mobFileCache.getCacheSize()); 189 assertEquals(EXPECTED_REFERENCE_ONE, cachedMobFile1.getReferenceCount()); 190 191 cachedMobFile1.close(); // Close the cached mob file 192 193 // Reopen three cached file 194 cachedMobFile1 = (CachedMobFile) mobFileCache.openFile( 195 fs, file1Path, cacheConf); 196 assertEquals(EXPECTED_CACHE_SIZE_ONE, mobFileCache.getCacheSize()); 197 CachedMobFile cachedMobFile2 = (CachedMobFile) mobFileCache.openFile( 198 fs, file2Path, cacheConf); 199 assertEquals(EXPECTED_CACHE_SIZE_TWO, mobFileCache.getCacheSize()); 200 CachedMobFile cachedMobFile3 = (CachedMobFile) mobFileCache.openFile( 201 fs, file3Path, cacheConf); 202 // Before the evict 203 // Evict the cache, should close the first file 1 204 assertEquals(EXPECTED_CACHE_SIZE_THREE, mobFileCache.getCacheSize()); 205 assertEquals(EXPECTED_REFERENCE_TWO, cachedMobFile1.getReferenceCount()); 206 assertEquals(EXPECTED_REFERENCE_TWO, cachedMobFile2.getReferenceCount()); 207 assertEquals(EXPECTED_REFERENCE_TWO, cachedMobFile3.getReferenceCount()); 208 mobFileCache.evict(); 209 assertEquals(EXPECTED_CACHE_SIZE_ONE, mobFileCache.getCacheSize()); 210 assertEquals(EXPECTED_REFERENCE_ONE, cachedMobFile1.getReferenceCount()); 211 assertEquals(EXPECTED_REFERENCE_ONE, cachedMobFile2.getReferenceCount()); 212 assertEquals(EXPECTED_REFERENCE_TWO, cachedMobFile3.getReferenceCount()); 213 } 214}