use of org.apache.accumulo.core.spi.balancer.data.TabletServerId in project accumulo by apache.
the class GroupBalancer method populateMigrations.
private void populateMigrations(Set<TabletServerId> current, List<TabletMigration> migrationsOut, Moves moves) {
if (moves.size() == 0) {
return;
}
Function<TabletId, String> partitioner = getPartitioner();
for (var tablet : getLocationProvider().entrySet()) {
String group = partitioner.apply(tablet.getKey());
var loc = tablet.getValue();
if (loc == null || !current.contains(loc)) {
migrationsOut.clear();
return;
}
TabletServerId dest = moves.removeMove(loc, group);
if (dest != null) {
migrationsOut.add(new TabletMigration(tablet.getKey(), loc, dest));
if (moves.size() == 0) {
break;
}
}
}
}
use of org.apache.accumulo.core.spi.balancer.data.TabletServerId in project accumulo by apache.
the class GroupBalancer method balance.
@Override
public long balance(BalanceParameters params) {
if (!shouldBalance(params.currentStatus(), params.currentMigrations())) {
return 5000;
}
if (System.currentTimeMillis() - lastRun < getWaitTime()) {
return 5000;
}
MapCounter<String> groupCounts = new MapCounter<>();
Map<TabletServerId, TserverGroupInfo> tservers = new HashMap<>();
for (TabletServerId tsi : params.currentStatus().keySet()) {
tservers.put(tsi, new TserverGroupInfo(tsi));
}
Function<TabletId, String> partitioner = getPartitioner();
// collect stats about current state
for (var tablet : getLocationProvider().entrySet()) {
String group = partitioner.apply(tablet.getKey());
var loc = tablet.getValue();
if (loc == null || !tservers.containsKey(loc)) {
return 5000;
}
groupCounts.increment(group, 1);
TserverGroupInfo tgi = tservers.get(loc);
tgi.addGroup(group);
}
Map<String, Integer> expectedCounts = new HashMap<>();
int totalExtra = 0;
for (String group : groupCounts.keySet()) {
int groupCount = groupCounts.getInt(group);
totalExtra += groupCount % params.currentStatus().size();
expectedCounts.put(group, (groupCount / params.currentStatus().size()));
}
// The number of extra tablets from all groups that each tserver must have.
int expectedExtra = totalExtra / params.currentStatus().size();
int maxExtraGroups = expectedExtra + 1;
expectedCounts = Collections.unmodifiableMap(expectedCounts);
tservers = Collections.unmodifiableMap(tservers);
for (TserverGroupInfo tgi : tservers.values()) {
tgi.finishedAdding(expectedCounts);
}
Moves moves = new Moves();
// The order of the following steps is important, because as ordered each step should not move
// any tablets moved by a previous step.
balanceExpected(tservers, moves);
if (moves.size() < getMaxMigrations()) {
balanceExtraExpected(tservers, expectedExtra, moves);
if (moves.size() < getMaxMigrations()) {
boolean cont = balanceExtraMultiple(tservers, maxExtraGroups, moves);
if (cont && moves.size() < getMaxMigrations()) {
balanceExtraExtra(tservers, maxExtraGroups, moves);
}
}
}
populateMigrations(tservers.keySet(), params.migrationsOut(), moves);
lastRun = System.currentTimeMillis();
return 5000;
}
use of org.apache.accumulo.core.spi.balancer.data.TabletServerId in project accumulo by apache.
the class TableLoadBalancer method getAssignments.
@Override
public void getAssignments(AssignmentParameters params) {
// separate the unassigned into tables
Map<TableId, Map<TabletId, TabletServerId>> groupedUnassigned = new HashMap<>();
params.unassignedTablets().forEach((tid, lastTserver) -> groupedUnassigned.computeIfAbsent(tid.getTable(), k -> new HashMap<>()).put(tid, lastTserver));
for (Entry<TableId, Map<TabletId, TabletServerId>> e : groupedUnassigned.entrySet()) {
Map<TabletId, TabletServerId> newAssignments = new HashMap<>();
getBalancerForTable(e.getKey()).getAssignments(new AssignmentParamsImpl(params.currentStatus(), e.getValue(), newAssignments));
newAssignments.forEach(params::addAssignment);
}
}
use of org.apache.accumulo.core.spi.balancer.data.TabletServerId in project accumulo by apache.
the class Manager method gatherTableInformation.
private SortedMap<TServerInstance, TabletServerStatus> gatherTableInformation(Set<TServerInstance> currentServers, SortedMap<TabletServerId, TServerStatus> balancerMap) {
final long rpcTimeout = getConfiguration().getTimeInMillis(Property.GENERAL_RPC_TIMEOUT);
int threads = getConfiguration().getCount(Property.MANAGER_STATUS_THREAD_POOL_SIZE);
ExecutorService tp = ThreadPools.createExecutorService(getConfiguration(), Property.MANAGER_STATUS_THREAD_POOL_SIZE, false);
long start = System.currentTimeMillis();
final SortedMap<TServerInstance, TabletServerStatus> result = new ConcurrentSkipListMap<>();
final RateLimiter shutdownServerRateLimiter = RateLimiter.create(MAX_SHUTDOWNS_PER_SEC);
for (TServerInstance serverInstance : currentServers) {
final TServerInstance server = serverInstance;
if (threads == 0) {
// Since an unbounded thread pool is being used, rate limit how fast task are added to the
// executor. This prevents the threads from growing large unless there are lots of
// unresponsive tservers.
sleepUninterruptibly(Math.max(1, rpcTimeout / 120_000), TimeUnit.MILLISECONDS);
}
tp.submit(() -> {
try {
Thread t = Thread.currentThread();
String oldName = t.getName();
try {
String message = "Getting status from " + server;
t.setName(message);
long startForServer = System.currentTimeMillis();
log.trace(message);
TServerConnection connection1 = tserverSet.getConnection(server);
if (connection1 == null) {
throw new IOException("No connection to " + server);
}
TabletServerStatus status = connection1.getTableMap(false);
result.put(server, status);
long duration = System.currentTimeMillis() - startForServer;
log.trace("Got status from {} in {} ms", server, duration);
} finally {
t.setName(oldName);
}
} catch (Exception ex) {
log.error("unable to get tablet server status {} {}", server, ex.toString());
log.debug("unable to get tablet server status {}", server, ex);
// MAX_BAD_STATUS_COUNT times
if (badServers.computeIfAbsent(server, k -> new AtomicInteger(0)).incrementAndGet() > MAX_BAD_STATUS_COUNT) {
if (shutdownServerRateLimiter.tryAcquire()) {
log.warn("attempting to stop {}", server);
try {
TServerConnection connection2 = tserverSet.getConnection(server);
if (connection2 != null) {
connection2.halt(managerLock);
}
} catch (TTransportException e1) {
// ignore: it's probably down
} catch (Exception e2) {
log.info("error talking to troublesome tablet server", e2);
}
} else {
log.warn("Unable to shutdown {} as over the shutdown limit of {} per minute", server, MAX_SHUTDOWNS_PER_SEC * 60);
}
badServers.remove(server);
}
}
});
}
tp.shutdown();
try {
tp.awaitTermination(Math.max(10000, rpcTimeout / 3), TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
log.debug("Interrupted while fetching status");
}
tp.shutdownNow();
// Threads may still modify map after shutdownNow is called, so create an immutable snapshot.
SortedMap<TServerInstance, TabletServerStatus> info = ImmutableSortedMap.copyOf(result);
tserverStatus.forEach((tsi, status) -> balancerMap.put(new TabletServerIdImpl(tsi), TServerStatusImpl.fromThrift(status)));
synchronized (badServers) {
badServers.keySet().retainAll(currentServers);
badServers.keySet().removeAll(info.keySet());
}
log.debug(String.format("Finished gathering information from %d of %d servers in %.2f seconds", info.size(), currentServers.size(), (System.currentTimeMillis() - start) / 1000.));
return info;
}
use of org.apache.accumulo.core.spi.balancer.data.TabletServerId in project accumulo by apache.
the class BaseHostRegexTableLoadBalancerTest method createCurrent.
protected SortedMap<TabletServerId, TServerStatus> createCurrent(int numTservers) {
String base = "192.168.0.";
TreeMap<TabletServerId, TServerStatus> current = new TreeMap<>();
for (int i = 1; i <= numTservers; i++) {
TServerStatusImpl status = new TServerStatusImpl(new org.apache.accumulo.core.master.thrift.TabletServerStatus());
Map<String, TableStatistics> tableMap = new HashMap<>();
tableMap.put(FOO.getId().canonical(), new TableStatisticsImpl(new TableInfo()));
tableMap.put(BAR.getId().canonical(), new TableStatisticsImpl(new TableInfo()));
tableMap.put(BAZ.getId().canonical(), new TableStatisticsImpl(new TableInfo()));
status.setTableMap(tableMap);
current.put(new TabletServerIdImpl(base + i, 9997, Integer.toHexString(1)), status);
}
// now put all of the tablets on one server
for (Map.Entry<String, TabletServerId> entry : initialTableLocation.entrySet()) {
TServerStatus status = current.get(entry.getValue());
if (status != null) {
TableId tableId = environment.getTableIdMap().get(entry.getKey());
((TableStatisticsImpl) status.getTableMap().get(tableId.canonical())).setOnlineTabletCount(5);
}
}
return current;
}
Aggregations