Repository: accumulo Updated Branches: refs/heads/master 80f44ad1b -> 1e9a42cc6
ACCUMULO-3176 Create Table with initial properties Signed-off-by: Christopher Tubbs <ctubb...@apache.org> Project: http://git-wip-us.apache.org/repos/asf/accumulo/repo Commit: http://git-wip-us.apache.org/repos/asf/accumulo/commit/afd1cb13 Tree: http://git-wip-us.apache.org/repos/asf/accumulo/tree/afd1cb13 Diff: http://git-wip-us.apache.org/repos/asf/accumulo/diff/afd1cb13 Branch: refs/heads/master Commit: afd1cb13383e104d1f2fdcea25931ec8691d0b45 Parents: bfcb0ed Author: Jenna Huston <jenna.husto...@gmail.com> Authored: Tue Sep 30 14:17:10 2014 -0400 Committer: Christopher Tubbs <ctubb...@apache.org> Committed: Tue Nov 25 11:29:08 2014 -0500 ---------------------------------------------------------------------- .../core/client/NewTableConfiguration.java | 78 ++++++++ .../core/client/admin/TableOperations.java | 22 +++ .../core/client/impl/TableOperationsImpl.java | 31 ++- .../accumulo/core/client/mock/MockAccumulo.java | 23 ++- .../accumulo/core/client/mock/MockTable.java | 32 +++- .../core/client/mock/MockTableOperations.java | 29 ++- .../client/impl/TableOperationsHelperTest.java | 6 + .../org/apache/accumulo/proxy/ProxyServer.java | 2 +- .../shell/commands/CreateTableCommand.java | 19 +- .../test/CreateTableWithNewTableConfigIT.java | 191 +++++++++++++++++++ .../org/apache/accumulo/test/ShellServerIT.java | 29 ++- 11 files changed, 441 insertions(+), 21 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/accumulo/blob/afd1cb13/core/src/main/java/org/apache/accumulo/core/client/NewTableConfiguration.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/accumulo/core/client/NewTableConfiguration.java b/core/src/main/java/org/apache/accumulo/core/client/NewTableConfiguration.java new file mode 100644 index 0000000..515919f --- /dev/null +++ b/core/src/main/java/org/apache/accumulo/core/client/NewTableConfiguration.java @@ -0,0 +1,78 @@ +/* + * 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; + +import static com.google.common.base.Preconditions.checkArgument; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.apache.accumulo.core.client.admin.TimeType; +import org.apache.accumulo.core.iterators.IteratorUtil; + +/** + * This object stores table creation parameters. Currently including: TimeType, limitVersion, and user specified initial properties + * + * @since 1.7.0 + */ +public class NewTableConfiguration { + + private static final TimeType DEFAULT_TIME_TYPE = TimeType.MILLIS; + private TimeType timeType = DEFAULT_TIME_TYPE; + + private boolean limitVersion = true; + + private Map<String,String> properties = new HashMap<String,String>(); + + public NewTableConfiguration setTimeType(TimeType tt) { + checkArgument(tt != null, "TimeType is null"); + + this.timeType = tt; + return this; + } + + public TimeType getTimeType() { + return timeType; + } + + /** + * Currently the only default iterator is the versioning iterator. This method will cause the table to be created without the versioning iterator + */ + public NewTableConfiguration withoutDefaultIterators() { + this.limitVersion = false; + return this; + } + + public NewTableConfiguration setProperties(Map<String,String> prop) { + checkArgument(prop != null, "properties is null"); + + this.properties = new HashMap<String,String>(prop); + return this; + } + + public Map<String,String> getProperties() { + Map<String,String> propertyMap = new HashMap<>(); + + if (limitVersion) { + propertyMap.putAll(IteratorUtil.generateInitialTableProperties(limitVersion)); + } + + propertyMap.putAll(properties); + return Collections.unmodifiableMap(propertyMap); + } +} http://git-wip-us.apache.org/repos/asf/accumulo/blob/afd1cb13/core/src/main/java/org/apache/accumulo/core/client/admin/TableOperations.java ---------------------------------------------------------------------- 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 97f538d..35157ef 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 @@ -28,6 +28,7 @@ import java.util.SortedSet; import org.apache.accumulo.core.client.AccumuloException; import org.apache.accumulo.core.client.AccumuloSecurityException; import org.apache.accumulo.core.client.IteratorSetting; +import org.apache.accumulo.core.client.NewTableConfiguration; import org.apache.accumulo.core.client.TableExistsException; import org.apache.accumulo.core.client.TableNotFoundException; import org.apache.accumulo.core.data.Range; @@ -83,7 +84,9 @@ public interface TableOperations { * if the user does not have permission * @throws TableExistsException * if the table already exists + * @deprecated since 1.7.0; use {@link #create(String, NewTableConfiguration)} instead. */ + @Deprecated void create(String tableName, boolean limitVersion) throws AccumuloException, AccumuloSecurityException, TableExistsException; /** @@ -99,10 +102,29 @@ public interface TableOperations { * if the user does not have permission * @throws TableExistsException * if the table already exists + * @deprecated since 1.7.0; use {@link #create(String, NewTableConfiguration)} instead. */ + @Deprecated void create(String tableName, boolean versioningIter, TimeType timeType) throws AccumuloException, AccumuloSecurityException, TableExistsException; /** + * @param tableName + * the name of the table + * @param ntc + * specifies the new table's configuration variable, which are: 1. enable/disable the versioning iterator, which will limit the number of Key + * versions kept; 2. specifies logical or real-time based time recording for entries in the table; 3. user defined properties to be merged into the + * initial properties of the table + * @throws AccumuloException + * if a general error occurs + * @throws AccumuloSecurityException + * if the user does not have permission + * @throws TableExistsException + * if the table already exists + * @since 1.7.0 + */ + void create(String tableName, NewTableConfiguration ntc) throws AccumuloSecurityException, AccumuloException, TableExistsException; + + /** * Imports a table exported via exportTable and copied via hadoop distcp. * * @param tableName http://git-wip-us.apache.org/repos/asf/accumulo/blob/afd1cb13/core/src/main/java/org/apache/accumulo/core/client/impl/TableOperationsImpl.java ---------------------------------------------------------------------- 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 3c450c3..30bedc6 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 @@ -56,6 +56,7 @@ import org.apache.accumulo.core.client.IsolatedScanner; import org.apache.accumulo.core.client.IteratorSetting; import org.apache.accumulo.core.client.NamespaceExistsException; import org.apache.accumulo.core.client.NamespaceNotFoundException; +import org.apache.accumulo.core.client.NewTableConfiguration; import org.apache.accumulo.core.client.RowIterator; import org.apache.accumulo.core.client.Scanner; import org.apache.accumulo.core.client.TableDeletedException; @@ -188,7 +189,7 @@ public class TableOperationsImpl extends TableOperationsHelper { */ @Override public void create(String tableName) throws AccumuloException, AccumuloSecurityException, TableExistsException { - create(tableName, true, TimeType.MILLIS); + create(tableName, new NewTableConfiguration()); } /** @@ -198,6 +199,7 @@ public class TableOperationsImpl extends TableOperationsHelper { * Enables/disables the versioning iterator, which will limit the number of Key versions kept. */ @Override + @Deprecated public void create(String tableName, boolean limitVersion) throws AccumuloException, AccumuloSecurityException, TableExistsException { create(tableName, limitVersion, TimeType.MILLIS); } @@ -211,17 +213,36 @@ public class TableOperationsImpl extends TableOperationsHelper { * Enables/disables the versioning iterator, which will limit the number of Key versions kept. */ @Override + @Deprecated public void create(String tableName, boolean limitVersion, TimeType timeType) throws AccumuloException, AccumuloSecurityException, TableExistsException { checkArgument(tableName != null, "tableName is null"); checkArgument(timeType != null, "timeType is null"); - List<ByteBuffer> args = Arrays.asList(ByteBuffer.wrap(tableName.getBytes(UTF_8)), ByteBuffer.wrap(timeType.name().getBytes(UTF_8))); + NewTableConfiguration ntc = new NewTableConfiguration().setTimeType(timeType); - Map<String,String> opts; if (limitVersion) - opts = IteratorUtil.generateInitialTableProperties(limitVersion); + create(tableName, ntc); else - opts = Collections.emptyMap(); + create(tableName, ntc.withoutDefaultIterators()); + } + + /** + * @param tableName + * the name of the table + * @param ntc + * specifies the new table's configuration. It determines whether the versioning iterator is enabled or disabled, logical or real-time based time + * recording for entries in the table + * + */ + @Override + public void create(String tableName, NewTableConfiguration ntc) throws AccumuloException, AccumuloSecurityException, TableExistsException { + checkArgument(tableName != null, "tableName is null"); + checkArgument(ntc != null, "ntc is null"); + + List<ByteBuffer> args = Arrays.asList(ByteBuffer.wrap(tableName.getBytes(StandardCharsets.UTF_8)), + ByteBuffer.wrap(ntc.getTimeType().name().getBytes(StandardCharsets.UTF_8))); + + Map<String,String> opts = ntc.getProperties(); try { doTableFateOperation(tableName, AccumuloException.class, FateOperation.TABLE_CREATE, args, opts); http://git-wip-us.apache.org/repos/asf/accumulo/blob/afd1cb13/core/src/main/java/org/apache/accumulo/core/client/mock/MockAccumulo.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/accumulo/core/client/mock/MockAccumulo.java b/core/src/main/java/org/apache/accumulo/core/client/mock/MockAccumulo.java index 66035f7..efadc53 100644 --- a/core/src/main/java/org/apache/accumulo/core/client/mock/MockAccumulo.java +++ b/core/src/main/java/org/apache/accumulo/core/client/mock/MockAccumulo.java @@ -17,6 +17,7 @@ package org.apache.accumulo.core.client.mock; import java.util.Collection; +import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; import java.util.Map; @@ -88,6 +89,26 @@ public class MockAccumulo { } public void createTable(String username, String tableName, boolean useVersions, TimeType timeType) { + Map<String,String> opts = Collections.emptyMap(); + createTable(username, tableName, useVersions, timeType, opts); + } + + public void createTable(String username, String tableName, boolean useVersions, TimeType timeType, Map<String,String> properties) { + String namespace = Tables.qualify(tableName).getFirst(); + + if (!namespaceExists(namespace)) { + return; + } + + MockNamespace n = namespaces.get(namespace); + MockTable t = new MockTable(n, useVersions, timeType, Integer.toString(tableIdCounter.incrementAndGet()), properties); + t.userPermissions.put(username, EnumSet.allOf(TablePermission.class)); + t.setNamespaceName(namespace); + t.setNamespace(n); + tables.put(tableName, t); + } + + public void createTable(String username, String tableName, TimeType timeType, Map<String,String> properties) { String namespace = Tables.qualify(tableName).getFirst(); if (!namespaceExists(namespace)) { @@ -95,7 +116,7 @@ public class MockAccumulo { } MockNamespace n = namespaces.get(namespace); - MockTable t = new MockTable(n, useVersions, timeType, Integer.toString(tableIdCounter.incrementAndGet())); + MockTable t = new MockTable(n, timeType, Integer.toString(tableIdCounter.incrementAndGet()), properties); t.userPermissions.put(username, EnumSet.allOf(TablePermission.class)); t.setNamespaceName(namespace); t.setNamespace(n); http://git-wip-us.apache.org/repos/asf/accumulo/blob/afd1cb13/core/src/main/java/org/apache/accumulo/core/client/mock/MockTable.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/accumulo/core/client/mock/MockTable.java b/core/src/main/java/org/apache/accumulo/core/client/mock/MockTable.java index 35cbdd2..ee9244b 100644 --- a/core/src/main/java/org/apache/accumulo/core/client/mock/MockTable.java +++ b/core/src/main/java/org/apache/accumulo/core/client/mock/MockTable.java @@ -104,8 +104,12 @@ public class MockTable { settings.put(key, entry.getValue()); } } - + MockTable(MockNamespace namespace, boolean limitVersion, TimeType timeType, String tableId) { + this(namespace, limitVersion, timeType, tableId, new HashMap<String,String>()); + } + + MockTable(MockNamespace namespace, boolean limitVersion, TimeType timeType, String tableId, Map<String,String> properties) { this(limitVersion, timeType, tableId); Set<Entry<String,String>> set = namespace.settings.entrySet(); Iterator<Entry<String,String>> entries = set.iterator(); @@ -115,8 +119,32 @@ public class MockTable { if (key.startsWith(Property.TABLE_PREFIX.getKey())) settings.put(key, entry.getValue()); } + + for (Entry<String,String> initialProp : properties.entrySet()) { + settings.put(initialProp.getKey(), initialProp.getValue()); + } } - + + public MockTable(MockNamespace namespace, TimeType timeType, String tableId, Map<String,String> properties) { + this.timeType = timeType; + this.tableId = tableId; + settings = properties; + for (Entry<String,String> entry : AccumuloConfiguration.getDefaultConfiguration()) { + String key = entry.getKey(); + if (key.startsWith(Property.TABLE_PREFIX.getKey())) + settings.put(key, entry.getValue()); + } + + Set<Entry<String,String>> set = namespace.settings.entrySet(); + Iterator<Entry<String,String>> entries = set.iterator(); + while (entries.hasNext()) { + Entry<String,String> entry = entries.next(); + String key = entry.getKey(); + if (key.startsWith(Property.TABLE_PREFIX.getKey())) + settings.put(key, entry.getValue()); + } + } + synchronized void addMutation(Mutation m) { if (m.size() == 0) throw new IllegalArgumentException("Can not add empty mutations"); http://git-wip-us.apache.org/repos/asf/accumulo/blob/afd1cb13/core/src/main/java/org/apache/accumulo/core/client/mock/MockTableOperations.java ---------------------------------------------------------------------- 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 59afc8b..e89985a 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 @@ -34,6 +34,7 @@ import org.apache.accumulo.core.client.AccumuloException; import org.apache.accumulo.core.client.AccumuloSecurityException; import org.apache.accumulo.core.client.IteratorSetting; import org.apache.accumulo.core.client.NamespaceNotFoundException; +import org.apache.accumulo.core.client.NewTableConfiguration; import org.apache.accumulo.core.client.TableExistsException; import org.apache.accumulo.core.client.TableNotFoundException; import org.apache.accumulo.core.client.admin.DiskUsage; @@ -61,6 +62,8 @@ import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.Text; import org.apache.log4j.Logger; +import com.google.common.base.Preconditions; + class MockTableOperations extends TableOperationsHelper { private static final Logger log = Logger.getLogger(MockTableOperations.class); private static final byte[] ZERO = {0}; @@ -88,27 +91,35 @@ class MockTableOperations extends TableOperationsHelper { @Override public void create(String tableName) throws AccumuloException, AccumuloSecurityException, TableExistsException { - create(tableName, true, TimeType.MILLIS); + create(tableName, new NewTableConfiguration()); } @Override + @Deprecated public void create(String tableName, boolean versioningIter) throws AccumuloException, AccumuloSecurityException, TableExistsException { create(tableName, versioningIter, TimeType.MILLIS); } @Override + @Deprecated public void create(String tableName, boolean versioningIter, TimeType timeType) throws AccumuloException, AccumuloSecurityException, TableExistsException { + NewTableConfiguration ntc = new NewTableConfiguration().setTimeType(timeType); + + if (versioningIter) + create(tableName, ntc); + else + create(tableName, ntc.withoutDefaultIterators()); + } + + @Override + public void create(String tableName, NewTableConfiguration ntc) throws AccumuloException, AccumuloSecurityException, TableExistsException { String namespace = Tables.qualify(tableName).getFirst(); - if (!tableName.matches(Tables.VALID_NAME_REGEX)) { - throw new IllegalArgumentException(); - } + + Preconditions.checkArgument(!tableName.matches(Tables.VALID_NAME_REGEX)); if (exists(tableName)) throw new TableExistsException(tableName, tableName, ""); - - if (!namespaceExists(namespace)) { - throw new IllegalArgumentException("Namespace (" + namespace + ") does not exist, create it first"); - } - acu.createTable(username, tableName, versioningIter, timeType); + Preconditions.checkArgument(!namespaceExists(namespace), "Namespace (" + namespace + ") does not exist, create it first"); + acu.createTable(username, tableName, ntc.getTimeType(), ntc.getProperties()); } @Override http://git-wip-us.apache.org/repos/asf/accumulo/blob/afd1cb13/core/src/test/java/org/apache/accumulo/core/client/impl/TableOperationsHelperTest.java ---------------------------------------------------------------------- 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 02838ed..85aee36 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 @@ -31,6 +31,7 @@ import java.util.TreeMap; import org.apache.accumulo.core.client.AccumuloException; import org.apache.accumulo.core.client.AccumuloSecurityException; import org.apache.accumulo.core.client.IteratorSetting; +import org.apache.accumulo.core.client.NewTableConfiguration; import org.apache.accumulo.core.client.TableExistsException; import org.apache.accumulo.core.client.TableNotFoundException; import org.apache.accumulo.core.client.admin.DiskUsage; @@ -61,14 +62,19 @@ public class TableOperationsHelperTest { public void create(String tableName) throws AccumuloException, AccumuloSecurityException, TableExistsException {} @Override + @Deprecated public void create(String tableName, boolean limitVersion) throws AccumuloException, AccumuloSecurityException, TableExistsException { create(tableName, limitVersion, TimeType.MILLIS); } @Override + @Deprecated public void create(String tableName, boolean versioningIter, TimeType timeType) throws AccumuloException, AccumuloSecurityException, TableExistsException {} @Override + public void create(String tableName, NewTableConfiguration ntc) throws AccumuloException, AccumuloSecurityException, TableExistsException {} + + @Override public void addSplits(String tableName, SortedSet<Text> partitionKeys) throws TableNotFoundException, AccumuloException, AccumuloSecurityException {} @Deprecated http://git-wip-us.apache.org/repos/asf/accumulo/blob/afd1cb13/proxy/src/main/java/org/apache/accumulo/proxy/ProxyServer.java ---------------------------------------------------------------------- diff --git a/proxy/src/main/java/org/apache/accumulo/proxy/ProxyServer.java b/proxy/src/main/java/org/apache/accumulo/proxy/ProxyServer.java index bd0782d..2ac70fd 100644 --- a/proxy/src/main/java/org/apache/accumulo/proxy/ProxyServer.java +++ b/proxy/src/main/java/org/apache/accumulo/proxy/ProxyServer.java @@ -117,7 +117,7 @@ import com.google.common.cache.RemovalNotification; */ public class ProxyServer implements AccumuloProxy.Iface { - private static final Logger logger = Logger.getLogger(ProxyServer.class); + public static final Logger logger = Logger.getLogger(ProxyServer.class); protected Instance instance; protected Class<? extends AuthenticationToken> tokenClass; http://git-wip-us.apache.org/repos/asf/accumulo/blob/afd1cb13/shell/src/main/java/org/apache/accumulo/shell/commands/CreateTableCommand.java ---------------------------------------------------------------------- diff --git a/shell/src/main/java/org/apache/accumulo/shell/commands/CreateTableCommand.java b/shell/src/main/java/org/apache/accumulo/shell/commands/CreateTableCommand.java index 81b39d2..bcf3812 100644 --- a/shell/src/main/java/org/apache/accumulo/shell/commands/CreateTableCommand.java +++ b/shell/src/main/java/org/apache/accumulo/shell/commands/CreateTableCommand.java @@ -19,12 +19,14 @@ package org.apache.accumulo.shell.commands; import java.io.IOException; import java.util.Map; import java.util.Map.Entry; +import java.util.HashMap; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import org.apache.accumulo.core.client.AccumuloException; import org.apache.accumulo.core.client.AccumuloSecurityException; +import org.apache.accumulo.core.client.NewTableConfiguration; import org.apache.accumulo.core.client.TableExistsException; import org.apache.accumulo.core.client.TableNotFoundException; import org.apache.accumulo.core.client.admin.TimeType; @@ -40,6 +42,7 @@ import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.Option; import org.apache.commons.cli.OptionGroup; import org.apache.commons.cli.Options; +import org.apache.commons.lang.StringUtils; import org.apache.hadoop.io.Text; public class CreateTableCommand extends Command { @@ -52,12 +55,14 @@ public class CreateTableCommand extends Command { private Option createTableOptEVC; private Option base64Opt; private Option createTableOptFormatter; + private Option createTableOptInitProp; @Override public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) throws AccumuloException, AccumuloSecurityException, TableExistsException, TableNotFoundException, IOException, ClassNotFoundException { final String testTableName = cl.getArgs()[0]; + final HashMap<String,String> props = new HashMap<String,String>(); if (!testTableName.matches(Tables.VALID_NAME_REGEX)) { shellState.getReader().println("Only letters, numbers and underscores are allowed for use in table names."); @@ -93,8 +98,16 @@ public class CreateTableCommand extends Command { timeType = TimeType.LOGICAL; } + if (cl.hasOption(createTableOptInitProp.getOpt())) { + String[] keyVals = StringUtils.split(cl.getOptionValue(createTableOptInitProp.getOpt()), ','); + for (String keyVal : keyVals) { + String[] sa = StringUtils.split(keyVal, '='); + props.put(sa[0], sa[1]); + } + } + // create table - shellState.getConnector().tableOperations().create(tableName, true, timeType); + shellState.getConnector().tableOperations().create(tableName, new NewTableConfiguration().setTimeType(timeType).setProperties(props)); if (partitions.size() > 0) { shellState.getConnector().tableOperations().addSplits(tableName, partitions); } @@ -134,7 +147,6 @@ public class CreateTableCommand extends Command { shellState.getConnector().tableOperations().setProperty(tableName, Property.TABLE_FORMATTER_CLASS.toString(), formatterClass); } - return 0; } @@ -161,11 +173,13 @@ public class CreateTableCommand extends Command { createTableOptEVC = new Option("evc", "enable-visibility-constraint", false, "prevent users from writing data they cannot read. When enabling this, consider disabling bulk import and alter table."); createTableOptFormatter = new Option("f", "formatter", true, "default formatter to set"); + createTableOptInitProp = new Option("prop", "init-properties", true, "user defined initial properties"); createTableOptCopyConfig.setArgName("table"); createTableOptCopySplits.setArgName("table"); createTableOptSplit.setArgName("filename"); createTableOptFormatter.setArgName("className"); + createTableOptInitProp.setArgName("properties"); // Splits and CopySplits are put in an optionsgroup to make them // mutually exclusive @@ -187,6 +201,7 @@ public class CreateTableCommand extends Command { o.addOption(createTableNoDefaultIters); o.addOption(createTableOptEVC); o.addOption(createTableOptFormatter); + o.addOption(createTableOptInitProp); return o; } http://git-wip-us.apache.org/repos/asf/accumulo/blob/afd1cb13/test/src/test/java/org/apache/accumulo/test/CreateTableWithNewTableConfigIT.java ---------------------------------------------------------------------- diff --git a/test/src/test/java/org/apache/accumulo/test/CreateTableWithNewTableConfigIT.java b/test/src/test/java/org/apache/accumulo/test/CreateTableWithNewTableConfigIT.java new file mode 100644 index 0000000..86d475c --- /dev/null +++ b/test/src/test/java/org/apache/accumulo/test/CreateTableWithNewTableConfigIT.java @@ -0,0 +1,191 @@ +/* + * 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.test; + +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.accumulo.core.client.AccumuloException; +import org.apache.accumulo.core.client.Connector; +import org.apache.accumulo.core.client.NewTableConfiguration; +import org.apache.accumulo.core.client.Scanner; +import org.apache.accumulo.core.client.TableNotFoundException; +import org.apache.accumulo.core.client.admin.TimeType; +import org.apache.accumulo.core.conf.Property; +import org.apache.accumulo.core.data.Key; +import org.apache.accumulo.core.data.Value; +import org.apache.accumulo.core.metadata.MetadataTable; +import org.apache.accumulo.core.metadata.schema.MetadataSchema; +import org.apache.accumulo.core.metadata.schema.MetadataSchema.TabletsSection.ServerColumnFamily; +import org.apache.accumulo.core.security.Authorizations; +import org.apache.accumulo.test.functional.SimpleMacIT; +import org.apache.log4j.Logger; +import org.junit.Assert; +import org.junit.Test; + +/** + * + */ +public class CreateTableWithNewTableConfigIT extends SimpleMacIT { + static private final Logger log = Logger.getLogger(CreateTableWithNewTableConfigIT.class); + + protected int defaultTimeoutSeconds() { + return 30; + }; + + public int numProperties(Connector connector, String tableName) throws AccumuloException, TableNotFoundException { + int countNew = 0; + for (Entry<String,String> entry : connector.tableOperations().getProperties(tableName)) { + countNew++; + } + + return countNew; + } + + public int compareProperties(Connector connector, String tableNameOrig, String tableName, String changedProp) throws AccumuloException, + TableNotFoundException { + boolean inNew = false; + int countOrig = 0; + for (Entry<String,String> orig : connector.tableOperations().getProperties(tableNameOrig)) { + countOrig++; + for (Entry<String,String> entry : connector.tableOperations().getProperties(tableName)) { + if (entry.equals(orig)) { + inNew = true; + break; + } else if (entry.getKey().equals(orig.getKey()) && !entry.getKey().equals(changedProp)) + Assert.fail("Property " + orig.getKey() + " has different value than deprecated method"); + } + if (!inNew) + Assert.fail("Original property missing after using the new create method"); + } + return countOrig; + } + + public boolean checkTimeType(Connector connector, String tableName, TimeType expectedTimeType) throws TableNotFoundException { + final Scanner scanner = connector.createScanner(MetadataTable.NAME, Authorizations.EMPTY); + String tableID = connector.tableOperations().tableIdMap().get(tableName) + "<"; + for (Entry<Key,Value> entry : scanner) { + Key k = entry.getKey(); + + if (k.getRow().toString().equals(tableID) && k.getColumnQualifier().toString().equals(ServerColumnFamily.TIME_COLUMN.getColumnQualifier().toString())) { + if (expectedTimeType == TimeType.MILLIS && entry.getValue().toString().charAt(0) == 'M') + return true; + if (expectedTimeType == TimeType.LOGICAL && entry.getValue().toString().charAt(0) == 'L') + return true; + } + } + return false; + } + + @Test + public void tableNameOnly() throws Exception { + log.info("Starting tableNameOnly"); + + // Create a table with the initial properties + Connector connector = getConnector(); + String tableName = getUniqueNames(2)[0]; + connector.tableOperations().create(tableName, new NewTableConfiguration()); + + String tableNameOrig = "original"; + connector.tableOperations().create(tableNameOrig, true); + + int countNew = numProperties(connector, tableName); + int countOrig = compareProperties(connector, tableNameOrig, tableName, null); + + Assert.assertEquals("Extra properties using the new create method", countOrig, countNew); + Assert.assertTrue("Wrong TimeType", checkTimeType(connector, tableName, TimeType.MILLIS)); + } + + @Test + public void tableNameAndLimitVersion() throws Exception { + log.info("Starting tableNameAndLimitVersion"); + + // Create a table with the initial properties + Connector connector = getConnector(); + String tableName = getUniqueNames(2)[0]; + boolean limitVersion = false; + connector.tableOperations().create(tableName, new NewTableConfiguration().withoutDefaultIterators()); + + String tableNameOrig = "originalWithLimitVersion"; + connector.tableOperations().create(tableNameOrig, limitVersion); + + int countNew = numProperties(connector, tableName); + int countOrig = compareProperties(connector, tableNameOrig, tableName, null); + + Assert.assertEquals("Extra properties using the new create method", countOrig, countNew); + Assert.assertTrue("Wrong TimeType", checkTimeType(connector, tableName, TimeType.MILLIS)); + } + + @Test + public void tableNameLimitVersionAndTimeType() throws Exception { + log.info("Starting tableNameLimitVersionAndTimeType"); + + // Create a table with the initial properties + Connector connector = getConnector(); + String tableName = getUniqueNames(2)[0]; + boolean limitVersion = false; + TimeType tt = TimeType.LOGICAL; + connector.tableOperations().create(tableName, new NewTableConfiguration().withoutDefaultIterators().setTimeType(tt)); + + String tableNameOrig = "originalWithLimitVersionAndTimeType"; + connector.tableOperations().create(tableNameOrig, limitVersion, tt); + + int countNew = numProperties(connector, tableName); + int countOrig = compareProperties(connector, tableNameOrig, tableName, null); + + Assert.assertEquals("Extra properties using the new create method", countOrig, countNew); + Assert.assertTrue("Wrong TimeType", checkTimeType(connector, tableName, tt)); + } + + @Test + public void addCustomPropAndChangeExisting() throws Exception { + log.info("Starting addCustomPropAndChangeExisting"); + + // Create and populate initial properties map for creating table 1 + Map<String,String> properties = new HashMap<String,String>(); + String propertyName = Property.TABLE_SPLIT_THRESHOLD.getKey(); + String volume = "10K"; + properties.put(propertyName, volume); + + String propertyName2 = "table.custom.testProp"; + String volume2 = "Test property"; + properties.put(propertyName2, volume2); + + // Create a table with the initial properties + Connector connector = getConnector(); + String tableName = getUniqueNames(2)[0]; + connector.tableOperations().create(tableName, new NewTableConfiguration().setProperties(properties)); + + String tableNameOrig = "originalWithTableName"; + connector.tableOperations().create(tableNameOrig, true); + + int countNew = numProperties(connector, tableName); + int countOrig = compareProperties(connector, tableNameOrig, tableName, propertyName); + + for (Entry<String,String> entry : connector.tableOperations().getProperties(tableName)) { + if (entry.getKey().equals(Property.TABLE_SPLIT_THRESHOLD.getKey())) + Assert.assertTrue("TABLE_SPLIT_THRESHOLD has been changed", entry.getValue().equals("10K")); + if (entry.getKey().equals("table.custom.testProp")) + Assert.assertTrue("table.custom.testProp has been changed", entry.getValue().equals("Test property")); + } + + Assert.assertEquals("Extra properties using the new create method", countOrig + 1, countNew); + Assert.assertTrue("Wrong TimeType", checkTimeType(connector, tableName, TimeType.MILLIS)); + + } +} http://git-wip-us.apache.org/repos/asf/accumulo/blob/afd1cb13/test/src/test/java/org/apache/accumulo/test/ShellServerIT.java ---------------------------------------------------------------------- diff --git a/test/src/test/java/org/apache/accumulo/test/ShellServerIT.java b/test/src/test/java/org/apache/accumulo/test/ShellServerIT.java index 4114dc8..0c219d6 100644 --- a/test/src/test/java/org/apache/accumulo/test/ShellServerIT.java +++ b/test/src/test/java/org/apache/accumulo/test/ShellServerIT.java @@ -70,6 +70,7 @@ import org.apache.hadoop.tools.DistCp; import org.apache.log4j.Logger; import org.junit.After; import org.junit.AfterClass; +import org.junit.Assert; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Rule; @@ -428,7 +429,7 @@ public class ShellServerIT extends SimpleMacIT { ts.exec("users", true, "xyzzy", false); } - @Test(timeout = 60 * 1000) + @Test public void durability() throws Exception { final String table = name.getMethodName(); ts.exec("createtable " + table); @@ -698,6 +699,32 @@ public class ShellServerIT extends SimpleMacIT { } @Test + public void createTableWithProperties() throws Exception { + final String table = name.getMethodName(); + + // create table with initial properties + String testProp = "table.custom.description=description,table.custom.testProp=testProp," + Property.TABLE_SPLIT_THRESHOLD.getKey() + "=10K"; + + ts.exec("createtable " + table + " -prop " + testProp, true); + ts.exec("insert a b c value", true); + ts.exec("scan", true, "value", true); + + Connector connector = getConnector(); + for (Entry<String,String> entry : connector.tableOperations().getProperties(table)) { + if (entry.getKey().equals("table.custom.description")) + Assert.assertTrue("Initial property was not set correctly", entry.getValue().equals("description")); + + if (entry.getKey().equals("table.custom.testProp")) + Assert.assertTrue("Initial property was not set correctly", entry.getValue().equals("testProp")); + + if (entry.getKey().equals(Property.TABLE_SPLIT_THRESHOLD.getKey())) + Assert.assertTrue("Initial property was not set correctly", entry.getValue().equals("10K")); + + } + ts.exec("deletetable -f " + table); + } + + @Test public void testCompactions() throws Exception { final String table = name.getMethodName();