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