This is an automated email from the ASF dual-hosted git repository. jmark99 pushed a commit to branch 1.10 in repository https://gitbox.apache.org/repos/asf/accumulo.git
The following commit(s) were added to refs/heads/1.10 by this push: new b94ce9a Fix incorrect scan range output in getsplits command (#2370) b94ce9a is described below commit b94ce9ac73328488f8f8dd55dfa77e3795353515 Author: Mark Owens <jmar...@apache.org> AuthorDate: Mon Nov 29 13:16:54 2021 -0500 Fix incorrect scan range output in getsplits command (#2370) In the Accumulo shell, calling getsplits with the verbose option can result in incorret output. It occurs when the tableId of the table happens to be a single character and there are other tables where the tableId starts with the same character. This results in the output of getsplits displaying splits for the other tables as well. Added a couple of grammatical fixes based upon @millerruntime suggestions. Closes #2356 --- .../accumulo/shell/commands/GetSplitsCommand.java | 2 + .../org/apache/accumulo/test/ShellServerIT.java | 75 +++++++++++++++++++++- 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/shell/src/main/java/org/apache/accumulo/shell/commands/GetSplitsCommand.java b/shell/src/main/java/org/apache/accumulo/shell/commands/GetSplitsCommand.java index 0eae20b..a89d797 100644 --- a/shell/src/main/java/org/apache/accumulo/shell/commands/GetSplitsCommand.java +++ b/shell/src/main/java/org/apache/accumulo/shell/commands/GetSplitsCommand.java @@ -81,6 +81,8 @@ public class GetSplitsCommand extends Command { final Text start = new Text(shellState.getConnector().tableOperations().tableIdMap().get(tableName)); final Text end = new Text(start); + // do not append the ';' until the end value above is assigned. + start.append(new byte[] {';'}, 0, 1); end.append(new byte[] {'<'}, 0, 1); scanner.setRange(new Range(start, end)); for (Iterator<Entry<Key,Value>> iterator = scanner.iterator(); iterator.hasNext();) { 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 8f009f3..5c874ab 100644 --- a/test/src/main/java/org/apache/accumulo/test/ShellServerIT.java +++ b/test/src/main/java/org/apache/accumulo/test/ShellServerIT.java @@ -327,7 +327,7 @@ public class ShellServerIT extends SharedMiniClusterBase { @Override public int defaultTimeoutSeconds() { - return 60; + return 180; } @Test @@ -2063,4 +2063,77 @@ public class ShellServerIT extends SharedMiniClusterBase { return null; } + // This test addresses a bug (#2356) where if a table with a tableId of character length 1 + // exists and another table(s) exist starting with the same character but with a tableId of + // length > 1, the verbose version of the getsplits command will return information from multiple + // tables when a lexicographical ordered table with an earlier ID is queried. + // + // In order to test, enough tables need to be created until the required condition exists. + // Since table ID counts increment using 1..9a..z, this test creates tables in groups of 36 + // until a second table meeting the criteria is created. + // It then adds splits to the single digit ID table and one of the others. It performs a + // "getsplits -v" command on the single digit ID table and verifies that data from the other + // table is not present. + // + // Due to the number for createtable calls, this test will time out if a match is not found + // within some number of operations. Therefore, if a match is not found within the creation + // of the first 360 or so tables, the test exits with no results. In initial runs of the ITs + // this never occurred. + @Test + public void testGetSplitsScanRange() throws Exception { + Shell.log.debug("Starting testGetSplitsScanRange test ------------------"); + int idCycleLen = 36; + int maxLoopcnt = 10; + int postModifier = 0; + int loopCnt = 0; + + String[] tables = new String[2]; + Connector conn = getCluster().getConnector(getPrincipal(), getToken()); + while (loopCnt++ < maxLoopcnt) { + Map<String,String> idMap = conn.tableOperations().tableIdMap(); + if (findIds(tables, idMap)) { + break; + } + createTables(idCycleLen, postModifier++); + } + if (loopCnt >= maxLoopcnt) { + Shell.log.warn("Warning: Unable to find needed tables...exiting test without verifying."); + return; + } + // add splits to the two tables + ts.exec("addsplits -t " + tables[0] + " a c e", true); + ts.exec("addsplits -t " + tables[1] + " g i t", true); + // first table should contain supplied string + ts.exec("getsplits -v -t " + tables[0], true, "(e, +inf) Default Tablet", true); + // first table should not contain the supplied string + ts.exec("getsplits -v -t " + tables[0], true, "(t, +inf) Default Tablet", false); + } + + private boolean findIds(String[] tables, Map<String,String> idMap) { + String ids = "0123456789abcdefghijklmnopqrstuvwxyz"; + for (int i = 0; i < ids.length(); i++) { + String id = ids.substring(i, i + 1); + if (idMap.containsValue(id) && idMap.containsValue(id + "0")) { + tables[0] = getTableNameFromId(idMap, id); + tables[1] = getTableNameFromId(idMap, id + "0"); + Shell.log + .debug("Found tables: " + tables[0] + ":" + id + ", " + tables[1] + ":" + id + "0"); + return true; + } + } + return false; + } + + private String getTableNameFromId(Map<String,String> map, String value) { + return map.entrySet().stream().filter(entry -> value.equals(entry.getValue())) + .map(Map.Entry::getKey).findFirst().get(); + } + + private void createTables(final int limit, final int modifier) throws IOException { + String postfix = Integer.toString(modifier); + for (int i = 0; i < limit; i++) { + ts.exec("createtable tabx" + Integer.toString(i) + postfix); + } + } + }