/**
* 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.regionserver.ccindex;
import java.util.List;
import java.util.Map;
import java.util.NavigableMap;
import java.util.SortedMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.hbase.ColumnNameParseException;
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.KeyValue;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.client.Delete;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.ccindex.CCIndexConstants;
import org.apache.hadoop.hbase.client.ccindex.CCIndexDescriptor;
import org.apache.hadoop.hbase.client.ccindex.IndexSpecification;
import org.apache.hadoop.hbase.client.ccindex.IndexedTable;
import org.apache.hadoop.hbase.util.Bytes;
/**
* Singleton class for index maintence logic.
*/
public class IndexMaintenanceUtils {
private static final Log LOG = LogFactory
.getLog(IndexMaintenanceUtils.class);
public static Put createIndexUpdateMultTable(
final IndexSpecification indexSpec, final byte[] row,
final SortedMap<byte[], byte[]> columnValues, byte[] indexedColumn) {
for (byte[] col : indexSpec.getIndexedColumns()) {
if (columnValues.get(col) != null) {
}
}
return null;
}
public static Put addColumnValue(final IndexSpecification indexSpec,
final SortedMap<byte[], byte[]> columnValues, Put put) {
for (byte[] col : indexSpec.getAdditionalColumns()) {
byte[] val = columnValues.get(col);
if (val != null) {
byte[][] colSeperated = KeyValue.parseColumn(col);
put.add(colSeperated[0], colSeperated[1], val);
}
}
return put;
}
public static Put createCCITUpdate(final IndexSpecification indexSpec,
final byte[] row, final SortedMap<byte[], byte[]> columnValues) {
byte[] indexRow = indexSpec.getKeyGenerator().createIndexKey(row,
columnValues.get(indexSpec.getIndexedColumn()));
Put update = new Put(indexRow);
// update.add(IndexedTable.INDEX_COL_FAMILY_NAME,
// IndexedTable.INDEX_BASE_ROW, row);
for (byte[] col : indexSpec.getIndexedColumns()) {
byte[] val = columnValues.get(col);
if (val == null) {
throw new RuntimeException("Unexpected missing column value. ["
+ Bytes.toString(col) + "]");
}
byte[][] colSeperated = KeyValue.parseColumn(col);
update.add(colSeperated[0], colSeperated[1], val);
}
for (byte[] col : indexSpec.getAdditionalColumns()) {
byte[] val = columnValues.get(col);
if (val != null) {
byte[][] colSeperated = KeyValue.parseColumn(col);
update.add(colSeperated[0], colSeperated[1], val);
}
}
return update;
}
public static Put createBaseCCTUpdate(final byte[] row,
final SortedMap<byte[], byte[]> columnValues,
final CCIndexDescriptor des) {
Put update = new Put(row);
for (byte[] col : des.getIndexedColumns()) {
byte[] val = columnValues.get(col);
if (val != null) {
byte[][] colSeperated = KeyValue.parseColumn(col);
update.add(colSeperated[0], colSeperated[1], val);
}
// if (val != null&&!Bytes.equals(val, CCIndexConstants.EMPYT_ROW))
// {
// byte[][] colSeperated = KeyValue.parseColumn(col);
// update.add(colSeperated[0], colSeperated[1], val);
// }
}
return update;
}
public static Put createCCTUpdate(final IndexSpecification indexSpec,
final byte[] row, final SortedMap<byte[], byte[]> columnValues) {
byte[] indexRow = indexSpec.getKeyGenerator().createIndexKey(row,
columnValues.get(indexSpec.getIndexedColumn()));
Put update = new Put(indexRow);
for (byte[] col : indexSpec.getIndexedColumns()) {
byte[] val = columnValues.get(col);
if (val != null && !Bytes.equals(val, CCIndexConstants.EMPYT_VALUE)) {
byte[][] colSeperated = KeyValue.parseColumn(col);
update.add(colSeperated[0], colSeperated[1], val);
}
}
return update;
}
public static Delete getBaseCCTDelete(Delete delete, CCIndexDescriptor desc) {
byte[] row = delete.getRow();
if (delete.getFamilyMap().size() == 0) {
return new Delete(row);
}
Delete ret = new Delete(row);
Map<byte[], List<KeyValue>> familyMap = delete.getFamilyMap();
for (byte[] family : familyMap.keySet()) {
for (KeyValue kv : familyMap.get(family)) {
if (desc.getIndexedFamiliesSet().contains(kv.getFamily())) {
ret.deleteColumns(kv.getFamily(), kv.getQualifier(), kv
.getTimestamp());
}
}
}
return ret;
}
public static Delete getCCITDelete(Result oldValue, Delete delete,
IndexSpecification spec) {
byte[] row = delete.getRow();
byte[] columnV = oldValue.getValue(spec.getFamily(), spec.getColumn()) == null ? CCIndexConstants.EMPYT_VALUE
: oldValue.getValue(spec.getFamily(), spec.getColumn());
byte[] newRow = spec.getKeyGenerator().createIndexKey(row, columnV);
Delete ret = new Delete(newRow);
Map<byte[], List<KeyValue>> familyMap = delete.getFamilyMap();
for (byte[] family : familyMap.keySet()) {
for (KeyValue kv : familyMap.get(family)) {
ret.deleteColumns(kv.getFamily(), kv.getQualifier(), kv
.getTimestamp());
}
}
return ret;
}
public static Delete getCCTDelete(Result oldValue, Delete delete,
IndexSpecification spec) {
byte[] row = delete.getRow();
byte[] columnV = oldValue.getValue(spec.getFamily(), spec.getColumn()) == null ? CCIndexConstants.EMPYT_VALUE
: oldValue.getValue(spec.getFamily(), spec.getColumn());
byte[] newRow = spec.getKeyGenerator().createIndexKey(row, columnV);
Delete ret = new Delete(newRow);
Map<byte[], List<KeyValue>> familyMap = delete.getFamilyMap();
for (byte[] family : familyMap.keySet()) {
for (KeyValue kv : familyMap.get(family)) {
// if(Bytes.equals(spec.getFamily(),kv.getFamily()))
// {
if (!spec.getAdditionalFamily().contains(kv.getFamily()))
ret.deleteColumns(kv.getFamily(), kv.getQualifier(), kv
.getTimestamp());
// }
}
}
return ret;
}
public static Put recoverPutSimple(final byte[] row,
final SortedMap<byte[], byte[]> columnValues) {
byte[] indexRow = row;
Put update = null;
update = new Put(indexRow);
for (byte[] col : columnValues.keySet()) {
try {
byte[] val = columnValues.get(col);
byte[][] colSeperated = KeyValue.parseColumn(col);
update.add(colSeperated[0], colSeperated[1], val);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
continue;
}
}
return update;
}
public static Put recoverPut(final byte[] row,
final SortedMap<byte[], byte[]> columnValues,boolean isBase,CCIndexDescriptor des) {
byte[] indexRow = row;
Put update = null;
update = new Put(indexRow);
if(!isBase)
{
for(IndexSpecification spec:des.getIndexes())
{
if(columnValues.get(spec.getIndexedColumn())==null)
{
columnValues.put(spec.getIndexedColumn(), CCIndexConstants.EMPYT_VALUE);
}
}
}
for (byte[] col : columnValues.keySet()) {
try {
byte[] val = columnValues.get(col);
if(isBase&&Bytes.compareTo(val, CCIndexConstants.EMPYT_VALUE)==0)
continue;
byte[][] colSeperated = KeyValue.parseColumn(col);
update.add(colSeperated[0], colSeperated[1], val);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
continue;
}
}
return update;
}
/**
* Ask if this update does apply to the index.
*
* @param indexSpec
* @param columnValues
* @return true if possibly apply.
*/
public static boolean doesApplyToIndex(final IndexSpecification indexSpec,
final SortedMap<byte[], byte[]> columnValues) {
for (byte[] neededCol : indexSpec.getIndexedColumns()) {
if (!columnValues.containsKey(neededCol)) {
LOG.debug("Index [" + indexSpec.getIndexId()
+ "] can't be updated because ["
+ Bytes.toString(neededCol) + "] is missing");
return false;
}
}
return true;
}
}