/**
* Copyright 2011 The Apache Software Foundation
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.hbase.index.coprocessor.regionserver;
import static org.junit.Assert.assertEquals;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseTestingUtility;
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.LargeTests;
import org.apache.hadoop.hbase.MasterNotRunningException;
import org.apache.hadoop.hbase.MiniHBaseCluster;
import org.apache.hadoop.hbase.UnknownRegionException;
import org.apache.hadoop.hbase.ZooKeeperConnectionException;
import org.apache.hadoop.hbase.client.HBaseAdmin;
import org.apache.hadoop.hbase.client.HTable;
import org.apache.hadoop.hbase.client.Mutation;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.ResultScanner;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.coprocessor.CoprocessorHost;
import org.apache.hadoop.hbase.coprocessor.ObserverContext;
import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
import org.apache.hadoop.hbase.index.ColumnQualifier.ValueType;
import org.apache.hadoop.hbase.index.IndexSpecification;
import org.apache.hadoop.hbase.index.IndexedHTableDescriptor;
import org.apache.hadoop.hbase.index.coprocessor.master.IndexMasterObserver;
import org.apache.hadoop.hbase.index.coprocessor.wal.IndexWALObserver;
import org.apache.hadoop.hbase.regionserver.HRegion;
import org.apache.hadoop.hbase.regionserver.HRegionServer;
import org.apache.hadoop.hbase.regionserver.InternalScanner;
import org.apache.hadoop.hbase.regionserver.KeyValueScanner;
import org.apache.hadoop.hbase.regionserver.ScanType;
import org.apache.hadoop.hbase.regionserver.Store;
import org.apache.hadoop.hbase.regionserver.wal.WALEdit;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.zookeeper.ZKAssign;
import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.experimental.categories.Category;
@Category(LargeTests.class)
public class TestForComplexIssues {
private static HBaseTestingUtility UTIL = new HBaseTestingUtility();
public static CountDownLatch latch = new CountDownLatch(1);
public static CountDownLatch latchForCompact = new CountDownLatch(1);
private static boolean compactionCalled = false;
private static volatile boolean closeCalled = false;
private static volatile boolean delayPostBatchMutate = false;
private static int openCount = 0;
private static int closeCount = 0;
@BeforeClass
public static void setupBeforeClass() throws Exception {
Configuration conf = UTIL.getConfiguration();
conf.set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY, IndexMasterObserver.class.getName());
conf.set(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY, LocalIndexRegionObserver.class.getName());
conf.set(CoprocessorHost.WAL_COPROCESSOR_CONF_KEY, IndexWALObserver.class.getName());
conf.setBoolean("hbase.use.secondary.index", true);
}
@Before
public void setUp() throws Exception {
UTIL.startMiniCluster(2);
}
@After
public void tearDown() throws Exception {
compactionCalled = false;
closeCalled = false;
delayPostBatchMutate = false;
UTIL.shutdownMiniCluster();
}
@Test(timeout = 180000)
public void testHDP2989() throws Exception {
HBaseAdmin admin = UTIL.getHBaseAdmin();
Configuration conf = UTIL.getConfiguration();
conf.setInt("hbase.client.retries.number", 1);
conf.setBoolean("hbase.use.secondary.index", true);
conf.setInt("hbase.regionserver.lease.period", 90000000);
ZooKeeperWatcher zkw = HBaseTestingUtility.getZooKeeperWatcher(UTIL);
String userTableName = "testHDP2989";
IndexedHTableDescriptor ihtd = new IndexedHTableDescriptor(userTableName);
HColumnDescriptor hcd = new HColumnDescriptor("col");
IndexSpecification iSpec = new IndexSpecification("ScanIndexf");
iSpec.addIndexColumn(hcd, "ql", ValueType.String, 10);
ihtd.addFamily(hcd);
ihtd.addIndex(iSpec);
admin.createTable(ihtd);
ZKAssign.blockUntilNoRIT(zkw);
HTable table = new HTable(conf, userTableName);
// test put with the indexed column
for (int i = 0; i < 10; i++) {
String row = "row" + i;
Put p = new Put(row.getBytes());
String val = "Val" + i;
p.add("col".getBytes(), "ql".getBytes(), val.getBytes());
table.put(p);
admin.flush(userTableName);
}
MiniHBaseCluster hBaseCluster = UTIL.getHBaseCluster();
List<HRegion> regions = hBaseCluster.getRegions(Bytes.toBytes(userTableName));
HRegion hRegion = regions.get(0);
byte[] encodedNameAsBytes = hRegion.getRegionInfo().getEncodedNameAsBytes();
int serverWith = hBaseCluster.getServerWith(hRegion.getRegionName());
int destServerNo = (serverWith == 1 ? 0 : 1);
HRegionServer destServer = hBaseCluster.getRegionServer(destServerNo);
admin.compact(userTableName);
while (!compactionCalled) {
Thread.sleep(1000);
}
byte[] dstRSName = Bytes.toBytes(destServer.getServerName().getServerName());
// Move the main region
MoveThread move = new MoveThread(admin, encodedNameAsBytes, dstRSName);
move.start();
// Move the indexRegion
regions = hBaseCluster.getRegions(Bytes.toBytes(userTableName + "_idx"));
HRegion hRegion1 = regions.get(0);
encodedNameAsBytes = hRegion1.getRegionInfo().getEncodedNameAsBytes();
serverWith = hBaseCluster.getServerWith(hRegion1.getRegionName());
destServerNo = (serverWith == 1 ? 0 : 1);
destServer = hBaseCluster.getRegionServer(destServerNo);
dstRSName = Bytes.toBytes(destServer.getServerName().getServerName());
move = new MoveThread(admin, encodedNameAsBytes, dstRSName);
move.start();
while (!closeCalled) {
Thread.sleep(200);
}
String row = "row" + 46;
Put p = new Put(row.getBytes());
String val = "Val" + 46;
p.add("col".getBytes(), "ql".getBytes(), val.getBytes());
try {
table.put(p);
} catch (Exception e) {
e.printStackTrace();
}
latchForCompact.countDown();
closeCount++;
latch.countDown();
List<HRegion> onlineRegions = destServer.getOnlineRegions(Bytes.toBytes(userTableName));
List<HRegion> onlineIdxRegions =
destServer.getOnlineRegions(Bytes.toBytes(userTableName + "_idx"));
while (onlineRegions.size() == 0 || onlineIdxRegions.size() == 0) {
Thread.sleep(1000);
onlineRegions = destServer.getOnlineRegions(Bytes.toBytes(userTableName));
onlineIdxRegions = destServer.getOnlineRegions(Bytes.toBytes(userTableName + "_idx"));
}
/*
* closeCount++; latch.countDown();
*/
Scan s = new Scan();
conf.setInt("hbase.client.retries.number", 10);
table = new HTable(conf, userTableName);
ResultScanner scanner = table.getScanner(s);
int i = 0;
for (Result result : scanner) {
i++;
}
HTable indextable = new HTable(conf, userTableName + "_idx");
s = new Scan();
scanner = indextable.getScanner(s);
int j = 0;
for (Result result : scanner) {
j++;
}
assertEquals("", i, j);
}
@Test(timeout = 180000)
// test for HDP-2983
public
void testCompactionOfIndexRegionBeforeMainRegionOpens() throws Exception {
HBaseAdmin admin = new HBaseAdmin(UTIL.getConfiguration());
Configuration conf = admin.getConfiguration();
conf.setBoolean("hbase.use.secondary.index", true);
ZooKeeperWatcher zkw = HBaseTestingUtility.getZooKeeperWatcher(UTIL);
String userTableName = "testCompactionOfIndexRegionBeforeMainRegionOpens";
IndexedHTableDescriptor ihtd = new IndexedHTableDescriptor(userTableName);
HColumnDescriptor hcd = new HColumnDescriptor("col1");
ihtd.addFamily(hcd);
IndexSpecification iSpec = new IndexSpecification("Index1");
iSpec.addIndexColumn(hcd, "ql", ValueType.String, 10);
IndexSpecification iSpec1 = new IndexSpecification("Index2");
iSpec1.addIndexColumn(hcd, "q2", ValueType.String, 10);
ihtd.addIndex(iSpec);
ihtd.addIndex(iSpec1);
admin.createTable(ihtd);
ZKAssign.blockUntilNoRIT(zkw);
openCount++;
HTable table = new HTable(conf, userTableName);
Put p = null;
for (int i = 0; i < 25; i++) {
p = new Put(Bytes.toBytes("row" + i));
p.add(Bytes.toBytes("col1"), Bytes.toBytes("ql"), Bytes.toBytes("test_val"));
p.add(Bytes.toBytes("col1"), Bytes.toBytes("q2"), Bytes.toBytes("test_val"));
table.put(p);
if (i == 4 || i == 11 || i == 24) {
admin.flush(userTableName);
admin.flush(userTableName + "_idx");
}
}
HTable indextable = new HTable(conf, userTableName + "_idx");
Scan s = new Scan();
ResultScanner scanner = indextable.getScanner(s);
int j = 0;
for (Result result : scanner) {
j++;
}
assertEquals("", 50, j);
MiniHBaseCluster hBaseCluster = UTIL.getHBaseCluster();
List<HRegion> regions = hBaseCluster.getRegions(Bytes.toBytes(userTableName));
HRegion hRegion = regions.get(0);
List<HRegion> indexRegions = hBaseCluster.getRegions(Bytes.toBytes(userTableName + "_idx"));
HRegion indexHRegion = indexRegions.get(0);
int srcServer = hBaseCluster.getServerWith(hRegion.getRegionName());
int destServer = (srcServer == 1 ? 0 : 1);
HRegionServer regionServer = hBaseCluster.getRegionServer(destServer);
// Abort the regionserver
hBaseCluster.abortRegionServer(srcServer);
hBaseCluster.waitOnRegionServer(srcServer);
boolean regionOnline =
hBaseCluster.getMaster().getAssignmentManager()
.isRegionAssigned(indexHRegion.getRegionInfo());
while (!regionOnline) {
regionOnline =
hBaseCluster.getMaster().getAssignmentManager()
.isRegionAssigned(indexHRegion.getRegionInfo());
}
admin.compact(userTableName + "_idx");
List<HRegion> onlineRegions =
regionServer.getOnlineRegions(Bytes.toBytes(userTableName + "_idx"));
List<String> storeFileList =
regionServer.getStoreFileList(onlineRegions.get(0).getRegionName());
while (storeFileList.size() != 1) {
Thread.sleep(1000);
storeFileList = regionServer.getStoreFileList(onlineRegions.get(0).getRegionName());
}
assertEquals("The total store files for the index table should be 1", 1, storeFileList.size());
indextable = new HTable(conf, userTableName + "_idx");
s = new Scan();
scanner = indextable.getScanner(s);
j = 0;
for (Result result : scanner) {
j++;
}
assertEquals("", 50, j);
// Decrement the latch
latch.countDown();
ZKAssign.blockUntilNoRIT(zkw);
openCount = 0;
// Check after dropping the index
storeFileList = regionServer.getStoreFileList(onlineRegions.get(0).getRegionName());
String storeFileName = storeFileList.get(0);
// admin.dropIndex("Index2", userTableName);
ZKAssign.blockUntilNoRIT(zkw);
while (storeFileList.get(0).equals(storeFileName)) {
Thread.sleep(1000);
storeFileList = regionServer.getStoreFileList(onlineRegions.get(0).getRegionName());
}
indextable = new HTable(conf, userTableName + "_idx");
s = new Scan();
scanner = indextable.getScanner(s);
j = 0;
for (Result result : scanner) {
j++;
}
assertEquals("", 25, j);
}
@Test(timeout = 180000)
public void testHDP3015() throws Exception {
final HBaseAdmin admin = UTIL.getHBaseAdmin();
Configuration conf = UTIL.getConfiguration();
conf.setBoolean("hbase.use.secondary.index", true);
conf.setInt("hbase.regionserver.lease.period", 90000000);
ZooKeeperWatcher zkw = HBaseTestingUtility.getZooKeeperWatcher(UTIL);
final String userTableName = "testHDP3015";
IndexedHTableDescriptor ihtd = new IndexedHTableDescriptor(userTableName);
HColumnDescriptor hcd = new HColumnDescriptor("col");
IndexSpecification iSpec = new IndexSpecification("ScanIndexf");
iSpec.addIndexColumn(hcd, "ql", ValueType.String, 10);
ihtd.addFamily(hcd);
ihtd.addIndex(iSpec);
admin.createTable(ihtd);
ZKAssign.blockUntilNoRIT(zkw);
HTable table = new HTable(conf, userTableName);
// test put with the indexed column
for (int i = 0; i < 4; i++) {
String row = "row" + i;
Put p = new Put(row.getBytes());
String val = "Val" + i;
p.add("col".getBytes(), "ql".getBytes(), val.getBytes());
if (i == 3) {
delayPostBatchMutate = true;
}
table.put(p);
if (i == 2) {
new Thread() {
public void run() {
try {
admin.flush(userTableName + "_idx");
} catch (Exception e) {
}
}
}.start();
}
}
MiniHBaseCluster hBaseCluster = UTIL.getHBaseCluster();
List<HRegion> userRegions = hBaseCluster.getRegions(Bytes.toBytes(userTableName));
List<HRegion> indexRegions = hBaseCluster.getRegions(Bytes.toBytes(userTableName + "_idx"));
HRegion indexHRegion = indexRegions.get(0);
int serverWith = hBaseCluster.getServerWith((userRegions.get(0).getRegionName()));
HRegionServer regionServer = hBaseCluster.getRegionServer(serverWith);
List<String> storeFileList = regionServer.getStoreFileList(indexHRegion.getRegionName());
while (storeFileList.size() == 0) {
storeFileList = regionServer.getStoreFileList(indexHRegion.getRegionName());
}
table = new HTable(conf, userTableName);
ResultScanner scanner = table.getScanner(new Scan());
int i = 0;
for (Result result : scanner) {
i++;
}
table = new HTable(conf, userTableName + "_idx");
scanner = table.getScanner(new Scan());
int j = 0;
for (Result result : scanner) {
j++;
}
assertEquals("", i, j);
hBaseCluster.abortRegionServer(serverWith);
hBaseCluster.waitOnRegionServer(serverWith);
boolean regionOnline =
hBaseCluster.getMaster().getAssignmentManager()
.isRegionAssigned(indexHRegion.getRegionInfo());
while (!regionOnline) {
regionOnline =
hBaseCluster.getMaster().getAssignmentManager()
.isRegionAssigned(indexHRegion.getRegionInfo());
}
table = new HTable(conf, userTableName);
scanner = table.getScanner(new Scan());
i = 0;
for (Result result : scanner) {
i++;
}
table = new HTable(conf, userTableName + "_idx");
scanner = table.getScanner(new Scan());
j = 0;
for (Result result : scanner) {
j++;
}
assertEquals("", i, j);
}
public static class LocalIndexRegionObserver extends IndexRegionObserver {
@Override
public InternalScanner preCompactScannerOpen(ObserverContext<RegionCoprocessorEnvironment> c,
Store store, List<? extends KeyValueScanner> scanners, ScanType scanType,
long earliestPutTs, InternalScanner s) throws IOException {
if (store.getTableName().equals("testHDP2989")) {
try {
compactionCalled = true;
latchForCompact.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return super.preCompactScannerOpen(c, store, scanners, scanType, earliestPutTs, s);
}
@Override
public void postOpen(ObserverContext<RegionCoprocessorEnvironment> e) {
if (e.getEnvironment().getRegion().getRegionInfo().getTableNameAsString()
.equals("testCompactionOfIndexRegionBeforeMainRegionOpens")
&& openCount > 0) {
try {
latch.await();
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
super.postOpen(e);
}
@Override
public void postClose(ObserverContext<RegionCoprocessorEnvironment> e, boolean abortRequested) {
if (e.getEnvironment().getRegion().getRegionInfo().getTableNameAsString()
.equals("testHDP2989_idx")
&& closeCount == 0) {
try {
closeCalled = true;
latch.await();
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
super.postClose(e, abortRequested);
}
@Override
public void postBatchMutate(ObserverContext<RegionCoprocessorEnvironment> ctx,
List<Mutation> mutations, WALEdit walEdit) {
if (ctx.getEnvironment().getRegion().getRegionInfo().getTableNameAsString()
.contains("testHDP3015")) {
if (delayPostBatchMutate) {
try {
latch.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
super.postBatchMutate(ctx, mutations, walEdit);
} else {
super.postBatchMutate(ctx, mutations, walEdit);
}
}
@Override
public void preFlush(ObserverContext<RegionCoprocessorEnvironment> e) throws IOException {
if (e.getEnvironment().getRegion().getRegionInfo().getTableNameAsString()
.contains("testHDP3015")) {
while (!delayPostBatchMutate) {
try {
Thread.sleep(200);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
super.preFlush(e);
latch.countDown();
} else {
super.preFlush(e);
}
}
}
public static class MoveThread extends Thread {
private HBaseAdmin admin;
byte[] regionName;
byte[] dstRSName;
public MoveThread(HBaseAdmin admin, byte[] regionName, byte[] dstRSName) {
this.admin = admin;
this.regionName = regionName;
this.dstRSName = dstRSName;
}
@Override
public void run() {
try {
this.admin.move(regionName, dstRSName);
} catch (UnknownRegionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (MasterNotRunningException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ZooKeeperConnectionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}