/*
* Copyright 2013 NGDATA nv
*
* Licensed 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.lilyproject.util.hbase;
import java.util.regex.Pattern;
import org.apache.hadoop.hbase.HTableDescriptor;
/**
* Utility that handles the mapping between repository/table names and HBase storage table names.
*/
public class RepoAndTableUtil {
public static final String DEFAULT_REPOSITORY = "default";
/**
* Separator between repository name and table name in the HBase table name.
*/
public static final String REPOSITORY_TABLE_SEPARATOR = "__";
// About these restrictions: HBase itself is very restrictive on table names. In addition, we don't allow dots
// and colons because these can cause issues parsing absolute link values.
private static final String VALID_NAME_PATTERN = "[a-zA-Z_0-9-.]+";
private static final Pattern VALID_NAME_CHARS = Pattern.compile(VALID_NAME_PATTERN);
public static final String VALID_NAME_EXPLANATION = "A valid name should follow the regex " + VALID_NAME_PATTERN
+ " and not contain " + REPOSITORY_TABLE_SEPARATOR + ".";
static final String OWNING_REPOSITORY_KEY = "lilyOwningRepository";
/**
* Checks if a table is owned by a certain repository. Assumes the passed table name is a record table name,
* i.e. this does not filter out any other tables that might exist in HBase.
*/
public static final boolean belongsToRepository(String hbaseTableName, String repositoryName) {
if (repositoryName.equals(DEFAULT_REPOSITORY)) {
return !hbaseTableName.contains(REPOSITORY_TABLE_SEPARATOR);
} else {
return hbaseTableName.startsWith(repositoryName + REPOSITORY_TABLE_SEPARATOR);
}
}
public static String getHBaseTableName(String repositoryName, String tableName) {
if (! isValidTableName(tableName)) throw new IllegalArgumentException("Bad table name: " + tableName);
if (! isValidTableName(repositoryName)) throw new IllegalArgumentException("Bad repository name: " + repositoryName);
if (repositoryName.equals(DEFAULT_REPOSITORY)) {
// Tables within the default repository are not prefixed with the repository name, because of backwards
// compatibility with the pre-multiple-repositories situation.
return tableName;
} else {
return repositoryName + REPOSITORY_TABLE_SEPARATOR + tableName;
}
}
public static boolean isValidTableName(String name) {
return VALID_NAME_CHARS.matcher(name).matches() && !name.contains(REPOSITORY_TABLE_SEPARATOR);
}
private static boolean isDefaultRepository(String name) {
return DEFAULT_REPOSITORY.equals(name);
}
public static String extractLilyTableName(String repositoryName, String hbaseTableName) {
if (isDefaultRepository(repositoryName)) {
return hbaseTableName;
} else {
String prefix = repositoryName + REPOSITORY_TABLE_SEPARATOR;
if (!hbaseTableName.startsWith(prefix)) {
throw new IllegalArgumentException(String.format("HBase table '%s' does not belong to repository '%s'",
hbaseTableName, repositoryName));
}
return hbaseTableName.substring(prefix.length());
}
}
/**
* Splits an HBase table name into Lily repository and table names. Assumes the provided HBase table name is a valid
* Lily record table (should be check on beforehand).
*
* @return an array of size 2: first element is repository name, second is table name
*/
public static String[] getRepositoryAndTable(String hbaseTableName) {
int pos = hbaseTableName.indexOf(REPOSITORY_TABLE_SEPARATOR);
if (pos == -1) {
return new String[] {DEFAULT_REPOSITORY, hbaseTableName };
} else {
String repository = hbaseTableName.substring(0, pos);
String table = hbaseTableName.substring(pos + REPOSITORY_TABLE_SEPARATOR.length());
return new String[] { repository, table };
}
}
/**
* Mark a table descriptor as being owned by a repository. This method is intended to be used before the
* table defined by the descriptor is created.
*
* @param tableDescriptor descriptor of a table to be created
* @param repositoryName name of the repository to which the table will belong
*/
public static void setRepositoryOwnership(HTableDescriptor tableDescriptor, String repositoryName) {
String existingValue = tableDescriptor.getValue(OWNING_REPOSITORY_KEY);
if (existingValue != null && !existingValue.equals(repositoryName)) {
throw new IllegalStateException("Table descriptor already belongs to repository '"
+ existingValue + "', can't set owning repository to " + repositoryName);
}
tableDescriptor.setValue(OWNING_REPOSITORY_KEY, repositoryName);
}
/**
* Get the name of the owning repository for a table descriptor.
*
* @param tableDescriptor descriptor for which the owning repository is to be retrieved
* @return the owning repository
*/
public static String getOwningRepository(HTableDescriptor tableDescriptor) {
return tableDescriptor.getValue(OWNING_REPOSITORY_KEY);
}
}