use of org.apache.accumulo.core.client.impl.Table in project accumulo by apache.
the class ReplicationIT method replicatedStatusEntriesAreDeleted.
@Test
public void replicatedStatusEntriesAreDeleted() throws Exception {
// Just stop it now, we'll restart it after we restart the tserver
getCluster().getClusterControl().stop(ServerType.GARBAGE_COLLECTOR);
final Connector conn = getConnector();
log.info("Got connector to MAC");
String table1 = "table1";
// replication shouldn't be online when we begin
Assert.assertFalse(ReplicationTable.isOnline(conn));
// Create two tables
conn.tableOperations().create(table1);
int attempts = 5;
while (attempts > 0) {
try {
// Enable replication on table1
conn.tableOperations().setProperty(table1, Property.TABLE_REPLICATION.getKey(), "true");
// Replicate table1 to cluster1 in the table with id of '4'
conn.tableOperations().setProperty(table1, Property.TABLE_REPLICATION_TARGET.getKey() + "cluster1", "4");
// Use the MockReplicaSystem impl and sleep for 5seconds
conn.instanceOperations().setProperty(Property.REPLICATION_PEERS.getKey() + "cluster1", ReplicaSystemFactory.getPeerConfigurationValue(MockReplicaSystem.class, "1000"));
attempts = 0;
} catch (Exception e) {
attempts--;
if (attempts <= 0) {
throw e;
}
sleepUninterruptibly(500, TimeUnit.MILLISECONDS);
}
}
Table.ID tableId = Table.ID.of(conn.tableOperations().tableIdMap().get(table1));
Assert.assertNotNull("Could not determine table id for " + table1, tableId);
// Write some data to table1
writeSomeData(conn, table1, 2000, 50);
conn.tableOperations().flush(table1, null, null, true);
// Make sure the replication table exists at this point
while (!ReplicationTable.isOnline(conn)) {
sleepUninterruptibly(MILLIS_BETWEEN_REPLICATION_TABLE_ONLINE_CHECKS, TimeUnit.MILLISECONDS);
}
Assert.assertTrue("Replication table did not exist", ReplicationTable.isOnline(conn));
// Grant ourselves the write permission for later
conn.securityOperations().grantTablePermission("root", ReplicationTable.NAME, TablePermission.WRITE);
log.info("Checking for replication entries in replication");
// Then we need to get those records over to the replication table
Set<String> entries = new HashSet<>();
for (int i = 0; i < 5; i++) {
try (Scanner s = conn.createScanner(MetadataTable.NAME, Authorizations.EMPTY)) {
s.setRange(ReplicationSection.getRange());
entries.clear();
for (Entry<Key, Value> entry : s) {
entries.add(entry.getKey().getRow().toString());
log.info("{}={}", entry.getKey().toStringNoTruncate(), entry.getValue());
}
if (!entries.isEmpty()) {
log.info("Replication entries {}", entries);
break;
}
Thread.sleep(1000);
}
}
Assert.assertFalse("Did not find any replication entries in the replication table", entries.isEmpty());
// Find the WorkSection record that will be created for that data we ingested
boolean notFound = true;
for (int i = 0; i < 10 && notFound; i++) {
try (Scanner s = ReplicationTable.getScanner(conn)) {
WorkSection.limit(s);
Entry<Key, Value> e = Iterables.getOnlyElement(s);
log.info("Found entry: {}", e.getKey().toStringNoTruncate());
Text expectedColqual = new ReplicationTarget("cluster1", "4", tableId).toText();
Assert.assertEquals(expectedColqual, e.getKey().getColumnQualifier());
notFound = false;
} catch (NoSuchElementException e) {
} catch (IllegalArgumentException e) {
// Somehow we got more than one element. Log what they were
try (Scanner s = ReplicationTable.getScanner(conn)) {
for (Entry<Key, Value> content : s) {
log.info("{} => {}", content.getKey().toStringNoTruncate(), content.getValue());
}
Assert.fail("Found more than one work section entry");
}
} catch (RuntimeException e) {
// Catch a propagation issue, fail if it's not what we expect
Throwable cause = e.getCause();
if (cause instanceof AccumuloSecurityException) {
AccumuloSecurityException sec = (AccumuloSecurityException) cause;
switch(sec.getSecurityErrorCode()) {
case PERMISSION_DENIED:
// retry -- the grant didn't happen yet
log.warn("Sleeping because permission was denied");
break;
default:
throw e;
}
} else {
throw e;
}
}
Thread.sleep(2000);
}
if (notFound) {
try (Scanner s = ReplicationTable.getScanner(conn)) {
for (Entry<Key, Value> content : s) {
log.info("{} => {}", content.getKey().toStringNoTruncate(), ProtobufUtil.toString(Status.parseFrom(content.getValue().get())));
}
Assert.assertFalse("Did not find the work entry for the status entry", notFound);
}
}
/**
* By this point, we should have data ingested into a table, with at least one WAL as a candidate for replication. Compacting the table should close all
* open WALs, which should ensure all records we're going to replicate have entries in the replication table, and nothing will exist in the metadata table
* anymore
*/
log.info("Killing tserver");
// Kill the tserver(s) and restart them
// to ensure that the WALs we previously observed all move to closed.
cluster.getClusterControl().stop(ServerType.TABLET_SERVER);
log.info("Starting tserver");
cluster.getClusterControl().start(ServerType.TABLET_SERVER);
log.info("Waiting to read tables");
sleepUninterruptibly(2 * 3, TimeUnit.SECONDS);
// Make sure we can read all the tables (recovery complete)
for (String table : new String[] { MetadataTable.NAME, table1 }) {
Iterators.size(conn.createScanner(table, Authorizations.EMPTY).iterator());
}
log.info("Recovered metadata:");
try (Scanner s = conn.createScanner(MetadataTable.NAME, Authorizations.EMPTY)) {
for (Entry<Key, Value> entry : s) {
log.info("{}={}", entry.getKey().toStringNoTruncate(), entry.getValue());
}
}
cluster.getClusterControl().start(ServerType.GARBAGE_COLLECTOR);
// Wait for a bit since the GC has to run (should be running after a one second delay)
waitForGCLock(conn);
Thread.sleep(1000);
log.info("After GC");
try (Scanner s = conn.createScanner(MetadataTable.NAME, Authorizations.EMPTY)) {
for (Entry<Key, Value> entry : s) {
log.info("{}={}", entry.getKey().toStringNoTruncate(), entry.getValue());
}
}
// We expect no records in the metadata table after compaction. We have to poll
// because we have to wait for the StatusMaker's next iteration which will clean
// up the dangling *closed* records after we create the record in the replication table.
// We need the GC to close the file (CloseWriteAheadLogReferences) before we can remove the record
log.info("Checking metadata table for replication entries");
Set<String> remaining = new HashSet<>();
for (int i = 0; i < 10; i++) {
try (Scanner s = conn.createScanner(MetadataTable.NAME, Authorizations.EMPTY)) {
s.setRange(ReplicationSection.getRange());
remaining.clear();
for (Entry<Key, Value> e : s) {
remaining.add(e.getKey().getRow().toString());
}
remaining.retainAll(entries);
if (remaining.isEmpty()) {
break;
}
log.info("remaining {}", remaining);
Thread.sleep(2000);
log.info("");
}
}
Assert.assertTrue("Replication status messages were not cleaned up from metadata table", remaining.isEmpty());
/**
* After we close out and subsequently delete the metadata record, this will propagate to the replication table, which will cause those records to be
* deleted after replication occurs
*/
int recordsFound = 0;
for (int i = 0; i < 30; i++) {
try (Scanner s = ReplicationTable.getScanner(conn)) {
recordsFound = 0;
for (Entry<Key, Value> entry : s) {
recordsFound++;
log.info("{} {}", entry.getKey().toStringNoTruncate(), ProtobufUtil.toString(Status.parseFrom(entry.getValue().get())));
}
if (recordsFound <= 2) {
break;
} else {
Thread.sleep(1000);
log.info("");
}
}
}
Assert.assertTrue("Found unexpected replication records in the replication table", recordsFound <= 2);
}
use of org.apache.accumulo.core.client.impl.Table in project accumulo by apache.
the class ReplicationOperationsImplIT method laterCreatedLogsDontBlockExecution.
@Test
public void laterCreatedLogsDontBlockExecution() throws Exception {
conn.tableOperations().create("foo");
Table.ID tableId1 = Table.ID.of(conn.tableOperations().tableIdMap().get("foo"));
String file1 = "/accumulo/wals/tserver+port/" + UUID.randomUUID();
Status stat = Status.newBuilder().setBegin(0).setEnd(10000).setInfiniteEnd(false).setClosed(false).build();
BatchWriter bw = ReplicationTable.getBatchWriter(conn);
Mutation m = new Mutation(file1);
StatusSection.add(m, tableId1, ProtobufUtil.toValue(stat));
bw.addMutation(m);
bw.close();
bw = conn.createBatchWriter(MetadataTable.NAME, new BatchWriterConfig());
m = new Mutation(ReplicationSection.getRowPrefix() + file1);
m.put(ReplicationSection.COLF, new Text(tableId1.getUtf8()), ProtobufUtil.toValue(stat));
bw.addMutation(m);
bw.close();
log.info("Reading metadata first time");
for (Entry<Key, Value> e : conn.createScanner(MetadataTable.NAME, Authorizations.EMPTY)) {
log.info("{}", e.getKey());
}
final AtomicBoolean done = new AtomicBoolean(false);
final AtomicBoolean exception = new AtomicBoolean(false);
final ReplicationOperationsImpl roi = getReplicationOperations();
Thread t = new Thread(new Runnable() {
@Override
public void run() {
try {
roi.drain("foo");
} catch (Exception e) {
log.error("Got error", e);
exception.set(true);
}
done.set(true);
}
});
t.start();
// We need to wait long enough for the table to read once
Thread.sleep(2000);
// Write another file, but also delete the old files
bw = conn.createBatchWriter(MetadataTable.NAME, new BatchWriterConfig());
m = new Mutation(ReplicationSection.getRowPrefix() + "/accumulo/wals/tserver+port/" + UUID.randomUUID());
m.put(ReplicationSection.COLF, new Text(tableId1.getUtf8()), ProtobufUtil.toValue(stat));
bw.addMutation(m);
m = new Mutation(ReplicationSection.getRowPrefix() + file1);
m.putDelete(ReplicationSection.COLF, new Text(tableId1.getUtf8()));
bw.addMutation(m);
bw.close();
log.info("Reading metadata second time");
for (Entry<Key, Value> e : conn.createScanner(MetadataTable.NAME, Authorizations.EMPTY)) {
log.info("{}", e.getKey());
}
bw = ReplicationTable.getBatchWriter(conn);
m = new Mutation(file1);
m.putDelete(StatusSection.NAME, new Text(tableId1.getUtf8()));
bw.addMutation(m);
bw.close();
try {
t.join(5000);
} catch (InterruptedException e) {
Assert.fail("ReplicationOperations.drain did not complete");
}
// We should pass immediately because we aren't waiting on both files to be deleted (just the one that we did)
Assert.assertTrue("Drain didn't finish", done.get());
}
use of org.apache.accumulo.core.client.impl.Table in project accumulo by apache.
the class CollectTabletStats method main.
public static void main(String[] args) throws Exception {
final CollectOptions opts = new CollectOptions();
final ScannerOpts scanOpts = new ScannerOpts();
opts.parseArgs(CollectTabletStats.class.getName(), args, scanOpts);
String[] columnsTmp = new String[] {};
if (opts.columns != null)
columnsTmp = opts.columns.split(",");
final String[] columns = columnsTmp;
final VolumeManager fs = VolumeManagerImpl.get();
Instance instance = opts.getInstance();
final ServerConfigurationFactory sconf = new ServerConfigurationFactory(instance);
Credentials creds = new Credentials(opts.getPrincipal(), opts.getToken());
ClientContext context = new ClientContext(instance, creds, sconf.getSystemConfiguration());
Table.ID tableId = Tables.getTableId(instance, opts.getTableName());
if (tableId == null) {
log.error("Unable to find table named {}", opts.getTableName());
System.exit(-1);
}
TreeMap<KeyExtent, String> tabletLocations = new TreeMap<>();
List<KeyExtent> candidates = findTablets(context, !opts.selectFarTablets, opts.getTableName(), tabletLocations);
if (candidates.size() < opts.numThreads) {
System.err.println("ERROR : Unable to find " + opts.numThreads + " " + (opts.selectFarTablets ? "far" : "local") + " tablets");
System.exit(-1);
}
List<KeyExtent> tabletsToTest = selectRandomTablets(opts.numThreads, candidates);
Map<KeyExtent, List<FileRef>> tabletFiles = new HashMap<>();
for (KeyExtent ke : tabletsToTest) {
List<FileRef> files = getTabletFiles(context, ke);
tabletFiles.put(ke, files);
}
System.out.println();
System.out.println("run location : " + InetAddress.getLocalHost().getHostName() + "/" + InetAddress.getLocalHost().getHostAddress());
System.out.println("num threads : " + opts.numThreads);
System.out.println("table : " + opts.getTableName());
System.out.println("table id : " + tableId);
for (KeyExtent ke : tabletsToTest) {
System.out.println("\t *** Information about tablet " + ke.getUUID() + " *** ");
System.out.println("\t\t# files in tablet : " + tabletFiles.get(ke).size());
System.out.println("\t\ttablet location : " + tabletLocations.get(ke));
reportHdfsBlockLocations(tabletFiles.get(ke));
}
System.out.println("%n*** RUNNING TEST ***%n");
ExecutorService threadPool = Executors.newFixedThreadPool(opts.numThreads);
for (int i = 0; i < opts.iterations; i++) {
ArrayList<Test> tests = new ArrayList<>();
for (final KeyExtent ke : tabletsToTest) {
final List<FileRef> files = tabletFiles.get(ke);
Test test = new Test(ke) {
@Override
public int runTest() throws Exception {
return readFiles(fs, sconf.getSystemConfiguration(), files, ke, columns);
}
};
tests.add(test);
}
runTest("read files", tests, opts.numThreads, threadPool);
}
for (int i = 0; i < opts.iterations; i++) {
ArrayList<Test> tests = new ArrayList<>();
for (final KeyExtent ke : tabletsToTest) {
final List<FileRef> files = tabletFiles.get(ke);
Test test = new Test(ke) {
@Override
public int runTest() throws Exception {
return readFilesUsingIterStack(fs, sconf, files, opts.auths, ke, columns, false);
}
};
tests.add(test);
}
runTest("read tablet files w/ system iter stack", tests, opts.numThreads, threadPool);
}
for (int i = 0; i < opts.iterations; i++) {
ArrayList<Test> tests = new ArrayList<>();
for (final KeyExtent ke : tabletsToTest) {
final List<FileRef> files = tabletFiles.get(ke);
Test test = new Test(ke) {
@Override
public int runTest() throws Exception {
return readFilesUsingIterStack(fs, sconf, files, opts.auths, ke, columns, true);
}
};
tests.add(test);
}
runTest("read tablet files w/ table iter stack", tests, opts.numThreads, threadPool);
}
for (int i = 0; i < opts.iterations; i++) {
ArrayList<Test> tests = new ArrayList<>();
final Connector conn = opts.getConnector();
for (final KeyExtent ke : tabletsToTest) {
Test test = new Test(ke) {
@Override
public int runTest() throws Exception {
return scanTablet(conn, opts.getTableName(), opts.auths, scanOpts.scanBatchSize, ke.getPrevEndRow(), ke.getEndRow(), columns);
}
};
tests.add(test);
}
runTest("read tablet data through accumulo", tests, opts.numThreads, threadPool);
}
for (final KeyExtent ke : tabletsToTest) {
final Connector conn = opts.getConnector();
threadPool.submit(new Runnable() {
@Override
public void run() {
try {
calcTabletStats(conn, opts.getTableName(), opts.auths, scanOpts.scanBatchSize, ke, columns);
} catch (Exception e) {
log.error("Failed to calculate tablet stats.", e);
}
}
});
}
threadPool.shutdown();
}
use of org.apache.accumulo.core.client.impl.Table in project accumulo by apache.
the class UnusedWalDoesntCloseReplicationStatusIT method test.
@Test
public void test() throws Exception {
File accumuloDir = this.getCluster().getConfig().getAccumuloDir();
final Connector conn = getConnector();
final String tableName = getUniqueNames(1)[0];
conn.securityOperations().grantTablePermission("root", MetadataTable.NAME, TablePermission.WRITE);
conn.tableOperations().create(tableName);
final Table.ID tableId = Table.ID.of(conn.tableOperations().tableIdMap().get(tableName));
final int numericTableId = Integer.parseInt(tableId.canonicalID());
final int fakeTableId = numericTableId + 1;
Assert.assertNotNull("Did not find table ID", tableId);
conn.tableOperations().setProperty(tableName, Property.TABLE_REPLICATION.getKey(), "true");
conn.tableOperations().setProperty(tableName, Property.TABLE_REPLICATION_TARGET.getKey() + "cluster1", "1");
// just sleep
conn.instanceOperations().setProperty(Property.REPLICATION_PEERS.getKey() + "cluster1", ReplicaSystemFactory.getPeerConfigurationValue(MockReplicaSystem.class, "50000"));
FileSystem fs = FileSystem.getLocal(new Configuration());
File tserverWalDir = new File(accumuloDir, ServerConstants.WAL_DIR + Path.SEPARATOR + "faketserver+port");
File tserverWal = new File(tserverWalDir, UUID.randomUUID().toString());
fs.mkdirs(new Path(tserverWalDir.getAbsolutePath()));
// Make a fake WAL with no data in it for our real table
FSDataOutputStream out = fs.create(new Path(tserverWal.getAbsolutePath()));
out.write(DfsLogger.LOG_FILE_HEADER_V3.getBytes(UTF_8));
DataOutputStream dos = new DataOutputStream(out);
dos.writeUTF("NullCryptoModule");
// Fake a single update WAL that has a mutation for another table
LogFileKey key = new LogFileKey();
LogFileValue value = new LogFileValue();
key.event = OPEN;
key.tserverSession = tserverWal.getAbsolutePath();
key.filename = tserverWal.getAbsolutePath();
key.write(out);
value.write(out);
key.event = LogEvents.DEFINE_TABLET;
key.tablet = new KeyExtent(Table.ID.of(Integer.toString(fakeTableId)), null, null);
key.seq = 1l;
key.tid = 1;
key.write(dos);
value.write(dos);
key.tablet = null;
key.event = LogEvents.MUTATION;
key.filename = tserverWal.getAbsolutePath();
value.mutations = Arrays.asList(new ServerMutation(new Text("row")));
key.write(dos);
value.write(dos);
key.event = LogEvents.COMPACTION_START;
key.filename = accumuloDir.getAbsolutePath() + "/tables/" + fakeTableId + "/t-000001/A000001.rf";
value.mutations = Collections.emptyList();
key.write(dos);
value.write(dos);
key.event = LogEvents.COMPACTION_FINISH;
value.mutations = Collections.emptyList();
key.write(dos);
value.write(dos);
dos.close();
BatchWriter bw = conn.createBatchWriter(tableName, new BatchWriterConfig());
Mutation m = new Mutation("m");
m.put("m", "m", "M");
bw.addMutation(m);
bw.close();
log.info("State of metadata table after inserting a record");
try (Scanner s = conn.createScanner(MetadataTable.NAME, Authorizations.EMPTY)) {
s.setRange(MetadataSchema.TabletsSection.getRange(tableId));
for (Entry<Key, Value> entry : s) {
System.out.println(entry.getKey().toStringNoTruncate() + " " + entry.getValue());
}
}
try (Scanner s = conn.createScanner(MetadataTable.NAME, Authorizations.EMPTY)) {
s.setRange(MetadataSchema.ReplicationSection.getRange());
for (Entry<Key, Value> entry : s) {
System.out.println(entry.getKey().toStringNoTruncate() + " " + ProtobufUtil.toString(Status.parseFrom(entry.getValue().get())));
}
log.info("Offline'ing table");
conn.tableOperations().offline(tableName, true);
// Add our fake WAL to the log column for this table
String walUri = tserverWal.toURI().toString();
KeyExtent extent = new KeyExtent(tableId, null, null);
bw = conn.createBatchWriter(MetadataTable.NAME, new BatchWriterConfig());
m = new Mutation(extent.getMetadataEntry());
m.put(MetadataSchema.TabletsSection.LogColumnFamily.NAME, new Text("localhost:12345/" + walUri), new Value((walUri + "|1").getBytes(UTF_8)));
bw.addMutation(m);
// Add a replication entry for our fake WAL
m = new Mutation(MetadataSchema.ReplicationSection.getRowPrefix() + new Path(walUri).toString());
m.put(MetadataSchema.ReplicationSection.COLF, new Text(tableId.getUtf8()), new Value(StatusUtil.fileCreated(System.currentTimeMillis()).toByteArray()));
bw.addMutation(m);
bw.close();
log.info("State of metadata after injecting WAL manually");
}
try (Scanner s = conn.createScanner(MetadataTable.NAME, Authorizations.EMPTY)) {
s.setRange(MetadataSchema.TabletsSection.getRange(tableId));
for (Entry<Key, Value> entry : s) {
log.info("{} {}", entry.getKey().toStringNoTruncate(), entry.getValue());
}
}
try (Scanner s = conn.createScanner(MetadataTable.NAME, Authorizations.EMPTY)) {
s.setRange(MetadataSchema.ReplicationSection.getRange());
for (Entry<Key, Value> entry : s) {
log.info("{} {}", entry.getKey().toStringNoTruncate(), ProtobufUtil.toString(Status.parseFrom(entry.getValue().get())));
}
log.info("Bringing table online");
conn.tableOperations().online(tableName, true);
Assert.assertEquals(1, Iterables.size(conn.createScanner(tableName, Authorizations.EMPTY)));
log.info("Table has performed recovery, state of metadata:");
}
try (Scanner s = conn.createScanner(MetadataTable.NAME, Authorizations.EMPTY)) {
s.setRange(MetadataSchema.TabletsSection.getRange(tableId));
for (Entry<Key, Value> entry : s) {
log.info("{} {}", entry.getKey().toStringNoTruncate(), entry.getValue());
}
}
try (Scanner s = conn.createScanner(MetadataTable.NAME, Authorizations.EMPTY)) {
s.setRange(MetadataSchema.ReplicationSection.getRange());
for (Entry<Key, Value> entry : s) {
Status status = Status.parseFrom(entry.getValue().get());
log.info("{} {}", entry.getKey().toStringNoTruncate(), ProtobufUtil.toString(status));
Assert.assertFalse("Status record was closed and it should not be", status.getClosed());
}
}
}
use of org.apache.accumulo.core.client.impl.Table in project accumulo by apache.
the class WorkMakerIT method singleUnitSingleTarget.
@Test
public void singleUnitSingleTarget() throws Exception {
String table = testName.getMethodName();
conn.tableOperations().create(table);
Table.ID tableId = Table.ID.of(conn.tableOperations().tableIdMap().get(table));
String file = "hdfs://localhost:8020/accumulo/wal/123456-1234-1234-12345678";
// Create a status record for a file
long timeCreated = System.currentTimeMillis();
Mutation m = new Mutation(new Path(file).toString());
m.put(StatusSection.NAME, new Text(tableId.getUtf8()), StatusUtil.fileCreatedValue(timeCreated));
BatchWriter bw = ReplicationTable.getBatchWriter(conn);
bw.addMutation(m);
bw.flush();
// Assert that we have one record in the status section
ReplicationTarget expected;
try (Scanner s = ReplicationTable.getScanner(conn)) {
StatusSection.limit(s);
Assert.assertEquals(1, Iterables.size(s));
MockWorkMaker workMaker = new MockWorkMaker(conn);
// Invoke the addWorkRecord method to create a Work record from the Status record earlier
expected = new ReplicationTarget("remote_cluster_1", "4", tableId);
workMaker.setBatchWriter(bw);
workMaker.addWorkRecord(new Text(file), StatusUtil.fileCreatedValue(timeCreated), ImmutableMap.of("remote_cluster_1", "4"), tableId);
}
// Scan over just the WorkSection
try (Scanner s = ReplicationTable.getScanner(conn)) {
WorkSection.limit(s);
Entry<Key, Value> workEntry = Iterables.getOnlyElement(s);
Key workKey = workEntry.getKey();
ReplicationTarget actual = ReplicationTarget.from(workKey.getColumnQualifier());
Assert.assertEquals(file, workKey.getRow().toString());
Assert.assertEquals(WorkSection.NAME, workKey.getColumnFamily());
Assert.assertEquals(expected, actual);
Assert.assertEquals(workEntry.getValue(), StatusUtil.fileCreatedValue(timeCreated));
}
}
Aggregations