/**
* Copyright 2009 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.client.ccindex;
import java.io.IOException;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.Map.Entry;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.ColumnNameParseException;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.ZooKeeperConnectionException;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.KeyValue;
import org.apache.hadoop.hbase.MasterNotRunningException;
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.regionserver.ccindex.IndexMaintenanceUtils;
import org.apache.hadoop.hbase.util.Bytes;
/**
* Extension of HBaseAdmin that creates,updates,adds and removes CCIndex.
*
* @author liujia
* @version 90.0
*/
public class CCIndexAdmin extends HBaseAdmin {
private static final Log LOG = LogFactory.getLog(CCIndexAdmin.class);
/**
* Constructor
*
* @param conf
* Configuration object
* @throws MasterNotRunningException
* @throws ZooKeeperConnectionException
*/
public CCIndexAdmin(Configuration conf)
throws MasterNotRunningException, ZooKeeperConnectionException {
super(conf);
}
/**
* Creates a new indexed table
*
* @param desc
* table descriptor for table
*
* @throws IOException
*/
public void createIndexedTable(CCIndexDescriptor desc) throws IOException {
super.createTable(desc.getBaseTableDescriptor());
this.createIndexTables(desc);
}
private void updateInfoCCT(CCIndexDescriptor indexDesc)
{
HTableDescriptor baseTableDes=indexDesc.getBaseTableDescriptor();
byte[] baseTableName = indexDesc.getBaseTableDescriptor().getName();
boolean createOrg = false;
for (IndexSpecification indexSpec : indexDesc.getIndexes()) {
try {
if (!createOrg) {
HTableDescriptor indexTableDescO = createCCTDesc(baseTableDes,
indexSpec, true);
this.disableTable(indexTableDescO.getName());
super.modifyTable(indexTableDescO.getName(),indexTableDescO );
super.enableTable(indexTableDescO.getName());
createOrg = true;
}
HTableDescriptor indexTableDesc = createCCTDesc(baseTableDes,
indexSpec, false);
this.disableTable(indexTableDesc.getName());
super.modifyTable(indexTableDesc.getName(),indexTableDesc );
super.enableTable(indexTableDesc.getName());
} catch (ColumnNameParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private void createIndexTables(CCIndexDescriptor indexDesc)
throws IOException {
HTableDescriptor baseTableDes=indexDesc.getBaseTableDescriptor();
byte[] baseTableName = indexDesc.getBaseTableDescriptor().getName();
for (IndexSpecification indexSpec : indexDesc.getIndexes()) {
HTableDescriptor indexTableDesc = createCCITDesc(baseTableDes,
indexSpec);
LOG.info("create table :"+indexTableDesc);
super.createTable(indexTableDesc);
}
boolean createOrg = false;
for (IndexSpecification indexSpec : indexDesc.getIndexes()) {
if (!createOrg) {
HTableDescriptor indexTableDescO = createCCTDesc(baseTableDes,
indexSpec, true);
LOG.info("create table :"+indexTableDescO);
super.createTable(indexTableDescO);
createOrg = true;
}
HTableDescriptor indexTableDesc = createCCTDesc(baseTableDes,
indexSpec, false);
LOG.info("create table :"+indexTableDesc);
super.createTable(indexTableDesc);
}
}
/**
* create the desc for CCIT
* @param baseTableDesc
* @param indexSpec
* @return
* @throws ColumnNameParseException
*/
private HTableDescriptor createCCITDesc(HTableDescriptor baseTableDesc,
IndexSpecification indexSpec) throws ColumnNameParseException {
byte []baseTableName=baseTableDesc.getName();
HTableDescriptor indexTableDesc = new HTableDescriptor(indexSpec
.getCCITName());
Set<byte[]> families = new TreeSet<byte[]>(Bytes.BYTES_COMPARATOR);
families.add(CCIndexConstants.INDEX_COL_FAMILY_NAME);
for (byte[] column : indexSpec.getAllColumns()) {
byte[][]fq=KeyValue.parseColumn(column);
indexTableDesc.addFamily(new HColumnDescriptor(fq[0]));
}
for (byte[] colFamily : families) {
indexTableDesc.addFamily(new HColumnDescriptor(colFamily));
}
byte[] info = Bytes.add(baseTableName,
CCIndexConstants.ORGTABLE_COLUMN_DELIMITER, indexSpec
.getIndexedColumn());
indexTableDesc.setValue(CCIndexConstants.CCIT_KEY, info);
indexTableDesc.setValue(CCIndexConstants.INDEXES_KEY, baseTableDesc.getValue(CCIndexConstants.INDEXES_KEY));
return indexTableDesc;
}
private HTableDescriptor createCCTDesc(HTableDescriptor baseTableDesc,
IndexSpecification indexSpec, boolean org)
throws ColumnNameParseException {
byte []baseTableName=baseTableDesc.getName();
HTableDescriptor indexTableDesc=org?new HTableDescriptor(indexSpec
.getCCTNameBase(baseTableDesc.getName())):new HTableDescriptor(indexSpec
.getCCTName());
Set<byte[]> families = new TreeSet<byte[]>(Bytes.BYTES_COMPARATOR);
families.add(CCIndexConstants.INDEX_COL_FAMILY_NAME);
for (byte[] column : indexSpec.getIndexedColumns()) {
byte[][] fq=KeyValue.parseColumn(column);
families.add(fq[0]);
}
for (byte[] colFamily : families) {
//System.out.println(new String(colFamily));
indexTableDesc.addFamily(new HColumnDescriptor(colFamily));
}
byte[] info = Bytes.add(baseTableName, new byte[] {});
for (byte[] columns : indexSpec.getIndexedColumns()) {
info = Bytes.add(info, CCIndexConstants.ORGTABLE_COLUMN_DELIMITER,
columns);
}
indexTableDesc.setValue(CCIndexConstants.CCT_KEY, info);
indexTableDesc.setValue(CCIndexConstants.INDEXES_KEY, baseTableDesc.getValue(CCIndexConstants.INDEXES_KEY));
//indexTableDesc.setValue(key, value)
return indexTableDesc;
}
/**
* Remove an index for a table.
*
* @throws IOException
*
*/
public void removeIndex(byte[] baseTableName, byte[] indexId)
throws IOException {
super.disableTable(baseTableName);
HTableDescriptor desc = super.getTableDescriptor(baseTableName);
CCIndexDescriptor indexDesc = new CCIndexDescriptor(desc);
IndexSpecification spec = indexDesc.getIndex(indexId);
indexDesc.removeIndex(indexId);
this.disableTable(spec.getCCITName());
this.deleteTable(spec.getCCITName());
this.disableTable(spec.getCCTName());
this.deleteTable(spec.getCCTName());
super.modifyTable(baseTableName, desc);
super.enableTable(baseTableName);
this.updateInfoCCT(indexDesc);
}
/** Add an index to a table. */
public void addIndex(byte[] baseTableName, IndexSpecification indexSpec)
throws IOException {
LOG.warn("Adding index to existing table ["
+ Bytes.toString(baseTableName)
+ "], this may take a long time");
// TODO, make table read-only
LOG
.warn("Not putting table in readonly, if its being written to, the index may get out of sync");
HTable baseTable=new HTable(baseTableName);
HTableDescriptor baseDesc=baseTable.getTableDescriptor();
HTableDescriptor CCITDesc = createCCITDesc(baseDesc, indexSpec);
HTableDescriptor CCTDesc = createCCTDesc(baseDesc, indexSpec,false);
super.createTable(CCITDesc);
super.createTable(CCTDesc);
super.disableTable(baseTableName);
CCIndexDescriptor indexDesc = new CCIndexDescriptor(super
.getTableDescriptor(baseTableName));
indexDesc.addIndex(indexSpec);
super.modifyTable(baseTableName, indexDesc.getBaseTableDescriptor());
super.enableTable(baseTableName);
/* now is empty */
reIndexTable(baseTableName, indexSpec);
}
private void reIndexTable(byte[] baseTableName, IndexSpecification indexSpec)
throws IOException {
// HTable baseTable = new HTable(baseTableName);
// HTable indexTable = new
// HTable(indexSpec.getIndexedTableName(baseTableName));
// for (RowResult rowResult :
// baseTable.getScanner(indexSpec.getAllColumns())) {
// SortedMap<byte[], byte[]> columnValues = new TreeMap<byte[],
// byte[]>(Bytes.BYTES_COMPARATOR);
// for (Entry<byte[], Cell> entry : rowResult.entrySet()) {
// columnValues.put(entry.getKey(), entry.getValue().getValue());
// }
// if (IndexMaintenanceUtils.doesApplyToIndex(indexSpec, columnValues))
// {
// Put indexUpdate = IndexMaintenanceUtils.createIndexUpdate(indexSpec,
// rowResult.getRow(), columnValues);
// indexTable.put(indexUpdate);
// }
// }
}
}