/**
* Copyright (C) 2013 Arman Gal
*
* Licensed 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.clevermore.monitor.server.tasks;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import org.clevermore.SmartExecutor;
import org.clevermore.monitor.server.constants.SmartPoolsMonitoring;
import org.clevermore.monitor.server.model.DatabaseServer;
import org.clevermore.monitor.server.model.IConnectedServersState;
import org.clevermore.monitor.server.model.ServerStatus;
import org.clevermore.monitor.shared.runtime.MemoryUsage;
import org.clevermore.monitor.shared.runtime.MemoryUsageLight;
import org.clevermore.monitor.shared.servers.ConnectedServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.inject.Inject;
public abstract class AbstractStateUpdaterThread<SS extends ServerStatus, R extends AbstractRefresher<SS>, DS extends DatabaseServer>
implements IStateUpdaterThread {
private static Logger logger = LoggerFactory.getLogger("StateUpdaterThread");
private AtomicInteger executionNumber = new AtomicInteger(0);
@Inject
private SmartExecutor smartExecutor;
@Inject
private IConnectedServersState<SS, DS> connectedServersState;
@Override
public void run() {
try {
// During threads scheduling, do not allow updates to servers
ConnectionSynch.connectionLock.lock();
long start = System.currentTimeMillis();
logger.info("Refreshing stats for all servers.");
ArrayList<ConnectedServer> serversList = new ArrayList<ConnectedServer>(0);
CompletionService<SS> compService = smartExecutor.getCompletionService(SmartPoolsMonitoring.REFERSHER);
Collection<SS> values = connectedServersState.getAllServers();
// scheduling update threads
Map<Future<SS>, R> futuresMap = new HashMap<Future<SS>, R>();
for (SS ss : values) {
R refresher = getRefresher(ss, new Date(), executionNumber.getAndIncrement());
Future<SS> future = compService.submit(refresher);
futuresMap.put(future, refresher);
}
// Waiting for all threads to finish
int i = 0;
do {
Future<SS> take = compService.poll(15, TimeUnit.SECONDS);
i++;
if (take != null) {
futuresMap.remove(take);
try {
SS ss = take.get(10, TimeUnit.SECONDS);
logger.info("Finished updating:{}, {} from {}", new Object[] {ss.getServerConfig().getName(), i, values.size()});
ConnectedServer cs = getConnectedServer(ss);
serversList.add(cs);
} catch (Exception e) {
take.cancel(true);
logger.error(e.getMessage(), e);
}
} else {
logger.warn("take was null!!!!");
}
} while (i < values.size());
if (futuresMap.size() > 0) {
// not good, for some server we couldn't collect stats
logger.error("Can't collect stats from all servers, skipped servers are below.");
for (Future<SS> f : futuresMap.keySet()) {
R r = futuresMap.get(f);
SS serverStataus = r.getServerStataus();
logger.error("Skipped:{}", serverStataus);
f.cancel(true);
ConnectedServer cs = getConnectedServer(serverStataus);
serversList.add(cs);
}
}
// finished querying all connected servers, now merging the results.
logger.info("Staring merge stats");
connectedServersState.mergeStats(serversList);
logger.info("Finished merge stats");
refreshDBs();
finishedRefresh();
logger.info("Refreshing finished for all servers, took:{}.", (System.currentTimeMillis() - start));
} catch (Throwable e) {
logger.error(e.getMessage(), e);
} finally {
ConnectionSynch.connectionLock.unlock();
}
}
private void refreshDBs() {
CompletionService<DS> compService = new ExecutorCompletionService<DS>(smartExecutor.getThreadPool(SmartPoolsMonitoring.REFERSHER));
int ref = 0;
for (DS ds : connectedServersState.getDatabases()) {
if (ds.isConnected()) {
compService.submit(getDbRefresher(ds));
ref++;
}
}
for (int i = 0; i < ref; i++) {
try {
Future<DS> take = compService.take();
DS ds = take.get();
logger.info("Finished refersh database:" + ds.getDatabaseConfig().getName());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
public abstract Callable<DS> getDbRefresher(DS ds);
public void finishedRefresh() {
// Nothing for now
}
public abstract R getRefresher(SS ss, Date executionDate, int excutionNumber);
/**
* prepares ConnectedServer with relevant to client/UI information
*
* @param ss
* @return
*/
public abstract ConnectedServer getConnectedServer(SS ss);
/**
* gets the light object from client representation
*
* @param ss
* @return
*/
public MemoryUsageLight getMemoryLight(ServerStatus ss) {
if (!ss.isConnected()) {
return new MemoryUsageLight();
}
MemoryUsage mu = ss.getLastMemoryUsage();
MemoryUsageLight mul = new MemoryUsageLight(mu.getInit(), mu.getUsed(), mu.getCommitted(), mu.getMax());
return mul;
}
public IConnectedServersState<SS, DS> getConnectedServersState() {
return connectedServersState;
}
public static class Test {
@org.junit.Test
public void test() {
System.out.println("start");
CompletionService<Boolean> compService = new ExecutorCompletionService<Boolean>(Executors.newCachedThreadPool());
for (int i = 0; i < 10; i++) {
compService.submit(new Callable<Boolean>() {
@Override
public Boolean call()
throws Exception {
Thread.sleep(10000);
return true;
}
});
}
for (int i = 0; i < 10; i++) {
try {
Future<Boolean> take = compService.take();
System.out.println(take.get(10, TimeUnit.MILLISECONDS));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}