in server/manager/src/main/java/org/apache/accumulo/manager/FateServiceHandler.java [139:790]
public void executeFateOperation(TInfo tinfo, TCredentials c, TFateId opid, TFateOperation top,
List<ByteBuffer> arguments, Map<String,String> options, boolean autoCleanup)
throws ThriftSecurityException, ThriftTableOperationException, ThriftPropertyException {
authenticate(c);
Fate.FateOperation op = Fate.FateOperation.fromThrift(top);
String goalMessage = op.toString() + " ";
String txUUIDStr = opid.getTxUUIDStr();
FateInstanceType type = FateInstanceType.fromThrift(opid.getType());
FateId fateId = FateId.from(type, txUUIDStr);
switch (op) {
case NAMESPACE_CREATE: {
TableOperation tableOp = TableOperation.CREATE;
validateArgumentCount(arguments, tableOp, 1);
String namespace = validateName(arguments.get(0), tableOp, NEW_NAMESPACE_NAME);
if (!security.canCreateNamespace(c)) {
throw new ThriftSecurityException(c.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED);
}
goalMessage += "Create " + namespace + " namespace.";
manager.fate(type).seedTransaction(op, fateId,
new TraceRepo<>(new CreateNamespace(c.getPrincipal(), namespace, options)), autoCleanup,
goalMessage);
break;
}
case NAMESPACE_RENAME: {
TableOperation tableOp = TableOperation.RENAME;
validateArgumentCount(arguments, tableOp, 2);
String oldName = validateName(arguments.get(0), tableOp,
EXISTING_NAMESPACE_NAME.and(NOT_BUILTIN_NAMESPACE));
String newName = validateName(arguments.get(1), tableOp, NEW_NAMESPACE_NAME);
NamespaceId namespaceId =
ClientServiceHandler.checkNamespaceId(manager.getContext(), oldName, tableOp);
if (!security.canRenameNamespace(c, namespaceId)) {
throw new ThriftSecurityException(c.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED);
}
goalMessage += "Rename " + oldName + " namespace to " + newName;
manager.fate(type).seedTransaction(op, fateId,
new TraceRepo<>(new RenameNamespace(namespaceId, oldName, newName)), autoCleanup,
goalMessage);
break;
}
case NAMESPACE_DELETE: {
TableOperation tableOp = TableOperation.DELETE;
validateArgumentCount(arguments, tableOp, 1);
String namespace = validateName(arguments.get(0), tableOp,
EXISTING_NAMESPACE_NAME.and(NOT_BUILTIN_NAMESPACE));
NamespaceId namespaceId =
ClientServiceHandler.checkNamespaceId(manager.getContext(), namespace, tableOp);
if (!security.canDeleteNamespace(c, namespaceId)) {
throw new ThriftSecurityException(c.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED);
}
goalMessage += "Delete namespace Id: " + namespaceId;
manager.fate(type).seedTransaction(op, fateId,
new TraceRepo<>(new DeleteNamespace(namespaceId)), autoCleanup, goalMessage);
break;
}
case TABLE_CREATE: {
TableOperation tableOp = TableOperation.CREATE;
int SPLIT_OFFSET = 5; // offset where split data begins in arguments list
if (arguments.size() < SPLIT_OFFSET) {
throw new ThriftTableOperationException(null, null, tableOp,
TableOperationExceptionType.OTHER,
"Expected at least " + SPLIT_OFFSET + " arguments, saw :" + arguments.size());
}
String tableName =
validateName(arguments.get(0), tableOp, NEW_TABLE_NAME.and(NOT_BUILTIN_TABLE));
TimeType timeType = TimeType.valueOf(ByteBufferUtil.toString(arguments.get(1)));
InitialTableState initialTableState =
InitialTableState.valueOf(ByteBufferUtil.toString(arguments.get(2)));
TabletAvailability initialTabletAvailability =
TabletAvailability.valueOf(ByteBufferUtil.toString(arguments.get(3)));
int splitCount = Integer.parseInt(ByteBufferUtil.toString(arguments.get(4)));
validateArgumentCount(arguments, tableOp, SPLIT_OFFSET + splitCount);
Path splitsPath = null;
Path splitsDirsPath = null;
if (splitCount > 0) {
try {
Path tmpDir = mkTempDir(opid);
splitsPath = new Path(tmpDir, "splits");
splitsDirsPath = new Path(tmpDir, "splitsDirs");
writeSplitsToFile(splitsPath, arguments, splitCount, SPLIT_OFFSET);
} catch (IOException e) {
throw new ThriftTableOperationException(null, tableName, tableOp,
TableOperationExceptionType.OTHER,
"Exception thrown while writing splits to file system");
}
}
NamespaceId namespaceId = ClientServiceHandler.checkNamespaceId(manager.getContext(),
TableNameUtil.qualify(tableName).getFirst(), tableOp);
if (!security.canCreateTable(c, tableName, namespaceId)) {
throw new ThriftSecurityException(c.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED);
}
for (Map.Entry<String,String> entry : options.entrySet()) {
if (!Property.isValidProperty(entry.getKey(), entry.getValue())) {
String errorMessage = "Property or value not valid ";
if (!Property.isValidTablePropertyKey(entry.getKey())) {
errorMessage = "Invalid Table Property ";
}
throw new ThriftPropertyException(entry.getKey(), entry.getValue(),
errorMessage + entry.getKey() + "=" + entry.getValue());
}
}
goalMessage += "Create table " + tableName + " " + initialTableState + " with " + splitCount
+ " splits and initial tabletAvailability of " + initialTabletAvailability;
manager.fate(type).seedTransaction(op, fateId,
new TraceRepo<>(new CreateTable(c.getPrincipal(), tableName, timeType, options,
splitsPath, splitCount, splitsDirsPath, initialTableState,
// Set the default tablet to be auto-mergeable with other tablets if it is split
initialTabletAvailability, namespaceId, TabletMergeability.always())),
autoCleanup, goalMessage);
break;
}
case TABLE_RENAME: {
TableOperation tableOp = TableOperation.RENAME;
validateArgumentCount(arguments, tableOp, 2);
String oldTableName =
validateName(arguments.get(0), tableOp, EXISTING_TABLE_NAME.and(NOT_BUILTIN_TABLE));
String newTableName = validateName(arguments.get(1), tableOp,
NEW_TABLE_NAME.and(sameNamespaceAs(oldTableName)));
TableId tableId =
ClientServiceHandler.checkTableId(manager.getContext(), oldTableName, tableOp);
NamespaceId namespaceId = getNamespaceIdFromTableId(tableOp, tableId);
final boolean canRename;
try {
canRename = security.canRenameTable(c, tableId, oldTableName, newTableName, namespaceId);
} catch (ThriftSecurityException e) {
throwIfTableMissingSecurityException(e, tableId, oldTableName, TableOperation.RENAME);
throw e;
}
if (!canRename) {
throw new ThriftSecurityException(c.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED);
}
goalMessage += "Rename table " + oldTableName + "(" + tableId + ") to " + oldTableName;
try {
manager.fate(type).seedTransaction(op, fateId,
new TraceRepo<>(new RenameTable(namespaceId, tableId, oldTableName, newTableName)),
autoCleanup, goalMessage);
} catch (NamespaceNotFoundException e) {
throw new ThriftTableOperationException(null, oldTableName, tableOp,
TableOperationExceptionType.NAMESPACE_NOTFOUND, "");
}
break;
}
case TABLE_CLONE: {
TableOperation tableOp = TableOperation.CLONE;
validateArgumentCount(arguments, tableOp, 3);
TableId srcTableId = validateTableIdArgument(arguments.get(0), tableOp, CAN_CLONE_TABLE);
String tableName =
validateName(arguments.get(1), tableOp, NEW_TABLE_NAME.and(NOT_BUILTIN_TABLE));
boolean keepOffline = false;
if (arguments.get(2) != null) {
keepOffline = Boolean.parseBoolean(ByteBufferUtil.toString(arguments.get(2)));
}
NamespaceId srcNamespaceId;
try {
srcNamespaceId = manager.getContext().getNamespaceId(srcTableId);
} catch (TableNotFoundException e) {
// could happen if the table was deleted while processing this request
throw new ThriftTableOperationException(srcTableId.canonical(), null, tableOp,
TableOperationExceptionType.NOTFOUND, "");
}
NamespaceId namespaceId = ClientServiceHandler.checkNamespaceId(manager.getContext(),
TableNameUtil.qualify(tableName).getFirst(), tableOp);
final boolean canCloneTable;
try {
canCloneTable =
security.canCloneTable(c, srcTableId, tableName, namespaceId, srcNamespaceId);
} catch (ThriftSecurityException e) {
throwIfTableMissingSecurityException(e, srcTableId, null, TableOperation.CLONE);
throw e;
}
if (!canCloneTable) {
throw new ThriftSecurityException(c.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED);
}
Map<String,String> propertiesToSet = new HashMap<>();
Set<String> propertiesToExclude = new HashSet<>();
for (Entry<String,String> entry : options.entrySet()) {
if (entry.getKey().startsWith(TableOperationsImpl.PROPERTY_EXCLUDE_PREFIX)) {
propertiesToExclude.add(
entry.getKey().substring(TableOperationsImpl.PROPERTY_EXCLUDE_PREFIX.length()));
continue;
}
if (!Property.isValidProperty(entry.getKey(), entry.getValue())) {
String errorMessage = "Property or value not valid ";
if (!Property.isValidTablePropertyKey(entry.getKey())) {
errorMessage = "Invalid Table Property ";
}
throw new ThriftPropertyException(entry.getKey(), entry.getValue(),
errorMessage + entry.getKey() + "=" + entry.getValue());
}
propertiesToSet.put(entry.getKey(), entry.getValue());
}
goalMessage += "Clone table " + srcTableId + " to " + tableName;
if (keepOffline) {
goalMessage += " and keep offline.";
}
manager.fate(type).seedTransaction(op, fateId,
new TraceRepo<>(new CloneTable(c.getPrincipal(), srcNamespaceId, srcTableId,
namespaceId, tableName, propertiesToSet, propertiesToExclude, keepOffline)),
autoCleanup, goalMessage);
break;
}
case TABLE_DELETE: {
TableOperation tableOp = TableOperation.DELETE;
validateArgumentCount(arguments, tableOp, 1);
String tableName =
validateName(arguments.get(0), tableOp, EXISTING_TABLE_NAME.and(NOT_BUILTIN_TABLE));
final TableId tableId =
ClientServiceHandler.checkTableId(manager.getContext(), tableName, tableOp);
NamespaceId namespaceId = getNamespaceIdFromTableId(tableOp, tableId);
final boolean canDeleteTable;
try {
canDeleteTable = security.canDeleteTable(c, tableId, namespaceId);
} catch (ThriftSecurityException e) {
throwIfTableMissingSecurityException(e, tableId, tableName, TableOperation.DELETE);
throw e;
}
if (!canDeleteTable) {
throw new ThriftSecurityException(c.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED);
}
goalMessage += "Delete table " + tableName + "(" + tableId + ")";
manager.fate(type).seedTransaction(op, fateId,
new TraceRepo<>(new PreDeleteTable(namespaceId, tableId)), autoCleanup, goalMessage);
break;
}
case TABLE_ONLINE: {
TableOperation tableOp = TableOperation.ONLINE;
validateArgumentCount(arguments, tableOp, 1);
final var tableId =
validateTableIdArgument(arguments.get(0), tableOp, NOT_BUILTIN_TABLE_ID);
NamespaceId namespaceId = getNamespaceIdFromTableId(tableOp, tableId);
final boolean canOnlineOfflineTable;
try {
canOnlineOfflineTable = security.canChangeTableState(c, tableId, top, namespaceId);
} catch (ThriftSecurityException e) {
throwIfTableMissingSecurityException(e, tableId, null, TableOperation.ONLINE);
throw e;
}
if (!canOnlineOfflineTable) {
throw new ThriftSecurityException(c.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED);
}
goalMessage += "Online table " + tableId;
final EnumSet<TableState> expectedCurrStates =
EnumSet.of(TableState.ONLINE, TableState.OFFLINE);
manager.fate(type).seedTransaction(op, fateId,
new TraceRepo<>(
new ChangeTableState(namespaceId, tableId, tableOp, expectedCurrStates)),
autoCleanup, goalMessage);
break;
}
case TABLE_OFFLINE: {
TableOperation tableOp = TableOperation.OFFLINE;
validateArgumentCount(arguments, tableOp, 1);
final var tableId =
validateTableIdArgument(arguments.get(0), tableOp, NOT_BUILTIN_TABLE_ID);
NamespaceId namespaceId = getNamespaceIdFromTableId(tableOp, tableId);
final boolean canOnlineOfflineTable;
try {
canOnlineOfflineTable = security.canChangeTableState(c, tableId, top, namespaceId);
} catch (ThriftSecurityException e) {
throwIfTableMissingSecurityException(e, tableId, null, TableOperation.OFFLINE);
throw e;
}
if (!canOnlineOfflineTable) {
throw new ThriftSecurityException(c.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED);
}
goalMessage += "Offline table " + tableId;
final EnumSet<TableState> expectedCurrStates =
EnumSet.of(TableState.ONLINE, TableState.OFFLINE);
manager.fate(type).seedTransaction(op, fateId,
new TraceRepo<>(
new ChangeTableState(namespaceId, tableId, tableOp, expectedCurrStates)),
autoCleanup, goalMessage);
break;
}
case TABLE_MERGE: {
TableOperation tableOp = TableOperation.MERGE;
validateArgumentCount(arguments, tableOp, 3);
String tableName = validateName(arguments.get(0), tableOp, EXISTING_TABLE_NAME);
Text startRow = ByteBufferUtil.toText(arguments.get(1));
Text endRow = ByteBufferUtil.toText(arguments.get(2));
final TableId tableId =
ClientServiceHandler.checkTableId(manager.getContext(), tableName, tableOp);
NamespaceId namespaceId = getNamespaceIdFromTableId(tableOp, tableId);
final boolean canMerge;
try {
canMerge = security.canMerge(c, tableId, namespaceId);
} catch (ThriftSecurityException e) {
throwIfTableMissingSecurityException(e, tableId, tableName, TableOperation.MERGE);
throw e;
}
if (!canMerge) {
throw new ThriftSecurityException(c.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED);
}
String startRowStr = StringUtils.defaultIfBlank(startRow.toString(), "-inf");
String endRowStr = StringUtils.defaultIfBlank(startRow.toString(), "+inf");
Manager.log.debug("Creating merge op: {} from startRow: {} to endRow: {}", tableId,
startRowStr, endRowStr);
goalMessage += "Merge table " + tableName + "(" + tableId + ") splits from " + startRowStr
+ " to " + endRowStr;
manager.fate(type).seedTransaction(op, fateId, new TraceRepo<>(
new TableRangeOp(MergeInfo.Operation.MERGE, namespaceId, tableId, startRow, endRow)),
autoCleanup, goalMessage);
break;
}
case TABLE_DELETE_RANGE: {
TableOperation tableOp = TableOperation.DELETE_RANGE;
validateArgumentCount(arguments, tableOp, 3);
String tableName =
validateName(arguments.get(0), tableOp, NOT_BUILTIN_TABLE.and(EXISTING_TABLE_NAME));
Text startRow = ByteBufferUtil.toText(arguments.get(1));
Text endRow = ByteBufferUtil.toText(arguments.get(2));
final TableId tableId =
ClientServiceHandler.checkTableId(manager.getContext(), tableName, tableOp);
NamespaceId namespaceId = getNamespaceIdFromTableId(tableOp, tableId);
final boolean canDeleteRange;
try {
canDeleteRange =
security.canDeleteRange(c, tableId, tableName, startRow, endRow, namespaceId);
} catch (ThriftSecurityException e) {
throwIfTableMissingSecurityException(e, tableId, tableName, TableOperation.DELETE_RANGE);
throw e;
}
if (!canDeleteRange) {
throw new ThriftSecurityException(c.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED);
}
goalMessage +=
"Delete table " + tableName + "(" + tableId + ") range " + startRow + " to " + endRow;
manager.fate(type).seedTransaction(op, fateId, new TraceRepo<>(
new TableRangeOp(MergeInfo.Operation.DELETE, namespaceId, tableId, startRow, endRow)),
autoCleanup, goalMessage);
break;
}
case TABLE_COMPACT: {
TableOperation tableOp = TableOperation.COMPACT;
validateArgumentCount(arguments, tableOp, 2);
TableId tableId = validateTableIdArgument(arguments.get(0), tableOp, null);
CompactionConfig compactionConfig =
UserCompactionUtils.decodeCompactionConfig(ByteBufferUtil.toBytes(arguments.get(1)));
NamespaceId namespaceId = getNamespaceIdFromTableId(tableOp, tableId);
final boolean canCompact;
try {
canCompact = security.canCompact(c, tableId, namespaceId);
} catch (ThriftSecurityException e) {
throwIfTableMissingSecurityException(e, tableId, null, TableOperation.COMPACT);
throw e;
}
if (!canCompact) {
throw new ThriftSecurityException(c.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED);
}
goalMessage += "Compact table (" + tableId + ") with config " + compactionConfig;
manager.fate(type).seedTransaction(op, fateId,
new TraceRepo<>(new CompactRange(namespaceId, tableId, compactionConfig)), autoCleanup,
goalMessage);
break;
}
case TABLE_CANCEL_COMPACT: {
TableOperation tableOp = TableOperation.COMPACT_CANCEL;
validateArgumentCount(arguments, tableOp, 1);
TableId tableId = validateTableIdArgument(arguments.get(0), tableOp, null);
NamespaceId namespaceId = getNamespaceIdFromTableId(tableOp, tableId);
final boolean canCancelCompact;
try {
canCancelCompact = security.canCompact(c, tableId, namespaceId);
} catch (ThriftSecurityException e) {
throwIfTableMissingSecurityException(e, tableId, null, TableOperation.COMPACT_CANCEL);
throw e;
}
if (!canCancelCompact) {
throw new ThriftSecurityException(c.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED);
}
goalMessage += "Cancel compaction of table (" + tableId + ")";
manager.fate(type).seedTransaction(op, fateId,
new TraceRepo<>(new CancelCompactions(namespaceId, tableId)), autoCleanup, goalMessage);
break;
}
case TABLE_IMPORT: {
TableOperation tableOp = TableOperation.IMPORT;
int IMPORT_DIR_OFFSET = 2; // offset where table list begins
if (arguments.size() < IMPORT_DIR_OFFSET) {
throw new ThriftTableOperationException(null, null, tableOp,
TableOperationExceptionType.OTHER,
"Expected at least " + IMPORT_DIR_OFFSET + "arguments, sar :" + arguments.size());
}
String tableName =
validateName(arguments.get(0), tableOp, NEW_TABLE_NAME.and(NOT_BUILTIN_TABLE));
boolean keepOffline = Boolean.parseBoolean(ByteBufferUtil.toString(arguments.get(1)));
boolean keepMappings = Boolean.parseBoolean(ByteBufferUtil.toString(arguments.get(2)));
List<ByteBuffer> exportDirArgs = arguments.stream().skip(3).collect(Collectors.toList());
Set<String> exportDirs = ByteBufferUtil.toStringSet(exportDirArgs);
NamespaceId namespaceId = ClientServiceHandler.checkNamespaceId(manager.getContext(),
TableNameUtil.qualify(tableName).getFirst(), tableOp);
final boolean canImport;
try {
canImport = security.canImport(c, tableName, exportDirs, namespaceId);
} catch (ThriftSecurityException e) {
throwIfTableMissingSecurityException(e, null, tableName, TableOperation.IMPORT);
throw e;
}
if (!canImport) {
throw new ThriftSecurityException(c.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED);
}
goalMessage += "Import table with new name: " + tableName + " from " + exportDirs;
manager.fate(type)
.seedTransaction(op, fateId, new TraceRepo<>(new ImportTable(c.getPrincipal(),
tableName, exportDirs, namespaceId, keepMappings, keepOffline)), autoCleanup,
goalMessage);
break;
}
case TABLE_EXPORT: {
TableOperation tableOp = TableOperation.EXPORT;
validateArgumentCount(arguments, tableOp, 2);
String tableName =
validateName(arguments.get(0), tableOp, EXISTING_TABLE_NAME.and(NOT_BUILTIN_TABLE));
String exportDir = ByteBufferUtil.toString(arguments.get(1));
TableId tableId =
ClientServiceHandler.checkTableId(manager.getContext(), tableName, tableOp);
NamespaceId namespaceId = getNamespaceIdFromTableId(tableOp, tableId);
final boolean canExport;
try {
canExport = security.canExport(c, tableId, tableName, exportDir, namespaceId);
} catch (ThriftSecurityException e) {
throwIfTableMissingSecurityException(e, tableId, tableName, TableOperation.EXPORT);
throw e;
}
if (!canExport) {
throw new ThriftSecurityException(c.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED);
}
goalMessage += "Export table " + tableName + "(" + tableId + ") to " + exportDir;
manager.fate(type).seedTransaction(op, fateId,
new TraceRepo<>(new ExportTable(namespaceId, tableName, tableId, exportDir)),
autoCleanup, goalMessage);
break;
}
case TABLE_BULK_IMPORT2: {
TableOperation tableOp = TableOperation.BULK_IMPORT;
validateArgumentCount(arguments, tableOp, 3);
final var tableId = validateTableIdArgument(arguments.get(0), tableOp, NOT_ROOT_TABLE_ID);
String dir = ByteBufferUtil.toString(arguments.get(1));
boolean setTime = Boolean.parseBoolean(ByteBufferUtil.toString(arguments.get(2)));
NamespaceId namespaceId = getNamespaceIdFromTableId(tableOp, tableId);
final boolean canBulkImport;
String tableName;
try {
tableName = manager.getContext().getQualifiedTableName(tableId);
canBulkImport = security.canBulkImport(c, tableId, tableName, dir, null, namespaceId);
} catch (ThriftSecurityException e) {
throwIfTableMissingSecurityException(e, tableId, "", TableOperation.BULK_IMPORT);
throw e;
} catch (TableNotFoundException e) {
throw new ThriftTableOperationException(tableId.canonical(), null,
TableOperation.BULK_IMPORT, TableOperationExceptionType.NOTFOUND,
"Table no longer exists");
}
if (!canBulkImport) {
throw new ThriftSecurityException(c.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED);
}
manager.updateBulkImportStatus(dir, BulkImportState.INITIAL);
goalMessage += "Bulk import (v2) " + dir + " to " + tableName + "(" + tableId + ")";
manager.fate(type).seedTransaction(op, fateId,
new TraceRepo<>(new PrepBulkImport(tableId, dir, setTime)), autoCleanup, goalMessage);
break;
}
case TABLE_TABLET_AVAILABILITY: {
TableOperation tableOp = TableOperation.SET_TABLET_AVAILABILITY;
validateArgumentCount(arguments, tableOp, 3);
String tableName = validateName(arguments.get(0), tableOp, NOT_METADATA_TABLE);
TableId tableId = null;
try {
tableId = manager.getContext().getTableId(tableName);
} catch (TableNotFoundException e) {
throw new ThriftTableOperationException(null, tableName,
TableOperation.SET_TABLET_AVAILABILITY, TableOperationExceptionType.NOTFOUND,
"Table no longer exists");
}
final NamespaceId namespaceId = getNamespaceIdFromTableId(tableOp, tableId);
final boolean canSetAvailability;
try {
canSetAvailability = security.canAlterTable(c, tableId, namespaceId);
} catch (ThriftSecurityException e) {
throwIfTableMissingSecurityException(e, tableId, tableName,
TableOperation.SET_TABLET_AVAILABILITY);
throw e;
}
if (!canSetAvailability) {
throw new ThriftSecurityException(c.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED);
}
TRange tRange = new TRange();
try {
new TDeserializer().deserialize(tRange, ByteBufferUtil.toBytes(arguments.get(1)));
} catch (TException e) {
throw new ThriftTableOperationException(tableId.canonical(), tableName,
TableOperation.SET_TABLET_AVAILABILITY, TableOperationExceptionType.BAD_RANGE,
e.getMessage());
}
TabletAvailability tabletAvailability =
TabletAvailability.valueOf(ByteBufferUtil.toString(arguments.get(2)));
goalMessage += "Set availability for table: " + tableName + "(" + tableId + ") range: "
+ tRange + " to: " + tabletAvailability.name();
manager.fate(type).seedTransaction(op, fateId,
new TraceRepo<>(new LockTable(tableId, namespaceId, tRange, tabletAvailability)),
autoCleanup, goalMessage);
break;
}
case TABLE_SPLIT: {
TableOperation tableOp = TableOperation.SPLIT;
int SPLIT_OFFSET = 3; // offset where split data begins in arguments list
if (arguments.size() < (SPLIT_OFFSET + 1)) {
throw new ThriftTableOperationException(null, null, tableOp,
TableOperationExceptionType.OTHER,
"Expected at least " + (SPLIT_OFFSET + 1) + " arguments, saw :" + arguments.size());
}
var tableId = validateTableIdArgument(arguments.get(0), tableOp, NOT_ROOT_TABLE_ID);
NamespaceId namespaceId = getNamespaceIdFromTableId(tableOp, tableId);
boolean canSplit;
try {
canSplit = security.canSplitTablet(c, tableId, namespaceId);
} catch (ThriftSecurityException e) {
throwIfTableMissingSecurityException(e, tableId, null, TableOperation.SPLIT);
throw e;
}
if (!canSplit) {
throw new ThriftSecurityException(c.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED);
}
var endRow = ByteBufferUtil.toText(arguments.get(1));
var prevEndRow = ByteBufferUtil.toText(arguments.get(2));
endRow = endRow.getLength() == 0 ? null : endRow;
prevEndRow = prevEndRow.getLength() == 0 ? null : prevEndRow;
SortedMap<Text,
TabletMergeability> splits = arguments.subList(SPLIT_OFFSET, arguments.size()).stream()
.map(TabletMergeabilityUtil::decode).collect(
Collectors.toMap(Pair::getFirst, Pair::getSecond, (a, b) -> a, TreeMap::new));
KeyExtent extent = new KeyExtent(tableId, endRow, prevEndRow);
Predicate<Text> outOfBoundsTest =
split -> !extent.contains(split) || split.equals(extent.endRow());
if (splits.keySet().stream().anyMatch(outOfBoundsTest)) {
splits.keySet().stream().filter(outOfBoundsTest).forEach(split -> log
.warn("split for {} is out of bounds : {}", extent, TextUtil.truncate(split)));
throw new ThriftTableOperationException(tableId.canonical(), null, tableOp,
TableOperationExceptionType.OTHER,
"Split is outside bounds of tablet or equal to the tablets endrow, see warning in logs for more information.");
}
var maxSplitSize = manager.getContext().getTableConfiguration(tableId)
.getAsBytes(Property.TABLE_MAX_END_ROW_SIZE);
Predicate<Text> oversizedTest = split -> split.getLength() > maxSplitSize;
if (splits.keySet().stream().anyMatch(oversizedTest)) {
splits.keySet().stream().filter(oversizedTest)
.forEach(split -> log.warn(
"split exceeds max configured split size len:{} max:{} extent:{} split:{}",
split.getLength(), maxSplitSize, extent, TextUtil.truncate(split)));
throw new ThriftTableOperationException(tableId.canonical(), null, tableOp,
TableOperationExceptionType.OTHER,
"Length of requested split exceeds tables configured max, see warning in logs for more information.");
}
goalMessage = "Splitting " + extent + " for user into " + (splits.size() + 1) + " tablets";
manager.fate(type).seedTransaction(op, fateId, new PreSplit(extent, splits), autoCleanup,
goalMessage);
break;
}
default:
throw new UnsupportedOperationException();
}
}