blob: b1b3bd9e2197f4b2d32d051f3e8cc01faaa47833 [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.gora.hbase.store;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor;
import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder.ModifyableColumnFamilyDescriptor;
import org.apache.hadoop.hbase.client.TableDescriptor;
import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
import org.apache.hadoop.hbase.io.compress.Compression.Algorithm;
import org.apache.hadoop.hbase.regionserver.BloomType;
import org.apache.hadoop.hbase.util.Bytes;
/**
* Mapping definitions for HBase. Thread safe.
* It holds a definition for a single table.
*/
public class HBaseMapping {
private final TableDescriptor tableDescriptor;
// a map from field name to hbase column
private final Map<String, HBaseColumn> columnMap;
public HBaseMapping(TableDescriptor tableDescriptor,
Map<String, HBaseColumn> columnMap) {
super();
this.tableDescriptor = tableDescriptor;
this.columnMap = columnMap;
}
public String getTableName() {
return tableDescriptor.getTableName().getNameAsString();
}
public TableDescriptor getTable() {
return tableDescriptor;
}
public HBaseColumn getColumn(String fieldName) {
return columnMap.get(fieldName);
}
/**
* A builder for creating the mapper. This will allow building a thread safe
* {@link HBaseMapping} using simple immutability.
*
*/
public static class HBaseMappingBuilder {
private Map<String, Map<String, ColumnFamilyDescriptor>> tableToFamilies =
new HashMap<>();
private Map<String, HBaseColumn> columnMap =
new HashMap<>();
private TableName tableName;
public String getTableName() {
return tableName.getNameAsString();
}
public void setTableName(String tableName) {
this.tableName = TableName.valueOf(tableName);
}
public void addFamilyProps(String tableName, String familyName,
String compression, String blockCache, String blockSize,
String bloomFilter ,String maxVersions, String timeToLive,
String inMemory) {
// We keep track of all tables, because even though we
// only build a mapping for one table. We do this because of the way
// the mapping file is set up.
// (First family properties are defined, whereafter columns are defined).
//
// HBaseMapping in fact does not need to support multiple tables,
// because a Store itself only supports a single table. (Every store
// instance simply creates one mapping instance for itself).
//
// TODO A nice solution would be to redefine the mapping file structure.
// For example nest columns in families. Of course this would break compatibility.
Map<String, ColumnFamilyDescriptor> families = getOrCreateFamilies(tableName);
ColumnFamilyDescriptor columnDescriptor = getOrCreateFamily(familyName, families);
ModifyableColumnFamilyDescriptor modifyableColFamilyDescriptor =
(ModifyableColumnFamilyDescriptor) columnDescriptor;
if(compression != null)
modifyableColFamilyDescriptor.setCompressionType(Algorithm.valueOf(compression));
if(blockCache != null)
modifyableColFamilyDescriptor.setBlockCacheEnabled(Boolean.parseBoolean(blockCache));
if(blockSize != null)
modifyableColFamilyDescriptor.setBlocksize(Integer.parseInt(blockSize));
if(bloomFilter != null)
modifyableColFamilyDescriptor.setBloomFilterType(BloomType.valueOf(bloomFilter));
if(maxVersions != null)
modifyableColFamilyDescriptor.setMaxVersions(Integer.parseInt(maxVersions));
if(timeToLive != null)
modifyableColFamilyDescriptor.setTimeToLive(Integer.parseInt(timeToLive));
if(inMemory != null)
modifyableColFamilyDescriptor.setInMemory(Boolean.parseBoolean(inMemory));
}
public void addColumnFamily(String tableName, String familyName) {
Map<String, ColumnFamilyDescriptor> families = getOrCreateFamilies(tableName);
getOrCreateFamily(familyName, families);
}
public void addField(String fieldName, String family, String qualifier) {
byte[] familyBytes = Bytes.toBytes(family);
byte[] qualifierBytes = qualifier == null ? null :
Bytes.toBytes(qualifier);
HBaseColumn column = new HBaseColumn(familyBytes, qualifierBytes);
columnMap.put(fieldName, column);
}
private ColumnFamilyDescriptor getOrCreateFamily(String familyName,
Map<String, ColumnFamilyDescriptor> families) {
ColumnFamilyDescriptor columnDescriptor = families.get(familyName);
if (columnDescriptor == null) {
ColumnFamilyDescriptorBuilder columnDescBuilder = ColumnFamilyDescriptorBuilder
.newBuilder(Bytes.toBytes(familyName));
columnDescriptor = columnDescBuilder.build();
families.put(familyName, columnDescriptor);
}
return columnDescriptor;
}
private Map<String, ColumnFamilyDescriptor> getOrCreateFamilies(String tableName) {
Map<String, ColumnFamilyDescriptor> families;
families = tableToFamilies.get(tableName);
if (families == null) {
families = new HashMap<>();
tableToFamilies.put(tableName, families);
}
return families;
}
public void renameTable(String oldName, String newName) {
Map<String, ColumnFamilyDescriptor> families = tableToFamilies.remove(oldName);
if (families == null) throw new IllegalArgumentException(oldName + " does not exist");
tableToFamilies.put(newName, families);
}
/**
* @return A newly constructed mapping.
*/
public HBaseMapping build() {
if (tableName == null) throw new IllegalStateException("tableName is not specified");
Map<String, ColumnFamilyDescriptor> families = tableToFamilies.get(tableName.getNameAsString());
if (families == null) throw new IllegalStateException("no families for table " + tableName);
TableDescriptorBuilder tableDescBuilder = TableDescriptorBuilder.newBuilder(tableName);
for (ColumnFamilyDescriptor familyDescriptor : families.values()) {
tableDescBuilder.setColumnFamily(familyDescriptor);
}
TableDescriptor tableDescriptor = tableDescBuilder.build();
return new HBaseMapping(tableDescriptor, columnMap);
}
}
public String toString() {
StringBuilder strBuilder = new StringBuilder();
strBuilder.append(this.getTableName());
strBuilder.append("\n");
for (Entry<String, HBaseColumn> mappingEntry : this.columnMap.entrySet()) {
byte[] familyBytes = mappingEntry.getValue().getFamily() == null ? new byte[0] : mappingEntry.getValue().getFamily() ;
byte[] qualifierBytes = mappingEntry.getValue().getQualifier() == null ? new byte[0] : mappingEntry.getValue().getQualifier() ;
strBuilder.append(mappingEntry.getKey() + " -> " + new String(familyBytes, StandardCharsets.UTF_8) + ":" + new String(qualifierBytes, StandardCharsets.UTF_8)) ;
strBuilder.append("\n");
}
return strBuilder.toString() ;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
HBaseMapping that = (HBaseMapping) o;
return Objects.equals(tableDescriptor, that.tableDescriptor) &&
Objects.equals(columnMap, that.columnMap);
}
@Override
public int hashCode() {
return Objects.hash(tableDescriptor, columnMap);
}
}