blob: 6f60f7f519037c65da709284e315e4d139d157e3 [file] [log] [blame]
/*
* 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.phoenix.hbase.index.covered.example;
import static org.apache.phoenix.query.BaseTest.setUpConfigForMiniCluster;
import static org.junit.Assert.fail;
import java.io.IOException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.DoNotRetryIOException;
import org.apache.hadoop.hbase.HBaseTestingUtility;
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.client.HBaseAdmin;
import org.apache.hadoop.hbase.client.HTable;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.RetriesExhaustedWithDetailsException;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.phoenix.end2end.NeedsOwnMiniClusterTest;
import org.apache.phoenix.hbase.index.IndexTestingUtils;
import org.apache.phoenix.hbase.index.Indexer;
import org.apache.phoenix.hbase.index.TableName;
import org.apache.phoenix.hbase.index.builder.BaseIndexCodec;
import org.apache.phoenix.hbase.index.covered.IndexMetaData;
import org.apache.phoenix.hbase.index.covered.IndexUpdate;
import org.apache.phoenix.hbase.index.covered.TableState;
import org.apache.phoenix.hbase.index.util.IndexManagementUtil;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
/**
* If {@link DoNotRetryIOException} is not subclassed correctly (with the {@link String} constructor),
* {@link MultiResponse#readFields(java.io.DataInput)} will not correctly deserialize the exception, and just return
* <tt>null</tt> to the client, which then just goes and retries.
*/
@Category(NeedsOwnMiniClusterTest.class)
public class FailWithoutRetriesIT {
private static final Log LOG = LogFactory.getLog(FailWithoutRetriesIT.class);
@Rule
public TableName table = new TableName();
private static final HBaseTestingUtility UTIL = new HBaseTestingUtility();
private String getIndexTableName() {
return Bytes.toString(table.getTableName()) + "_index";
}
public static class FailingTestCodec extends BaseIndexCodec {
@Override
public Iterable<IndexUpdate> getIndexDeletes(TableState state, IndexMetaData context) throws IOException {
throw new RuntimeException("Intentionally failing deletes for " + FailWithoutRetriesIT.class.getName());
}
@Override
public Iterable<IndexUpdate> getIndexUpserts(TableState state, IndexMetaData context) throws IOException {
throw new RuntimeException("Intentionally failing upserts for " + FailWithoutRetriesIT.class.getName());
}
}
@BeforeClass
public static void setupCluster() throws Exception {
// setup and verify the config
Configuration conf = UTIL.getConfiguration();
setUpConfigForMiniCluster(conf);
IndexTestingUtils.setupConfig(conf);
IndexManagementUtil.ensureMutableIndexingCorrectlyConfigured(conf);
// start the cluster
UTIL.startMiniCluster();
}
/**
* If this test times out, then we didn't fail quickly enough. {@link Indexer} maybe isn't rethrowing the exception
* correctly?
* <p>
* We use a custom codec to enforce the thrown exception.
*
* @throws Exception
*/
@Test(timeout = 300000)
public void testQuickFailure() throws Exception {
// incorrectly setup indexing for the primary table - target index table doesn't exist, which
// should quickly return to the client
byte[] family = Bytes.toBytes("family");
ColumnGroup fam1 = new ColumnGroup(getIndexTableName());
// values are [col1]
fam1.add(new CoveredColumn(family, CoveredColumn.ALL_QUALIFIERS));
CoveredColumnIndexSpecifierBuilder builder = new CoveredColumnIndexSpecifierBuilder();
// add the index family
builder.addIndexGroup(fam1);
// usually, we would create the index table here, but we don't for the sake of the test.
// setup the primary table
String primaryTable = Bytes.toString(table.getTableName());
@SuppressWarnings("deprecation")
HTableDescriptor pTable = new HTableDescriptor(primaryTable);
pTable.addFamily(new HColumnDescriptor(family));
// override the codec so we can use our test one
builder.build(pTable, FailingTestCodec.class);
// create the primary table
HBaseAdmin admin = UTIL.getHBaseAdmin();
admin.createTable(pTable);
Configuration conf = new Configuration(UTIL.getConfiguration());
// up the number of retries/wait time to make it obvious that we are failing with retries here
conf.setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, 20);
conf.setLong(HConstants.HBASE_CLIENT_PAUSE, 1000);
HTable primary = new HTable(conf, primaryTable);
primary.setAutoFlush(false, true);
// do a simple put that should be indexed
Put p = new Put(Bytes.toBytes("row"));
p.add(family, null, Bytes.toBytes("value"));
primary.put(p);
try {
primary.flushCommits();
fail("Shouldn't have gotten a successful write to the primary table");
} catch (RetriesExhaustedWithDetailsException e) {
LOG.info("Correclty got a failure of the put!");
}
primary.close();
}
}