This is an automated email from the ASF dual-hosted git repository. mmiller pushed a commit to branch 1.9 in repository https://gitbox.apache.org/repos/asf/accumulo.git
The following commit(s) were added to refs/heads/1.9 by this push: new 9cc673a fixes #1474: Option to leave cloned tables offline (#1475) 9cc673a is described below commit 9cc673a4d7096207ff3ff619bc5c9f718faa225a Author: Ivan Bella <i...@bella.name> AuthorDate: Tue Jan 28 13:59:09 2020 -0500 fixes #1474: Option to leave cloned tables offline (#1475) * Added an optional keepOffline option to TableOperations.clone via a CloneConfiguration * Updated the shell clone command with a -o option * Updated the CloneTestIT to test the keepOffline option * Updated the ShellServerIT to test the -o option --- .../core/client/admin/CloneConfiguration.java | 118 +++++++++++++++++++++ .../core/client/admin/TableOperations.java | 20 ++++ .../core/client/impl/CloneConfigurationImpl.java | 118 +++++++++++++++++++++ .../core/client/impl/TableOperationsImpl.java | 17 ++- .../core/client/mock/MockTableOperations.java | 8 ++ .../client/impl/TableOperationsHelperTest.java | 6 ++ .../apache/accumulo/master/FateServiceHandler.java | 9 +- .../apache/accumulo/master/tableOps/CloneInfo.java | 1 + .../accumulo/master/tableOps/CloneTable.java | 3 +- .../accumulo/master/tableOps/FinishCloneTable.java | 6 +- .../accumulo/shell/commands/CloneTableCommand.java | 15 ++- .../org/apache/accumulo/test/ShellServerIT.java | 23 ++++ .../accumulo/test/functional/CloneTestIT.java | 44 ++++++++ 13 files changed, 380 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/org/apache/accumulo/core/client/admin/CloneConfiguration.java b/core/src/main/java/org/apache/accumulo/core/client/admin/CloneConfiguration.java new file mode 100644 index 0000000..4f9ea89 --- /dev/null +++ b/core/src/main/java/org/apache/accumulo/core/client/admin/CloneConfiguration.java @@ -0,0 +1,118 @@ +/* + * 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.accumulo.core.client.admin; + +import java.util.Map; +import java.util.Set; + +import org.apache.accumulo.core.client.impl.CloneConfigurationImpl; + +/** + * A configuration object that can be used with the table clone command in the + * {@link TableOperations}. + * + * @since 1.10 and 2.1 + */ +public interface CloneConfiguration { + /** + * Determines if memory is flushed in the source table before cloning. + * + * @return true if memory is flushed in the source table before cloning. + */ + public boolean isFlush(); + + /** + * The source table properties are copied. This allows overriding of some of those properties. + * + * @return The source table properties to override. + */ + public Map<String,String> getPropertiesToSet(); + + /** + * The source table properties are copied, this allows reverting to system defaults for some of + * those properties. + * + * @return The properties that are to be reverted to system defaults. + */ + public Set<String> getPropertiesToExclude(); + + /** + * The new table is normally brought online after the cloning process. This allows leaving the new + * table offline + * + * @return true if the new table is to be kept offline after cloning. + */ + public boolean isKeepOffline(); + + /** + * A CloneConfiguration builder + * + * @since 1.10 and 2.1 + */ + public static interface Builder { + /** + * Determines if memory is flushed in the source table before cloning. + * + * @param flush + * true if memory is flushed in the source table before cloning. + */ + public Builder setFlush(boolean flush); + + /** + * The source table properties are copied. This allows overriding of some of those properties. + * + * @param propertiesToSet + * The source table properties to override. + */ + public Builder setPropertiesToSet(Map<String,String> propertiesToSet); + + /** + * The source table properties are copied, this allows reverting to system defaults for some of + * those properties. + * + * @param propertiesToExclude + * The properties that are to be reverted to system defaults. + */ + public Builder setPropertiesToExclude(Set<String> propertiesToExclude); + + /** + * The new table is normally brought online after the cloning process. This allows leaving the + * new table offline + * + * @param keepOffline + * true if the new table is to be kept offline after cloning. + */ + public Builder setKeepOffline(boolean keepOffline); + + /** + * Build the clone configuration + * + * @return the built immutable clone configuration + */ + public CloneConfiguration build(); + } + + /** + * @return a {@link CloneConfiguration} builder + */ + public static CloneConfiguration.Builder builder() { + return new CloneConfigurationImpl(); + } + +} diff --git a/core/src/main/java/org/apache/accumulo/core/client/admin/TableOperations.java b/core/src/main/java/org/apache/accumulo/core/client/admin/TableOperations.java index 7ff76c9..5b9e5ac 100644 --- a/core/src/main/java/org/apache/accumulo/core/client/admin/TableOperations.java +++ b/core/src/main/java/org/apache/accumulo/core/client/admin/TableOperations.java @@ -434,6 +434,26 @@ public interface TableOperations { AccumuloSecurityException, TableNotFoundException, TableExistsException; /** + * Clone a table from an existing table. The cloned table will have the same data as the source + * table it was created from. After cloning, the two tables can mutate independently. Initially + * the cloned table should not use any extra space, however as the source table and cloned table + * major compact extra space will be used by the clone. + * + * Initially the cloned table is only readable and writable by the user who created it. + * + * @param srcTableName + * the table to clone + * @param newTableName + * the name of the clone + * @param config + * the clone command configuration + * @since 1.10 and 2.1 + */ + void clone(String srcTableName, String newTableName, CloneConfiguration config) + throws AccumuloException, AccumuloSecurityException, TableNotFoundException, + TableExistsException; + + /** * Rename a table * * @param oldTableName diff --git a/core/src/main/java/org/apache/accumulo/core/client/impl/CloneConfigurationImpl.java b/core/src/main/java/org/apache/accumulo/core/client/impl/CloneConfigurationImpl.java new file mode 100644 index 0000000..3c01690 --- /dev/null +++ b/core/src/main/java/org/apache/accumulo/core/client/impl/CloneConfigurationImpl.java @@ -0,0 +1,118 @@ +/* + * 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.accumulo.core.client.impl; + +import java.util.Collections; +import java.util.Map; +import java.util.Set; + +import org.apache.accumulo.core.client.admin.CloneConfiguration; + +import com.google.common.base.Preconditions; + +/** + * A {@link CloneConfiguration} implementation which also implements the builder thereof + * + * @since 1.10 and 2.1 + */ +public class CloneConfigurationImpl implements CloneConfiguration, CloneConfiguration.Builder { + + // The purpose of this is to allow building an immutable CloneConfiguration object without + // creating + // separate Builder and CloneConfiguration objects. This is done to reduce object creation and + // copying. This could easily be changed to two objects without changing the interfaces. + private boolean built = false; + + // determines if memory is flushed in the source table before cloning. + private boolean flush = true; + + // the sources table properties are copied, this allows overriding of those properties + private Map<String,String> propertiesToSet = null; + + // do not copy these properties from the source table, just revert to system defaults + private Set<String> propertiesToExclude = null; + + // do not bring the table online after cloning + private boolean keepOffline = false; + + public CloneConfigurationImpl() {} + + public boolean isFlush() { + Preconditions.checkState(built); + return flush; + } + + public Map<String,String> getPropertiesToSet() { + Preconditions.checkState(built); + return (propertiesToSet == null ? Collections.<String,String>emptyMap() + : Collections.unmodifiableMap(propertiesToSet)); + } + + public Set<String> getPropertiesToExclude() { + Preconditions.checkState(built); + return (propertiesToExclude == null ? Collections.<String>emptySet() + : Collections.unmodifiableSet(propertiesToExclude)); + } + + public boolean isKeepOffline() { + Preconditions.checkState(built); + return keepOffline; + } + + @Override + public Builder setFlush(boolean flush) { + Preconditions.checkState(!built); + this.flush = flush; + return this; + } + + @Override + public Builder setPropertiesToSet(Map<String,String> propertiesToSet) { + Preconditions.checkState(!built); + this.propertiesToSet = propertiesToSet; + return this; + } + + @Override + public Builder setPropertiesToExclude(Set<String> propertiesToExclude) { + Preconditions.checkState(!built); + this.propertiesToExclude = propertiesToExclude; + return this; + } + + @Override + public Builder setKeepOffline(boolean keepOffline) { + Preconditions.checkState(!built); + this.keepOffline = keepOffline; + return this; + } + + @Override + public CloneConfiguration build() { + Preconditions.checkState(!built); + built = true; + return this; + } + + @Override + public String toString() { + return "{flush=" + flush + ", propertiesToSet=" + propertiesToSet + ", propertiesToExclude=" + + propertiesToExclude + ", keepOffline=" + keepOffline + ", built=" + built + "}"; + } +} diff --git a/core/src/main/java/org/apache/accumulo/core/client/impl/TableOperationsImpl.java b/core/src/main/java/org/apache/accumulo/core/client/impl/TableOperationsImpl.java index 4a7d22d..10e14ac 100644 --- a/core/src/main/java/org/apache/accumulo/core/client/impl/TableOperationsImpl.java +++ b/core/src/main/java/org/apache/accumulo/core/client/impl/TableOperationsImpl.java @@ -66,6 +66,7 @@ import org.apache.accumulo.core.client.TableDeletedException; import org.apache.accumulo.core.client.TableExistsException; import org.apache.accumulo.core.client.TableNotFoundException; import org.apache.accumulo.core.client.TableOfflineException; +import org.apache.accumulo.core.client.admin.CloneConfiguration; import org.apache.accumulo.core.client.admin.CompactionConfig; import org.apache.accumulo.core.client.admin.DiskUsage; import org.apache.accumulo.core.client.admin.FindMax; @@ -716,23 +717,35 @@ public class TableOperationsImpl extends TableOperationsHelper { Map<String,String> propertiesToSet, Set<String> propertiesToExclude) throws AccumuloSecurityException, TableNotFoundException, AccumuloException, TableExistsException { + clone(srcTableName, newTableName, + CloneConfiguration.builder().setFlush(flush).setPropertiesToSet(propertiesToSet) + .setPropertiesToExclude(propertiesToExclude).setKeepOffline(false).build()); + } + + @Override + public void clone(String srcTableName, String newTableName, CloneConfiguration config) + throws AccumuloSecurityException, TableNotFoundException, AccumuloException, + TableExistsException { checkArgument(srcTableName != null, "srcTableName is null"); checkArgument(newTableName != null, "newTableName is null"); String srcTableId = Tables.getTableId(context.getInstance(), srcTableName); - if (flush) + if (config.isFlush()) _flush(srcTableId, null, null, true); + Set<String> propertiesToExclude = config.getPropertiesToExclude(); if (propertiesToExclude == null) propertiesToExclude = Collections.emptySet(); + Map<String,String> propertiesToSet = config.getPropertiesToSet(); if (propertiesToSet == null) propertiesToSet = Collections.emptyMap(); List<ByteBuffer> args = Arrays.asList(ByteBuffer.wrap(srcTableId.getBytes(UTF_8)), - ByteBuffer.wrap(newTableName.getBytes(UTF_8))); + ByteBuffer.wrap(newTableName.getBytes(UTF_8)), + ByteBuffer.wrap(Boolean.toString(config.isKeepOffline()).getBytes(UTF_8))); Map<String,String> opts = new HashMap<>(); for (Entry<String,String> entry : propertiesToSet.entrySet()) { if (entry.getKey().startsWith(CLONE_EXCLUDE_PREFIX)) diff --git a/core/src/main/java/org/apache/accumulo/core/client/mock/MockTableOperations.java b/core/src/main/java/org/apache/accumulo/core/client/mock/MockTableOperations.java index d76d29c..6e92b7b 100644 --- a/core/src/main/java/org/apache/accumulo/core/client/mock/MockTableOperations.java +++ b/core/src/main/java/org/apache/accumulo/core/client/mock/MockTableOperations.java @@ -38,6 +38,7 @@ import org.apache.accumulo.core.client.IteratorSetting; import org.apache.accumulo.core.client.NamespaceNotFoundException; import org.apache.accumulo.core.client.TableExistsException; import org.apache.accumulo.core.client.TableNotFoundException; +import org.apache.accumulo.core.client.admin.CloneConfiguration; import org.apache.accumulo.core.client.admin.CompactionConfig; import org.apache.accumulo.core.client.admin.DiskUsage; import org.apache.accumulo.core.client.admin.FindMax; @@ -475,6 +476,13 @@ class MockTableOperations extends TableOperationsHelper { } @Override + public void clone(String srcTableName, String newTableName, CloneConfiguration config) + throws AccumuloException, AccumuloSecurityException, TableNotFoundException, + TableExistsException { + throw new NotImplementedException(); + } + + @Override public void flush(String tableName, Text start, Text end, boolean wait) throws AccumuloException, AccumuloSecurityException, TableNotFoundException { if (!exists(tableName)) diff --git a/core/src/test/java/org/apache/accumulo/core/client/impl/TableOperationsHelperTest.java b/core/src/test/java/org/apache/accumulo/core/client/impl/TableOperationsHelperTest.java index e732686..c1ae4da 100644 --- a/core/src/test/java/org/apache/accumulo/core/client/impl/TableOperationsHelperTest.java +++ b/core/src/test/java/org/apache/accumulo/core/client/impl/TableOperationsHelperTest.java @@ -38,6 +38,7 @@ import org.apache.accumulo.core.client.AccumuloSecurityException; import org.apache.accumulo.core.client.IteratorSetting; import org.apache.accumulo.core.client.TableExistsException; import org.apache.accumulo.core.client.TableNotFoundException; +import org.apache.accumulo.core.client.admin.CloneConfiguration; import org.apache.accumulo.core.client.admin.CompactionConfig; import org.apache.accumulo.core.client.admin.DiskUsage; import org.apache.accumulo.core.client.admin.Locations; @@ -154,6 +155,11 @@ public class TableOperationsHelperTest { TableExistsException {} @Override + public void clone(String srcTableName, String newTableName, CloneConfiguration config) + throws AccumuloException, AccumuloSecurityException, TableNotFoundException, + TableExistsException {} + + @Override public void rename(String oldTableName, String newTableName) throws AccumuloSecurityException, TableNotFoundException, AccumuloException, TableExistsException {} diff --git a/server/master/src/main/java/org/apache/accumulo/master/FateServiceHandler.java b/server/master/src/main/java/org/apache/accumulo/master/FateServiceHandler.java index 7949ac2..08237f8 100644 --- a/server/master/src/main/java/org/apache/accumulo/master/FateServiceHandler.java +++ b/server/master/src/main/java/org/apache/accumulo/master/FateServiceHandler.java @@ -224,9 +224,14 @@ class FateServiceHandler implements FateService.Iface { } case TABLE_CLONE: { TableOperation tableOp = TableOperation.CLONE; - validateArgumentCount(arguments, tableOp, 2); + validateArgumentCount(arguments, tableOp, 3); String srcTableId = validateTableIdArgument(arguments.get(0), tableOp, CAN_CLONE); String tableName = validateTableNameArgument(arguments.get(1), tableOp, NOT_SYSTEM); + boolean keepOffline = false; + if (arguments.get(2) != null) { + keepOffline = Boolean.parseBoolean(ByteBufferUtil.toString(arguments.get(2))); + } + String namespaceId; try { namespaceId = @@ -269,7 +274,7 @@ class FateServiceHandler implements FateService.Iface { } master.fate.seedTransaction(opid, new TraceRepo<>(new CloneTable(c.getPrincipal(), - namespaceId, srcTableId, tableName, propertiesToSet, propertiesToExclude)), + namespaceId, srcTableId, tableName, propertiesToSet, propertiesToExclude, keepOffline)), autoCleanup); break; diff --git a/server/master/src/main/java/org/apache/accumulo/master/tableOps/CloneInfo.java b/server/master/src/main/java/org/apache/accumulo/master/tableOps/CloneInfo.java index 96ff954..7e822c8 100644 --- a/server/master/src/main/java/org/apache/accumulo/master/tableOps/CloneInfo.java +++ b/server/master/src/main/java/org/apache/accumulo/master/tableOps/CloneInfo.java @@ -31,6 +31,7 @@ class CloneInfo implements Serializable { String srcNamespaceId; Map<String,String> propertiesToSet; Set<String> propertiesToExclude; + boolean keepOffline; public String user; } diff --git a/server/master/src/main/java/org/apache/accumulo/master/tableOps/CloneTable.java b/server/master/src/main/java/org/apache/accumulo/master/tableOps/CloneTable.java index 22e8a68..c45afdb 100644 --- a/server/master/src/main/java/org/apache/accumulo/master/tableOps/CloneTable.java +++ b/server/master/src/main/java/org/apache/accumulo/master/tableOps/CloneTable.java @@ -29,7 +29,7 @@ public class CloneTable extends MasterRepo { private CloneInfo cloneInfo; public CloneTable(String user, String namespaceId, String srcTableId, String tableName, - Map<String,String> propertiesToSet, Set<String> propertiesToExclude) { + Map<String,String> propertiesToSet, Set<String> propertiesToExclude, boolean keepOffline) { cloneInfo = new CloneInfo(); cloneInfo.user = user; cloneInfo.srcTableId = srcTableId; @@ -37,6 +37,7 @@ public class CloneTable extends MasterRepo { cloneInfo.propertiesToExclude = propertiesToExclude; cloneInfo.propertiesToSet = propertiesToSet; cloneInfo.srcNamespaceId = namespaceId; + cloneInfo.keepOffline = keepOffline; } @Override diff --git a/server/master/src/main/java/org/apache/accumulo/master/tableOps/FinishCloneTable.java b/server/master/src/main/java/org/apache/accumulo/master/tableOps/FinishCloneTable.java index d089ba1..213f254 100644 --- a/server/master/src/main/java/org/apache/accumulo/master/tableOps/FinishCloneTable.java +++ b/server/master/src/main/java/org/apache/accumulo/master/tableOps/FinishCloneTable.java @@ -44,7 +44,11 @@ class FinishCloneTable extends MasterRepo { // may never create files.. therefore there is no need to consume namenode space w/ directories // that are not used... tablet will create directories as needed - TableManager.getInstance().transitionTableState(cloneInfo.tableId, TableState.ONLINE); + if (!cloneInfo.keepOffline) { + TableManager.getInstance().transitionTableState(cloneInfo.tableId, TableState.ONLINE); + } else { + TableManager.getInstance().transitionTableState(cloneInfo.tableId, TableState.OFFLINE); + } Utils.unreserveNamespace(cloneInfo.srcNamespaceId, tid, false); if (!cloneInfo.srcNamespaceId.equals(cloneInfo.namespaceId)) diff --git a/shell/src/main/java/org/apache/accumulo/shell/commands/CloneTableCommand.java b/shell/src/main/java/org/apache/accumulo/shell/commands/CloneTableCommand.java index 33850a4..d7045ed 100644 --- a/shell/src/main/java/org/apache/accumulo/shell/commands/CloneTableCommand.java +++ b/shell/src/main/java/org/apache/accumulo/shell/commands/CloneTableCommand.java @@ -25,6 +25,7 @@ import org.apache.accumulo.core.client.AccumuloException; import org.apache.accumulo.core.client.AccumuloSecurityException; import org.apache.accumulo.core.client.TableExistsException; import org.apache.accumulo.core.client.TableNotFoundException; +import org.apache.accumulo.core.client.admin.CloneConfiguration; import org.apache.accumulo.shell.Shell; import org.apache.accumulo.shell.Shell.Command; import org.apache.accumulo.shell.Token; @@ -37,6 +38,7 @@ public class CloneTableCommand extends Command { private Option setPropsOption; private Option excludePropsOption; private Option noFlushOption; + private Option keepOfflineOption; @Override public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) @@ -46,6 +48,7 @@ public class CloneTableCommand extends Command { final HashMap<String,String> props = new HashMap<>(); final HashSet<String> exclude = new HashSet<>(); boolean flush = true; + boolean keepOffline = false; if (cl.hasOption(setPropsOption.getOpt())) { String[] keyVals = cl.getOptionValue(setPropsOption.getOpt()).split(","); @@ -66,8 +69,13 @@ public class CloneTableCommand extends Command { flush = false; } - shellState.getConnector().tableOperations().clone(cl.getArgs()[0], cl.getArgs()[1], flush, - props, exclude); + if (cl.hasOption(keepOfflineOption.getOpt())) { + keepOffline = true; + } + + shellState.getConnector().tableOperations().clone(cl.getArgs()[0], cl.getArgs()[1], + CloneConfiguration.builder().setFlush(flush).setPropertiesToSet(props) + .setPropertiesToExclude(exclude).setKeepOffline(keepOffline).build()); return 0; } @@ -99,6 +107,9 @@ public class CloneTableCommand extends Command { noFlushOption = new Option("nf", "noFlush", false, "do not flush table data in memory before cloning."); o.addOption(noFlushOption); + keepOfflineOption = + new Option("o", "offline", false, "do not bring the table online after cloning."); + o.addOption(keepOfflineOption); return o; } diff --git a/test/src/main/java/org/apache/accumulo/test/ShellServerIT.java b/test/src/main/java/org/apache/accumulo/test/ShellServerIT.java index abf06bf..8f009f3 100644 --- a/test/src/main/java/org/apache/accumulo/test/ShellServerIT.java +++ b/test/src/main/java/org/apache/accumulo/test/ShellServerIT.java @@ -828,6 +828,29 @@ public class ShellServerIT extends SharedMiniClusterBase { ts.exec("scan", true, "value", true); ts.exec("clonetable " + table + " " + clone); // verify constraint, config, and splits were cloned + ts.exec("table " + clone); + ts.exec("scan", true, "value", true); + ts.exec("constraint --list -t " + clone, true, "VisibilityConstraint=2", true); + ts.exec("config -t " + clone + " -np", true, "123M", true); + ts.exec("getsplits -t " + clone, true, "a\nb\nc\n"); + ts.exec("deletetable -f " + table); + ts.exec("deletetable -f " + clone); + } + + @Test + public void clonetableOffline() throws Exception { + final String table = name.getMethodName(), clone = table + "_clone"; + + // clonetable + ts.exec("createtable " + table + " -evc"); + ts.exec("config -t " + table + " -s table.split.threshold=123M", true); + ts.exec("addsplits -t " + table + " a b c", true); + ts.exec("insert a b c value"); + ts.exec("scan", true, "value", true); + ts.exec("clonetable " + table + " " + clone + " -o"); + // verify constraint, config, and splits were cloned + ts.exec("table " + clone); + ts.exec("scan", false, "TableOfflineException", true); ts.exec("constraint --list -t " + clone, true, "VisibilityConstraint=2", true); ts.exec("config -t " + clone + " -np", true, "123M", true); ts.exec("getsplits -t " + clone, true, "a\nb\nc\n"); diff --git a/test/src/main/java/org/apache/accumulo/test/functional/CloneTestIT.java b/test/src/main/java/org/apache/accumulo/test/functional/CloneTestIT.java index d76a28a..d072365 100644 --- a/test/src/main/java/org/apache/accumulo/test/functional/CloneTestIT.java +++ b/test/src/main/java/org/apache/accumulo/test/functional/CloneTestIT.java @@ -40,12 +40,15 @@ import org.apache.accumulo.core.client.Connector; import org.apache.accumulo.core.client.MutationsRejectedException; import org.apache.accumulo.core.client.Scanner; import org.apache.accumulo.core.client.TableNotFoundException; +import org.apache.accumulo.core.client.admin.CloneConfiguration; import org.apache.accumulo.core.client.admin.DiskUsage; +import org.apache.accumulo.core.client.impl.Tables; import org.apache.accumulo.core.conf.Property; import org.apache.accumulo.core.data.Key; import org.apache.accumulo.core.data.Mutation; import org.apache.accumulo.core.data.Range; import org.apache.accumulo.core.data.Value; +import org.apache.accumulo.core.master.state.tables.TableState; import org.apache.accumulo.core.metadata.MetadataTable; import org.apache.accumulo.core.metadata.RootTable; import org.apache.accumulo.core.metadata.schema.MetadataSchema; @@ -57,6 +60,7 @@ import org.apache.hadoop.fs.FileStatus; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.Text; +import org.apache.thrift.TException; import org.junit.Assume; import org.junit.Test; @@ -121,6 +125,12 @@ public class CloneTestIT extends AccumuloClusterHarness { } + private void assertTableState(String table, Connector c, TableState expected) throws TException { + String tableId = c.tableOperations().tableIdMap().get(table); + TableState tableState = Tables.getTableState(c.getInstance(), tableId); + assertEquals(expected, tableState); + } + private void checkData(String table2, Connector c) throws TableNotFoundException { Scanner scanner = c.createScanner(table2, Authorizations.EMPTY); @@ -248,6 +258,8 @@ public class CloneTestIT extends AccumuloClusterHarness { c.tableOperations().clone(table1, table2, true, props, exclude); + assertTableState(table2, c, TableState.ONLINE); + Mutation m3 = new Mutation("009"); m3.put("data", "x", "1"); m3.put("data", "y", "2"); @@ -268,6 +280,38 @@ public class CloneTestIT extends AccumuloClusterHarness { } @Test + public void testOfflineClone() throws Exception { + String[] tableNames = getUniqueNames(3); + String table1 = tableNames[0]; + String table2 = tableNames[1]; + + Connector c = getConnector(); + AccumuloCluster cluster = getCluster(); + Assume.assumeTrue(cluster instanceof MiniAccumuloClusterImpl); + MiniAccumuloClusterImpl mac = (MiniAccumuloClusterImpl) cluster; + String rootPath = mac.getConfig().getDir().getAbsolutePath(); + + c.tableOperations().create(table1); + + BatchWriter bw = writeData(table1, c); + + Map<String,String> props = new HashMap<>(); + props.put(Property.TABLE_FILE_COMPRESSED_BLOCK_SIZE.getKey(), "500K"); + + Set<String> exclude = new HashSet<>(); + exclude.add(Property.TABLE_FILE_MAX.getKey()); + + c.tableOperations().clone(table1, table2, CloneConfiguration.builder().setFlush(true) + .setPropertiesToSet(props).setPropertiesToExclude(exclude).setKeepOffline(true).build()); + + assertTableState(table2, c, TableState.OFFLINE); + + // delete tables + c.tableOperations().delete(table1); + c.tableOperations().delete(table2); + } + + @Test public void testCloneWithSplits() throws Exception { Connector conn = getConnector();