use of org.apache.accumulo.core.metadata.schema.TabletsMetadata in project accumulo by apache.
the class TableOperationsImpl method waitForTableStateTransition.
private void waitForTableStateTransition(TableId tableId, TableState expectedState) throws AccumuloException, TableNotFoundException {
Text startRow = null;
Text lastRow = null;
while (true) {
if (context.getTableState(tableId) != expectedState) {
context.clearTableListCache();
TableState currentState = context.getTableState(tableId);
if (currentState != expectedState) {
context.requireNotDeleted(tableId);
if (currentState == TableState.DELETING)
throw new TableNotFoundException(tableId.canonical(), "", TABLE_DELETED_MSG);
throw new AccumuloException("Unexpected table state " + tableId + " " + currentState + " != " + expectedState);
}
}
Range range;
if (startRow == null || lastRow == null)
range = new KeyExtent(tableId, null, null).toMetaRange();
else
range = new Range(startRow, lastRow);
TabletsMetadata tablets = TabletsMetadata.builder(context).scanMetadataTable().overRange(range).fetch(LOCATION, PREV_ROW).build();
KeyExtent lastExtent = null;
int total = 0;
int waitFor = 0;
int holes = 0;
Text continueRow = null;
MapCounter<String> serverCounts = new MapCounter<>();
for (TabletMetadata tablet : tablets) {
total++;
Location loc = tablet.getLocation();
if ((expectedState == TableState.ONLINE && (loc == null || loc.getType() == LocationType.FUTURE)) || (expectedState == TableState.OFFLINE && loc != null)) {
if (continueRow == null)
continueRow = tablet.getExtent().toMetaRow();
waitFor++;
lastRow = tablet.getExtent().toMetaRow();
if (loc != null) {
serverCounts.increment(loc.getHostPortSession(), 1);
}
}
if (!tablet.getExtent().tableId().equals(tableId)) {
throw new AccumuloException("Saw unexpected table Id " + tableId + " " + tablet.getExtent());
}
if (lastExtent != null && !tablet.getExtent().isPreviousExtent(lastExtent)) {
holes++;
}
lastExtent = tablet.getExtent();
}
if (continueRow != null) {
startRow = continueRow;
}
if (holes > 0 || total == 0) {
startRow = null;
lastRow = null;
}
if (waitFor > 0 || holes > 0 || total == 0) {
long waitTime;
long maxPerServer = 0;
if (serverCounts.size() > 0) {
maxPerServer = serverCounts.max();
waitTime = maxPerServer * 10;
} else
waitTime = waitFor * 10L;
waitTime = Math.max(100, waitTime);
waitTime = Math.min(5000, waitTime);
log.trace("Waiting for {}({}) tablets, startRow = {} lastRow = {}, holes={} sleeping:{}ms", waitFor, maxPerServer, startRow, lastRow, holes, waitTime);
sleepUninterruptibly(waitTime, MILLISECONDS);
} else {
break;
}
}
}
use of org.apache.accumulo.core.metadata.schema.TabletsMetadata in project accumulo by apache.
the class TabletServer method run.
// main loop listens for client requests
@Override
public void run() {
SecurityUtil.serverLogin(getConfiguration());
// To make things easier on users/devs, and to avoid creating an upgrade path to 1.7
// We can just make the zookeeper paths before we try to use.
initializeZkForReplication();
if (authKeyWatcher != null) {
log.info("Seeding ZooKeeper watcher for authentication keys");
try {
authKeyWatcher.updateAuthKeys();
} catch (KeeperException | InterruptedException e) {
// TODO Does there need to be a better check? What are the error conditions that we'd fall
// out here? AUTH_FAILURE?
// If we get the error, do we just put it on a timer and retry the exists(String, Watcher)
// call?
log.error("Failed to perform initial check for authentication tokens in" + " ZooKeeper. Delegation token authentication will be unavailable.", e);
}
}
try {
clientAddress = startTabletClientService();
} catch (UnknownHostException e1) {
throw new RuntimeException("Failed to start the tablet client service", e1);
}
announceExistence();
try {
MetricsUtil.initializeMetrics(context.getConfiguration(), this.applicationName, clientAddress);
} catch (Exception e1) {
log.error("Error initializing metrics, metrics will not be emitted.", e1);
}
metrics = new TabletServerMetrics(this);
updateMetrics = new TabletServerUpdateMetrics();
scanMetrics = new TabletServerScanMetrics();
mincMetrics = new TabletServerMinCMetrics();
ceMetrics = new CompactionExecutorsMetrics();
MetricsUtil.initializeProducers(metrics, updateMetrics, scanMetrics, mincMetrics, ceMetrics);
this.compactionManager = new CompactionManager(new Iterable<Compactable>() {
@Override
public Iterator<Compactable> iterator() {
return Iterators.transform(onlineTablets.snapshot().values().iterator(), Tablet::asCompactable);
}
}, getContext(), ceMetrics);
compactionManager.start();
try {
walMarker.initWalMarker(getTabletSession());
} catch (Exception e) {
log.error("Unable to create WAL marker node in zookeeper", e);
throw new RuntimeException(e);
}
ThreadPoolExecutor distWorkQThreadPool = ThreadPools.createExecutorService(getConfiguration(), Property.TSERV_WORKQ_THREADS, true);
bulkFailedCopyQ = new DistributedWorkQueue(getContext().getZooKeeperRoot() + Constants.ZBULK_FAILED_COPYQ, getConfiguration(), getContext());
try {
bulkFailedCopyQ.startProcessing(new BulkFailedCopyProcessor(getContext()), distWorkQThreadPool);
} catch (Exception e1) {
throw new RuntimeException("Failed to start distributed work queue for copying ", e1);
}
try {
logSorter.startWatchingForRecoveryLogs(distWorkQThreadPool);
} catch (Exception ex) {
log.error("Error setting watches for recoveries");
throw new RuntimeException(ex);
}
final AccumuloConfiguration aconf = getConfiguration();
// if the replication name is ever set, then start replication services
@SuppressWarnings("deprecation") Property p = Property.REPLICATION_NAME;
context.getScheduledExecutor().scheduleWithFixedDelay(() -> {
if (this.replServer == null) {
if (!getConfiguration().get(p).isEmpty()) {
log.info(p.getKey() + " was set, starting repl services.");
setupReplication(aconf);
}
}
}, 0, 5, TimeUnit.SECONDS);
// random 30-60 minute delay
int tabletCheckFrequency = 30 + random.nextInt(31);
// Periodically check that metadata of tablets matches what is held in memory
ThreadPools.createGeneralScheduledExecutorService(aconf).scheduleWithFixedDelay(() -> {
final SortedMap<KeyExtent, Tablet> onlineTabletsSnapshot = onlineTablets.snapshot();
Map<KeyExtent, Long> updateCounts = new HashMap<>();
// gather updateCounts for each tablet
onlineTabletsSnapshot.forEach((ke, tablet) -> {
updateCounts.put(ke, tablet.getUpdateCount());
});
// gather metadata for all tablets readTablets()
try (TabletsMetadata tabletsMetadata = getContext().getAmple().readTablets().forTablets(onlineTabletsSnapshot.keySet()).fetch(FILES, LOGS, ECOMP, PREV_ROW).build()) {
// for each tablet, compare its metadata to what is held in memory
tabletsMetadata.forEach(tabletMetadata -> {
KeyExtent extent = tabletMetadata.getExtent();
Tablet tablet = onlineTabletsSnapshot.get(extent);
Long counter = updateCounts.get(extent);
tablet.compareTabletInfo(counter, tabletMetadata);
});
}
}, tabletCheckFrequency, tabletCheckFrequency, TimeUnit.MINUTES);
final long CLEANUP_BULK_LOADED_CACHE_MILLIS = TimeUnit.MINUTES.toMillis(15);
context.getScheduledExecutor().scheduleWithFixedDelay(new BulkImportCacheCleaner(this), CLEANUP_BULK_LOADED_CACHE_MILLIS, CLEANUP_BULK_LOADED_CACHE_MILLIS, TimeUnit.MILLISECONDS);
HostAndPort managerHost;
while (!serverStopRequested) {
// send all of the pending messages
try {
ManagerMessage mm = null;
ManagerClientService.Client iface = null;
try {
// was requested
while (mm == null && !serverStopRequested) {
mm = managerMessages.poll(1, TimeUnit.SECONDS);
}
// have a message to send to the manager, so grab a
// connection
managerHost = getManagerAddress();
iface = managerConnection(managerHost);
TServiceClient client = iface;
// then finally block should place mm back on queue
while (!serverStopRequested && mm != null && client != null && client.getOutputProtocol() != null && client.getOutputProtocol().getTransport() != null && client.getOutputProtocol().getTransport().isOpen()) {
try {
mm.send(getContext().rpcCreds(), getClientAddressString(), iface);
mm = null;
} catch (TException ex) {
log.warn("Error sending message: queuing message again");
managerMessages.putFirst(mm);
mm = null;
throw ex;
}
// if any messages are immediately available grab em and
// send them
mm = managerMessages.poll();
}
} finally {
if (mm != null) {
managerMessages.putFirst(mm);
}
returnManagerConnection(iface);
sleepUninterruptibly(1, TimeUnit.SECONDS);
}
} catch (InterruptedException e) {
log.info("Interrupt Exception received, shutting down");
serverStopRequested = true;
} catch (Exception e) {
// may have lost connection with manager
// loop back to the beginning and wait for a new one
// this way we survive manager failures
log.error(getClientAddressString() + ": TServerInfo: Exception. Manager down?", e);
}
}
// get prematurely finalized
synchronized (this) {
while (!shutdownComplete) {
try {
this.wait(1000);
} catch (InterruptedException e) {
log.error(e.toString());
}
}
}
log.debug("Stopping Replication Server");
if (this.replServer != null) {
this.replServer.stop();
}
log.debug("Stopping Thrift Servers");
if (server != null) {
server.stop();
}
try {
log.debug("Closing filesystems");
getVolumeManager().close();
} catch (IOException e) {
log.warn("Failed to close filesystem : {}", e.getMessage(), e);
}
gcLogger.logGCInfo(getConfiguration());
log.info("TServerInfo: stop requested. exiting ... ");
try {
tabletServerLock.unlock();
} catch (Exception e) {
log.warn("Failed to release tablet server lock", e);
}
}
use of org.apache.accumulo.core.metadata.schema.TabletsMetadata in project accumulo by apache.
the class ExternalCompaction_1_IT method testExternalCompactionDeadTServer.
@Test
public void testExternalCompactionDeadTServer() throws Exception {
// Shut down the normal TServers
getCluster().getProcesses().get(TABLET_SERVER).forEach(p -> {
try {
getCluster().killProcess(TABLET_SERVER, p);
} catch (Exception e) {
fail("Failed to shutdown tablet server");
}
});
// Start our TServer that will not commit the compaction
ProcessInfo tserverProcess = getCluster().exec(ExternalCompactionTServer.class);
final String table3 = this.getUniqueNames(1)[0];
try (final AccumuloClient client = Accumulo.newClient().from(getCluster().getClientProperties()).build()) {
createTable(client, table3, "cs7");
writeData(client, table3);
getCluster().getClusterControl().startCompactors(Compactor.class, 1, QUEUE7);
getCluster().getClusterControl().startCoordinator(CompactionCoordinator.class);
compact(client, table3, 2, QUEUE7, false);
// ExternalCompactionTServer will not commit the compaction. Wait for the
// metadata table entries to show up.
LOG.info("Waiting for external compaction to complete.");
TableId tid = getCluster().getServerContext().getTableId(table3);
Stream<ExternalCompactionFinalState> fs = getFinalStatesForTable(getCluster(), tid);
while (fs.count() == 0) {
LOG.info("Waiting for compaction completed marker to appear");
UtilWaitThread.sleep(250);
fs = getFinalStatesForTable(getCluster(), tid);
}
LOG.info("Validating metadata table contents.");
TabletsMetadata tm = getCluster().getServerContext().getAmple().readTablets().forTable(tid).fetch(ColumnType.ECOMP).build();
List<TabletMetadata> md = new ArrayList<>();
tm.forEach(t -> md.add(t));
assertEquals(1, md.size());
TabletMetadata m = md.get(0);
Map<ExternalCompactionId, ExternalCompactionMetadata> em = m.getExternalCompactions();
assertEquals(1, em.size());
List<ExternalCompactionFinalState> finished = new ArrayList<>();
getFinalStatesForTable(getCluster(), tid).forEach(f -> finished.add(f));
assertEquals(1, finished.size());
assertEquals(em.entrySet().iterator().next().getKey(), finished.get(0).getExternalCompactionId());
tm.close();
// Force a flush on the metadata table before killing our tserver
client.tableOperations().flush("accumulo.metadata");
// Stop our TabletServer. Need to perform a normal shutdown so that the WAL is closed
// normally.
LOG.info("Stopping our tablet server");
getCluster().stopProcessWithTimeout(tserverProcess.getProcess(), 30, TimeUnit.SECONDS);
getCluster().getClusterControl().stop(ServerType.TABLET_SERVER);
// Start a TabletServer to commit the compaction.
LOG.info("Starting normal tablet server");
getCluster().getClusterControl().start(ServerType.TABLET_SERVER);
// Wait for the compaction to be committed.
LOG.info("Waiting for compaction completed marker to disappear");
Stream<ExternalCompactionFinalState> fs2 = getFinalStatesForTable(getCluster(), tid);
while (fs2.count() != 0) {
LOG.info("Waiting for compaction completed marker to disappear");
UtilWaitThread.sleep(500);
fs2 = getFinalStatesForTable(getCluster(), tid);
}
verify(client, table3, 2);
// We need to cancel the compaction or delete the table here because we initiate a user
// compaction above in the test. Even though the external compaction was cancelled
// because we split the table, FaTE will continue to queue up a compaction
client.tableOperations().cancelCompaction(table3);
}
}
use of org.apache.accumulo.core.metadata.schema.TabletsMetadata in project accumulo by apache.
the class ExternalCompactionMetricsIT method testMetrics.
@Test
public void testMetrics() throws Exception {
Collection<ProcessReference> tservers = ((MiniAccumuloClusterImpl) getCluster()).getProcesses().get(ServerType.TABLET_SERVER);
assertEquals(2, tservers.size());
// kill one tserver so that queue metrics are not spread across tservers
((MiniAccumuloClusterImpl) getCluster()).killProcess(TABLET_SERVER, tservers.iterator().next());
String[] names = getUniqueNames(2);
try (final AccumuloClient client = Accumulo.newClient().from(getCluster().getClientProperties()).build()) {
String table1 = names[0];
createTable(client, table1, "cs1", 5);
String table2 = names[1];
createTable(client, table2, "cs2", 10);
writeData(client, table1);
writeData(client, table2);
final LinkedBlockingQueue<Metric> queueMetrics = new LinkedBlockingQueue<>();
final AtomicBoolean shutdownTailer = new AtomicBoolean(false);
Thread thread = Threads.createThread("metric-tailer", () -> {
while (!shutdownTailer.get()) {
List<String> statsDMetrics = sink.getLines();
for (String s : statsDMetrics) {
if (shutdownTailer.get()) {
break;
}
if (s.startsWith(MetricsProducer.METRICS_MAJC_QUEUED)) {
queueMetrics.add(TestStatsDSink.parseStatsDMetric(s));
}
}
}
});
thread.start();
compact(client, table1, 7, "DCQ1", false);
compact(client, table2, 13, "DCQ2", false);
boolean sawDCQ1_5 = false;
boolean sawDCQ2_10 = false;
// wait until expected number of queued are seen in metrics
while (!sawDCQ1_5 || !sawDCQ2_10) {
Metric qm = queueMetrics.take();
sawDCQ1_5 |= match(qm, "DCQ1", "5");
sawDCQ2_10 |= match(qm, "DCQ2", "10");
}
cluster.getClusterControl().startCompactors(Compactor.class, 1, QUEUE1);
cluster.getClusterControl().startCompactors(Compactor.class, 1, QUEUE2);
cluster.getClusterControl().startCoordinator(CompactionCoordinator.class);
boolean sawDCQ1_0 = false;
boolean sawDCQ2_0 = false;
// wait until queued goes to zero in metrics
while (!sawDCQ1_0 || !sawDCQ2_0) {
Metric qm = queueMetrics.take();
sawDCQ1_0 |= match(qm, "DCQ1", "0");
sawDCQ2_0 |= match(qm, "DCQ2", "0");
}
shutdownTailer.set(true);
thread.join();
// Wait for all external compactions to complete
long count;
do {
UtilWaitThread.sleep(100);
try (TabletsMetadata tm = getCluster().getServerContext().getAmple().readTablets().forLevel(DataLevel.USER).fetch(ColumnType.ECOMP).build()) {
count = tm.stream().flatMap(t -> t.getExternalCompactions().keySet().stream()).count();
}
} while (count > 0);
verify(client, table1, 7);
verify(client, table2, 13);
} finally {
// We stopped the TServer and started our own, restart the original TabletServers
// Uncomment this if other tests are added.
//
// cluster.getClusterControl().start(ServerType.TABLET_SERVER);
}
}
Aggregations