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.coprocessor; 019 020import static org.junit.Assert.assertTrue; 021 022import java.io.IOException; 023import java.util.Optional; 024import org.apache.hadoop.conf.Configuration; 025import org.apache.hadoop.fs.Path; 026import org.apache.hadoop.hbase.Coprocessor; 027import org.apache.hadoop.hbase.HBaseClassTestRule; 028import org.apache.hadoop.hbase.HBaseTestingUtil; 029import org.apache.hadoop.hbase.TableName; 030import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder; 031import org.apache.hadoop.hbase.client.Durability; 032import org.apache.hadoop.hbase.client.Put; 033import org.apache.hadoop.hbase.client.RegionInfo; 034import org.apache.hadoop.hbase.client.RegionInfoBuilder; 035import org.apache.hadoop.hbase.client.TableDescriptor; 036import org.apache.hadoop.hbase.client.TableDescriptorBuilder; 037import org.apache.hadoop.hbase.regionserver.ChunkCreator; 038import org.apache.hadoop.hbase.regionserver.HRegion; 039import org.apache.hadoop.hbase.regionserver.MemStoreLAB; 040import org.apache.hadoop.hbase.regionserver.RegionCoprocessorHost; 041import org.apache.hadoop.hbase.regionserver.RegionServerServices; 042import org.apache.hadoop.hbase.testclassification.CoprocessorTests; 043import org.apache.hadoop.hbase.testclassification.SmallTests; 044import org.apache.hadoop.hbase.util.Bytes; 045import org.apache.hadoop.hbase.util.EnvironmentEdgeManager; 046import org.apache.hadoop.hbase.util.Threads; 047import org.apache.hadoop.hbase.wal.WALEdit; 048import org.junit.ClassRule; 049import org.junit.Test; 050import org.junit.experimental.categories.Category; 051import org.mockito.Mockito; 052 053@Category({ CoprocessorTests.class, SmallTests.class }) 054public class TestRegionObserverStacking { 055 056 @ClassRule 057 public static final HBaseClassTestRule CLASS_RULE = 058 HBaseClassTestRule.forClass(TestRegionObserverStacking.class); 059 060 private static HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil(); 061 static final Path DIR = TEST_UTIL.getDataTestDir(); 062 063 public static class ObserverA implements RegionCoprocessor, RegionObserver { 064 long id; 065 066 @Override 067 public Optional<RegionObserver> getRegionObserver() { 068 return Optional.of(this); 069 } 070 071 @Override 072 public void postPut(final ObserverContext<? extends RegionCoprocessorEnvironment> c, 073 final Put put, final WALEdit edit, final Durability durability) throws IOException { 074 id = EnvironmentEdgeManager.currentTime(); 075 Threads.sleepWithoutInterrupt(10); 076 } 077 } 078 079 public static class ObserverB implements RegionCoprocessor, RegionObserver { 080 long id; 081 082 @Override 083 public Optional<RegionObserver> getRegionObserver() { 084 return Optional.of(this); 085 } 086 087 @Override 088 public void postPut(final ObserverContext<? extends RegionCoprocessorEnvironment> c, 089 final Put put, final WALEdit edit, final Durability durability) throws IOException { 090 id = EnvironmentEdgeManager.currentTime(); 091 Threads.sleepWithoutInterrupt(10); 092 } 093 } 094 095 public static class ObserverC implements RegionCoprocessor, RegionObserver { 096 long id; 097 098 @Override 099 public Optional<RegionObserver> getRegionObserver() { 100 return Optional.of(this); 101 } 102 103 @Override 104 public void postPut(final ObserverContext<? extends RegionCoprocessorEnvironment> c, 105 final Put put, final WALEdit edit, final Durability durability) throws IOException { 106 id = EnvironmentEdgeManager.currentTime(); 107 Threads.sleepWithoutInterrupt(10); 108 } 109 } 110 111 HRegion initHRegion(byte[] tableName, String callingMethod, Configuration conf, 112 byte[]... families) throws IOException { 113 TableDescriptorBuilder builder = 114 TableDescriptorBuilder.newBuilder(TableName.valueOf(tableName)); 115 for (byte[] family : families) { 116 builder.setColumnFamily(ColumnFamilyDescriptorBuilder.of(family)); 117 } 118 TableDescriptor tableDescriptor = builder.build(); 119 ChunkCreator.initialize(MemStoreLAB.CHUNK_SIZE_DEFAULT, false, 0, 0, 0, null, 120 MemStoreLAB.INDEX_CHUNK_SIZE_PERCENTAGE_DEFAULT); 121 RegionInfo info = RegionInfoBuilder.newBuilder(tableDescriptor.getTableName()).build(); 122 Path path = new Path(DIR + callingMethod); 123 HRegion r = HBaseTestingUtil.createRegionAndWAL(info, path, conf, tableDescriptor); 124 // this following piece is a hack. currently a coprocessorHost 125 // is secretly loaded at OpenRegionHandler. we don't really 126 // start a region server here, so just manually create cphost 127 // and set it to region. 128 RegionCoprocessorHost host = 129 new RegionCoprocessorHost(r, Mockito.mock(RegionServerServices.class), conf); 130 r.setCoprocessorHost(host); 131 return r; 132 } 133 134 @Test 135 public void testRegionObserverStacking() throws Exception { 136 byte[] ROW = Bytes.toBytes("testRow"); 137 byte[] TABLE = Bytes.toBytes(this.getClass().getSimpleName()); 138 byte[] A = Bytes.toBytes("A"); 139 byte[][] FAMILIES = new byte[][] { A }; 140 141 Configuration conf = TEST_UTIL.getConfiguration(); 142 HRegion region = initHRegion(TABLE, getClass().getName(), conf, FAMILIES); 143 RegionCoprocessorHost h = region.getCoprocessorHost(); 144 h.load(ObserverA.class, Coprocessor.PRIORITY_HIGHEST, conf); 145 h.load(ObserverB.class, Coprocessor.PRIORITY_USER, conf); 146 h.load(ObserverC.class, Coprocessor.PRIORITY_LOWEST, conf); 147 148 Put put = new Put(ROW); 149 put.addColumn(A, A, A); 150 region.put(put); 151 152 Coprocessor c = h.findCoprocessor(ObserverA.class.getName()); 153 long idA = ((ObserverA) c).id; 154 c = h.findCoprocessor(ObserverB.class.getName()); 155 long idB = ((ObserverB) c).id; 156 c = h.findCoprocessor(ObserverC.class.getName()); 157 long idC = ((ObserverC) c).id; 158 159 assertTrue(idA < idB); 160 assertTrue(idB < idC); 161 HBaseTestingUtil.closeRegionAndWAL(region); 162 } 163}