package com.tesora.dve.server.connectionmanager;
/*
* #%L
* Tesora Inc.
* Database Virtualization Engine
* %%
* Copyright (C) 2011 - 2014 Tesora Inc.
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import com.tesora.dve.server.connectionmanager.log.ShutdownLog;
import org.apache.log4j.Logger;
import com.tesora.dve.common.RemoteException;
import com.tesora.dve.server.connectionmanager.UserNotification.NotificationType;
import com.tesora.dve.common.catalog.CatalogDAO;
import com.tesora.dve.common.catalog.StorageSite;
import com.tesora.dve.common.catalog.CatalogDAO.CatalogDAOFactory;
import com.tesora.dve.comms.client.messages.GenericResponse;
import com.tesora.dve.comms.client.messages.ResponseMessage;
import com.tesora.dve.exceptions.PEException;
import com.tesora.dve.worker.agent.Envelope;
import com.tesora.dve.server.statistics.RollingStatisticsAccumulator;
import com.tesora.dve.sql.schema.PEStorageSite.TCacheSite;
import com.tesora.dve.worker.agent.Agent;
public class NotificationManager extends Agent {
private static final int PER_MINUTE_THRESHOLD = 10;
public static int PER_SECOND_THRESHOLD = 1;
private Logger logger = Logger.getLogger(NotificationManager.class);
Map<StorageSite, RollingStatisticsAccumulator> failureStatMap1sec = new HashMap<StorageSite, RollingStatisticsAccumulator>();
Map<StorageSite, RollingStatisticsAccumulator> failureStatMap1min = new HashMap<StorageSite, RollingStatisticsAccumulator>();
public NotificationManager() throws PEException {
super(NotificationManager.class.getSimpleName());
}
@Override
public void onMessage(Envelope e) throws PEException {
Object payload = e.getPayload();
if (payload instanceof NotificationManagerRequest) {
NotificationManagerRequest m = (NotificationManagerRequest)payload;
ResponseMessage resp;
try {
resp = m.executeRequest(e, this);
} catch (Exception ex) {
resp = new GenericResponse().setException(new RemoteException(getName(), ex));
}
if (resp != null)
returnResponse(e, resp);
} else {
throw new PEException("WorkerManager received message of invalid type (" + payload.toString() + ")");
}
}
public synchronized void onSiteFailure(StorageSite site) throws PEException {
notify(new UserNotification(NotificationType.SiteFailure,
"Communications failure on site " + site + " (url: " + site.getMasterUrl() + ")"));
if (false == failureStatMap1sec.containsKey(site)) {
failureStatMap1sec.put(site, new RollingStatisticsAccumulator(10, 100));
failureStatMap1min.put(site, new RollingStatisticsAccumulator(10, 6000));
}
failureStatMap1sec.get(site).addDatum(1);
failureStatMap1min.get(site).addDatum(1);
if (failureStatMap1sec.get(site).getTransactionsPerSecond() >= PER_SECOND_THRESHOLD || failureStatMap1min.get(site).getTransactionsPerSecond() >= PER_MINUTE_THRESHOLD) {
CatalogDAO c = CatalogDAOFactory.newInstance();
try {
StorageSite realSite = site instanceof TCacheSite ? site.getRecoverableSite(c) : site;
if (realSite.getMasterUrl().equals(site.getMasterUrl()))
site.onSiteFailure(c);
} finally {
c.close();
}
}
}
private void notify(UserNotification userNotification) {
logger.warn(userNotification.getNotificationMessage());
}
@Override
public synchronized void onTimeout() {
for (Iterator<Entry<StorageSite, RollingStatisticsAccumulator>> i = failureStatMap1min.entrySet().iterator(); i.hasNext();) {
Entry<StorageSite, RollingStatisticsAccumulator> entry = i.next();
if (failureStatMap1min.get(entry.getKey()).getTransactionsPerSecond() == 0) {
i.remove();
failureStatMap1sec.remove(entry.getKey());
}
}
}
public void shutdown() {
try {
super.close();
} catch (PEException e) {
ShutdownLog.logShutdownError("Error shutting down " + getClass().getSimpleName(), e);
}
}
}