package com.linkedin.databus2.core.container.monitoring.mbean;
/*
*
* Copyright 2013 LinkedIn Corp. All rights reserved
*
* 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.
*
*/
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.concurrent.locks.Lock;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import org.apache.avro.io.JsonEncoder;
import org.apache.avro.specific.SpecificDatumWriter;
import org.apache.log4j.Logger;
import com.linkedin.databus.core.Checkpoint;
import com.linkedin.databus.core.monitoring.mbean.AbstractMonitoringMBean;
import com.linkedin.databus.core.monitoring.mbean.DatabusMonitoringMBean;
import com.linkedin.databus2.core.container.monitoring.events.DbusHttpTotalStatsEvent;
public class DbusHttpTotalStats extends AbstractMonitoringMBean<DbusHttpTotalStatsEvent>
implements DbusHttpTotalStatsMBean
{
public static final String MODULE = DbusHttpTotalStats.class.getName();
public static final Logger LOG = Logger.getLogger(MODULE);
private final HashSet<Object> _peers;
private final String _dimension;
public DbusHttpTotalStats(int ownerId, String dimesion, boolean enabled, boolean threadSafe,
DbusHttpTotalStatsEvent initData)
{
super(enabled, threadSafe, initData);
_event.ownerId = ownerId;
_event.dimension = dimesion;
_peers = new HashSet<Object>(1000);
_dimension = dimesion;
reset();
}
public DbusHttpTotalStats clone(boolean threadSafe)
{
return new DbusHttpTotalStats(_event.ownerId, _dimension, _enabled.get(), threadSafe,
getStatistics(null));
}
@Override
public int getNumPeers()
{
Lock readLock = acquireReadLock();
int result = 0;
try
{
result = _event.numPeers;
}
finally
{
releaseLock(readLock);
}
return result;
}
@Override
public int getNumRegisterCalls()
{
Lock readLock = acquireReadLock();
int result = 0;
try
{
result = _event.numRegisterCalls;
}
finally
{
releaseLock(readLock);
}
return result;
}
@Override
public int getNumSourcesCalls()
{
Lock readLock = acquireReadLock();
int result = 0;
try
{
result = _event.numSourcesCalls;
}
finally
{
releaseLock(readLock);
}
return result;
}
@Override
public long getNumStreamCalls()
{
Lock readLock = acquireReadLock();
long result = 0;
try
{
result = _event.numStreamCalls;
}
finally
{
releaseLock(readLock);
}
return result;
}
@Override
public long getTimeSinceLastResetMs()
{
Lock readLock = acquireReadLock();
long result = 0;
try
{
result = System.currentTimeMillis() - _event.timestampLastResetMs;
}
finally
{
releaseLock(readLock);
}
return result;
}
@Override
public long getTimestampLastResetMs()
{
Lock readLock = acquireReadLock();
long result = 0;
try
{
result = _event.timestampLastResetMs;
}
finally
{
releaseLock(readLock);
}
return result;
}
@Override
public long getMaxStreamWinScn()
{
Lock readLock = acquireReadLock();
try
{
return _event.maxStreamWinScn;
}
finally
{
releaseLock(readLock);
}
}
@Override
public long getMinStreamWinScn()
{
Lock readLock = acquireReadLock();
try
{
return _event.minStreamWinScn;
}
finally
{
releaseLock(readLock);
}
}
@Override
public double getLatencyStreamCalls()
{
Lock readLock = acquireReadLock();
try
{
long numCalls = _event.numStreamCalls;
return (0 == numCalls) ? 0.0 : 1.0 * _event.timeStreamCallsMs / numCalls;
}
finally
{
releaseLock(readLock);
}
}
/** Not thread-safe! Make sure you are holding a write lock*/
private void registerPeer(String peer)
{
_peers.add(peer);
_event.numPeers = _peers.size();
}
public void registerRegisterCall(String peer)
{
if (! _enabled.get()) return;
Lock writeLock = acquireWriteLock();
try
{
_event.numRegisterCalls++;
registerPeer(peer);
}
finally
{
releaseLock(writeLock);
}
}
public void registerSourcesCall(String peer)
{
if (! _enabled.get()) return;
Lock writeLock = acquireWriteLock();
try
{
_event.numSourcesCalls++;
registerPeer(peer);
}
finally
{
releaseLock(writeLock);
}
}
public void registerStreamResponse(long totalTime)
{
if (! _enabled.get()) return;
Lock writeLock = acquireWriteLock();
try
{
_event.numStreamCalls++;
_event.timeStreamCallsMs += totalTime;
}
finally
{
releaseLock(writeLock);
}
}
public void registerStreamRequest(String peer, Checkpoint cp)
{
long winScn = cp.getWindowScn();
Lock writeLock = acquireWriteLock();
try
{
_event.maxStreamWinScn = maxValue(_event.maxStreamWinScn, winScn);
_event.minStreamWinScn = minValue(_event.minStreamWinScn, winScn);
registerPeer(peer);
}
finally
{
releaseLock(writeLock);
}
}
@Override
protected void resetData()
{
_event.timestampLastResetMs = System.currentTimeMillis();
_event.timeSinceLastResetMs = 0;
_event.numPeers = 0;
_event.numRegisterCalls = 0;
_event.numSourcesCalls = 0;
_event.numStreamCalls = 0;
_event.timeStreamCallsMs = 0;
_event.maxStreamWinScn = DEFAULT_MAX_LONG_VALUE;
_event.minStreamWinScn = DEFAULT_MIN_LONG_VALUE;
_event.numErrInvalidParamsRegisterCalls = 0;
_event.numErrRegisterCalls = 0;
_event.numErrInvalidParamsStreamCalls = 0;
_event.numErrScnNotFoundStreamCalls = 0;
_event.numErrSourcesCalls = 0;
_event.numErrStreamCalls = 0;
_event.numErrInvalidParamsRegisterCalls = 0;
_event.numErrInvalidParamsSourcesCalls = 0;
_event.mastershipStatus = 0;
_peers.clear();
}
@Override
public JsonEncoder createJsonEncoder(OutputStream out) throws IOException
{
return new JsonEncoder(_event.getSchema(), out);
}
@Override
protected void cloneData(DbusHttpTotalStatsEvent event)
{
event.ownerId = _event.ownerId;
event.dimension = _event.dimension;
event.timestampLastResetMs = _event.timestampLastResetMs;
event.timeSinceLastResetMs = System.currentTimeMillis() - _event.timestampLastResetMs;
event.numPeers = _event.numPeers;
event.numRegisterCalls = _event.numRegisterCalls;
event.numSourcesCalls = _event.numSourcesCalls;
event.numStreamCalls = _event.numStreamCalls;
event.timeStreamCallsMs = _event.timeStreamCallsMs;
event.maxStreamWinScn = _event.maxStreamWinScn;
event.minStreamWinScn = _event.minStreamWinScn;
event.numErrInvalidParamsRegisterCalls = _event.numErrInvalidParamsRegisterCalls;
event.numErrRegisterCalls = _event.numErrRegisterCalls;
event.numErrInvalidParamsStreamCalls = _event.numErrInvalidParamsStreamCalls;
event.numErrScnNotFoundStreamCalls = _event.numErrScnNotFoundStreamCalls;
event.numErrSourcesCalls = _event.numErrSourcesCalls;
event.numErrStreamCalls = _event.numErrStreamCalls;
event.numErrInvalidParamsRegisterCalls = _event.numErrInvalidParamsRegisterCalls;
event.numErrInvalidParamsSourcesCalls = _event.numErrInvalidParamsSourcesCalls;
event.mastershipStatus = _event.mastershipStatus;
}
@Override
protected DbusHttpTotalStatsEvent newDataEvent()
{
return new DbusHttpTotalStatsEvent();
}
@Override
protected SpecificDatumWriter<DbusHttpTotalStatsEvent> getAvroWriter()
{
return new SpecificDatumWriter<DbusHttpTotalStatsEvent>(DbusHttpTotalStatsEvent.class);
}
@Override
public void mergeStats(DatabusMonitoringMBean<DbusHttpTotalStatsEvent> other)
{
super.mergeStats(other);
if (other instanceof DbusHttpTotalStats)
{
mergeClients((DbusHttpTotalStats)other);
}
}
@Override
protected void doMergeStats(Object eventData)
{
if (! (eventData instanceof DbusHttpTotalStatsEvent))
{
LOG.warn("Attempt to merge unknown event class" + eventData.getClass().getName());
return;
}
DbusHttpTotalStatsEvent e = (DbusHttpTotalStatsEvent)eventData;
/** Allow use negative relay IDs for aggregation across multiple relays */
if (_event.ownerId > 0 && e.ownerId != _event.ownerId)
{
LOG.warn("Attempt to data for a different relay " + e.ownerId);
return;
}
_event.numPeers += e.numPeers;
_event.numRegisterCalls += e.numRegisterCalls;
_event.numSourcesCalls += e.numSourcesCalls;
_event.numStreamCalls += e.numStreamCalls;
_event.timeStreamCallsMs += e.timeStreamCallsMs;
_event.maxStreamWinScn = maxValue(_event.maxStreamWinScn, e.maxStreamWinScn);
_event.minStreamWinScn = minValue(_event.minStreamWinScn, e.minStreamWinScn);
_event.numErrInvalidParamsRegisterCalls += e.numErrInvalidParamsRegisterCalls;
_event.numErrRegisterCalls += e.numErrRegisterCalls;
_event.numErrInvalidParamsStreamCalls += e.numErrInvalidParamsStreamCalls;
_event.numErrScnNotFoundStreamCalls += e.numErrScnNotFoundStreamCalls;
_event.numErrSourcesCalls += e.numErrSourcesCalls;
_event.numErrStreamCalls += e.numErrStreamCalls;
_event.numErrInvalidParamsRegisterCalls += e.numErrInvalidParamsRegisterCalls;
_event.numErrInvalidParamsSourcesCalls += e.numErrInvalidParamsSourcesCalls;
_event.mastershipStatus = Math.max(e.mastershipStatus,_event.mastershipStatus);
// numClients cannot be merged
}
/** A bit of a hack to merge state outside the event state */
private void mergeClients(DbusHttpTotalStats other)
{
Lock otherReadLock = other.acquireReadLock();
Lock writeLock = acquireWriteLock(otherReadLock);
try
{
_peers.addAll(other._peers);
_event.numPeers = _peers.size();
}
finally
{
releaseLock(writeLock);
releaseLock(otherReadLock);
}
}
@Override
public ObjectName generateObjectName() throws MalformedObjectNameException
{
Hashtable<String, String> mbeanProps = generateBaseMBeanProps();
mbeanProps.put("ownerId", Integer.toString(_event.ownerId));
mbeanProps.put("dimension", _dimension);
return new ObjectName(AbstractMonitoringMBean.JMX_DOMAIN, mbeanProps);
}
@Override
public String getDimension()
{
return _dimension;
}
public void registerInvalidStreamRequest(String peer)
{
Lock writeLock = acquireWriteLock();
try
{
registerPeer(peer);
_event.numErrStreamCalls++;
_event.numErrInvalidParamsStreamCalls++;
}
finally
{
releaseLock(writeLock);
}
}
public void registerScnNotFoundStreamResponse(String peer)
{
Lock writeLock = acquireWriteLock();
try
{
registerPeer(peer);
_event.numErrStreamCalls++;
_event.numErrScnNotFoundStreamCalls++;
}
finally
{
releaseLock(writeLock);
}
}
public void registerInvalidSourceRequest(String peer)
{
Lock writeLock = acquireWriteLock();
try
{
registerPeer(peer);
_event.numErrInvalidParamsSourcesCalls++;
_event.numErrSourcesCalls++;
}
finally
{
releaseLock(writeLock);
}
}
public void registerInvalidRegisterCall(String peer)
{
Lock writeLock = acquireWriteLock();
try
{
registerPeer(peer);
_event.numErrStreamCalls++;
_event.numErrInvalidParamsRegisterCalls++;
}
finally
{
releaseLock(writeLock);
}
}
@Override
public long getNumScnNotFoundStream()
{
Lock readLock = acquireReadLock();
long result = 0;
try
{
result = _event.numErrScnNotFoundStreamCalls;
}
finally
{
releaseLock(readLock);
}
return result;
}
@Override
public long getNumErrStream()
{
Lock readLock = acquireReadLock();
long result = 0;
try
{
result = _event.numErrStreamCalls;
}
finally
{
releaseLock(readLock);
}
return result;
}
@Override
public long getNumErrStreamReq()
{
Lock readLock = acquireReadLock();
long result = 0;
try
{
result = _event.numErrInvalidParamsStreamCalls;
}
finally
{
releaseLock(readLock);
}
return result;
}
@Override
public long getNumErrRegister()
{
Lock readLock = acquireReadLock();
long result = 0;
try
{
result = _event.numErrRegisterCalls;
}
finally
{
releaseLock(readLock);
}
return result;
}
@Override
public long getNumErrRegisterReq()
{
Lock readLock = acquireReadLock();
long result = 0;
try
{
result = _event.numErrInvalidParamsRegisterCalls;
}
finally
{
releaseLock(readLock);
}
return result;
}
@Override
public long getNumErrSources()
{
Lock readLock = acquireReadLock();
long result = 0;
try
{
result = _event.numErrSourcesCalls;
}
finally
{
releaseLock(readLock);
}
return result;
}
@Override
public long getNumErrSourcesReq()
{
Lock readLock = acquireReadLock();
long result = 0;
try
{
result = _event.numErrInvalidParamsSourcesCalls;
}
finally
{
releaseLock(readLock);
}
return result;
}
@Override
public int getMastershipStatus()
{
Lock readLock = acquireReadLock();
int result = 0;
try
{
result = _event.mastershipStatus;
}
finally
{
releaseLock(readLock);
}
return result;
}
public void registerMastershipStatus(int i)
{
Lock writeLock = acquireWriteLock();
try
{
_event.mastershipStatus = i;
}
finally
{
releaseLock(writeLock);
}
}
@Override
public double getHttpErrorRate()
{
Lock readLock = acquireReadLock();
try
{
long totalCalls = _event.numStreamCalls + _event.numRegisterCalls + _event.numSourcesCalls;
long totalErrors = _event.numErrStreamCalls + _event.numErrSourcesCalls +
_event.numErrRegisterCalls;
return 0 == totalCalls ? 0.0 : 1.0 * totalErrors / totalCalls;
}
finally
{
releaseLock(readLock);
}
}
}