blob: b89c223aa67e7670de11f679709cefc130429bf4 [file] [log] [blame]
/*
* 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.functional;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map.Entry;
import java.util.SortedSet;
import java.util.TreeSet;
import org.apache.accumulo.core.client.BatchWriter;
import org.apache.accumulo.core.client.Connector;
import org.apache.accumulo.core.client.Scanner;
import org.apache.accumulo.core.data.Key;
import org.apache.accumulo.core.data.Mutation;
import org.apache.accumulo.core.data.Value;
import org.apache.accumulo.core.security.Authorizations;
import org.apache.accumulo.harness.AccumuloClusterHarness;
import org.apache.hadoop.io.Text;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.Iterators;
public class DeleteRowsIT extends AccumuloClusterHarness {
@Override
protected int defaultTimeoutSeconds() {
return 5 * 60;
}
private static final Logger log = LoggerFactory.getLogger(DeleteRowsIT.class);
private static final int ROWS_PER_TABLET = 10;
private static final String[] LETTERS = new String[] {"a", "b", "c", "d", "e", "f", "g", "h", "i",
"j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"};
static final SortedSet<Text> SPLITS = new TreeSet<>();
static {
for (String alpha : LETTERS) {
SPLITS.add(new Text(alpha));
}
}
static final List<String> ROWS = new ArrayList<>(Arrays.asList(LETTERS));
static {
// put data on first and last tablet
ROWS.add("A");
ROWS.add("{");
}
@Test
public void testDeleteAllRows() throws Exception {
Connector c = getConnector();
String[] tableNames = this.getUniqueNames(20);
for (String tableName : tableNames) {
c.tableOperations().create(tableName);
c.tableOperations().deleteRows(tableName, null, null);
Scanner scanner = c.createScanner(tableName, Authorizations.EMPTY);
assertEquals(0, Iterators.size(scanner.iterator()));
}
}
@Test
public void testManyRows() throws Exception {
// Delete ranges of rows, and verify the tablets are removed.
int i = 0;
// Eliminate whole tablets
String tableName = getUniqueNames(1)[0];
testSplit(tableName + i++, "f", "h", "abcdefijklmnopqrstuvwxyz", 260);
// Eliminate whole tablets, partial first tablet
testSplit(tableName + i++, "f1", "h", "abcdeff1ijklmnopqrstuvwxyz", 262);
// Eliminate whole tablets, partial last tablet
testSplit(tableName + i++, "f", "h1", "abcdefijklmnopqrstuvwxyz", 258);
// Eliminate whole tablets, partial first and last tablet
testSplit(tableName + i++, "f1", "h1", "abcdeff1ijklmnopqrstuvwxyz", 260);
// Eliminate one tablet
testSplit(tableName + i++, "f", "g", "abcdefhijklmnopqrstuvwxyz", 270);
// Eliminate partial tablet, matches start split
testSplit(tableName + i++, "f", "f1", "abcdefghijklmnopqrstuvwxyz", 278);
// Eliminate partial tablet, matches end split
testSplit(tableName + i++, "f1", "g", "abcdeff1hijklmnopqrstuvwxyz", 272);
// Eliminate tablets starting at -inf
testSplit(tableName + i++, null, "h", "ijklmnopqrstuvwxyz", 200);
// Eliminate tablets ending at +inf
testSplit(tableName + i++, "t", null, "abcdefghijklmnopqrst", 200);
// Eliminate some rows inside one tablet
testSplit(tableName + i++, "t0", "t2", "abcdefghijklmnopqrstt0uvwxyz", 278);
// Eliminate some rows in the first tablet
testSplit(tableName + i++, null, "A1", "abcdefghijklmnopqrstuvwxyz", 278);
// Eliminate some rows in the last tablet
testSplit(tableName + i++, "{1", null, "abcdefghijklmnopqrstuvwxyz{1", 272);
// Delete everything
testSplit(tableName + i++, null, null, "", 0);
}
private void testSplit(String table, String start, String end, String result, int entries)
throws Exception {
// Put a bunch of rows on each tablet
Connector c = getConnector();
c.tableOperations().create(table);
BatchWriter bw = c.createBatchWriter(table, null);
for (String row : ROWS) {
for (int j = 0; j < ROWS_PER_TABLET; j++) {
Mutation m = new Mutation(row + j);
m.put("cf", "cq", "value");
bw.addMutation(m);
}
}
bw.flush();
bw.close();
// Split the table
c.tableOperations().addSplits(table, SPLITS);
Text startText = start == null ? null : new Text(start);
Text endText = end == null ? null : new Text(end);
c.tableOperations().deleteRows(table, startText, endText);
Collection<Text> remainingSplits = c.tableOperations().listSplits(table);
StringBuilder sb = new StringBuilder();
// See that whole tablets are removed
for (Text split : remainingSplits)
sb.append(split.toString());
assertEquals(result, sb.toString());
// See that the rows are really deleted
Scanner scanner = c.createScanner(table, Authorizations.EMPTY);
int count = 0;
for (Entry<Key,Value> entry : scanner) {
Text row = entry.getKey().getRow();
assertTrue((startText == null || row.compareTo(startText) <= 0)
|| (endText == null || row.compareTo(endText) > 0));
assertTrue(startText != null || endText != null);
count++;
}
log.info("Finished table " + table);
assertEquals(entries, count);
}
}