com.bigdata.io.writecache.WriteCacheServiceCounters Maven / Gradle / Ivy
/**
Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016. All rights reserved.
Contact:
SYSTAP, LLC DBA Blazegraph
2501 Calvert ST NW #106
Washington, DC 20008
[email protected]
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.bigdata.io.writecache;
import java.util.concurrent.TimeUnit;
import com.bigdata.counters.CAT;
import com.bigdata.counters.CounterSet;
import com.bigdata.counters.Instrument;
import com.bigdata.counters.OneShotInstrument;
import com.bigdata.io.writecache.WriteCache.ReadCache;
import com.bigdata.io.writecache.WriteCacheService.WriteTask;
import com.bigdata.util.Bytes;
/**
* Performance counters for the {@link WriteCacheService}.
*
* @author Bryan Thompson
*/
public class WriteCacheServiceCounters extends WriteCacheCounters implements
IWriteCacheServiceCounters {
/** #of configured buffers (immutable). */
public final int nbuffers;
/**
* The configured dirty list threshold before evicting to disk (immutable).
*/
public final int dirtyListThreshold;
/**
* The threshold of reclaimable space at which we will attempt to coalesce
* records in cache buffers.
*/
public final int compactingThreshold;
/**
* #of dirty buffers (instantaneous).
*
* Note: This is set by the {@link WriteTask} thread and by
* {@link WriteCacheService#reset()}. It is volatile so it is visible from a
* thread which looks at the counters and for correct publication from
* reset().
*/
public volatile int ndirty;
/**
* #of clean buffers (instantaneous).
*
* Note: This is set by the {@link WriteTask} thread and by
* {@link WriteCacheService#reset()}. It is volatile so it is visible from a
* thread which looks at the counters and for correct publication from
* reset().
*/
public volatile int nclean;
/**
* The maximum #of dirty buffers observed by the {@link WriteTask} (its
* maximum observed backlog). This is only set by the {@link WriteTask}
* thread, but it is volatile so it is visible from a thread which looks at
* the counters.
*/
public volatile int maxdirty;
/**
* #of times the {@link WriteCacheService} was reset (typically to handle an
* error condition).
*
* Note: This is set by {@link WriteCacheService#reset()}. It is volatile so
* it is visible from a thread which looks at the counters and for correct
* publication from reset().
*/
public volatile long nreset;
/**
* The #of {@link WriteCache} blocks sent by the leader to the first
* downstream follower.
*/
public volatile long nsend;
/**
* The #of {@link WriteCache} buffers written to the disk.
*/
public volatile long nbufferEvictedToChannel;
/**
* The cumulative latency (nanoseconds) when writing a write cache buffer
* onto the backing channel.
*
* See BLZG-1589 (new latency-oriented counters)
*/
public volatile long elapsedBufferEvictedToChannelNanos;
/**
* The cumulative number of records written onto the backing channel. This
* may be used to track the number of induced write operators per second.
* However, note that the RWStore will pad out writes to their slot size in
* order to offer the underlying file system and disk controller an
* opportunity to meld together multiple writes into a single IO. This is
* particularly effective in combination with the small slots optimization.
*
* See BLZG-1589 (new latency-oriented counters)
*/
public volatile long nrecordsEvictedToChannel;
/**
* The #of {@link WriteCache} buffers that have been compacted.
*/
public volatile long ncompact;
/**
* The #of record-level writes made onto the {@link WriteCacheService}.
*/
public volatile long ncacheWrites;
/**
* The cumulative latency (nanoseconds) when writing into the
* write cache.
*
* See BLZG-1589 (new latency-oriented counters)
*/
public volatile long elapsedCacheWriteNanos;
/**
* The requests to clear an address from the cache.
*
* @see WriteCacheService#clearWrite(long, int)
*/
public volatile long nclearAddrRequests;
/**
* The #of addresses actually found and cleared from the cache by the
* {@link WriteCacheService}.
*
* @see WriteCacheService#clearWrite(long, int)
*/
public volatile long nclearAddrCleared;
/**
* The #of read requests that were a miss in the cache and resulted in a
* read through to the disk where the record was NOT installed into the read
* cache (either because there is no read cache, because the record is too
* large for the read cache, or because the thread could not obtain a
* {@link ReadCache} block to install the read).
*/
public final CAT nreadNotInstalled = new CAT();
public final CAT memoCacheSize = new CAT();
public WriteCacheServiceCounters(final int nbuffers,
final int dirtyListThreshold, final int compactingThreshold) {
this.nbuffers = nbuffers;
this.dirtyListThreshold = dirtyListThreshold;
this.compactingThreshold = compactingThreshold;
}
@Override
public CounterSet getCounters() {
final CounterSet root = super.getCounters();
root.addCounter(NBUFFERS, new OneShotInstrument(nbuffers));
root.addCounter(DIRTY_LIST_THRESHOLD, new OneShotInstrument(
dirtyListThreshold));
root.addCounter(COMPACTING_THRESHOLD, new OneShotInstrument(
compactingThreshold));
root.addCounter(NDIRTY, new Instrument() {
@Override
public void sample() {
setValue(ndirty);
}
});
root.addCounter(MAX_DIRTY, new Instrument() {
@Override
public void sample() {
setValue(maxdirty);
}
});
root.addCounter(NCLEAN, new Instrument() {
@Override
public void sample() {
setValue(nclean);
}
});
root.addCounter(NRESET, new Instrument() {
@Override
public void sample() {
setValue(nreset);
}
});
root.addCounter(NSEND, new Instrument() {
@Override
public void sample() {
setValue(nsend);
}
});
root.addCounter(NBUFFER_EVICTED_TO_CHANNEL, new Instrument() {
@Override
public void sample() {
setValue(nbufferEvictedToChannel);
}
});
root.addCounter(ELAPSED_BUFFER_EVICTED_TO_CHANNEL_NANOS, new Instrument() {
@Override
public void sample() {
setValue(elapsedBufferEvictedToChannelNanos);
}
});
root.addCounter(AVERAGE_BUFFER_EVICTED_TO_CHANNEL_NANOS, new Instrument() {
@Override
public void sample() {
if (nbufferEvictedToChannel > 0) {
final double d = elapsedBufferEvictedToChannelNanos / nbufferEvictedToChannel;
setValue(((long) (d * 100)) / 100d);
}
}
});
root.addCounter(NRECORDS_EVICTED_TO_CHANNEL, new Instrument() {
@Override
public void sample() {
setValue(nrecordsEvictedToChannel);
}
});
root.addCounter(AVERAGE_RECORD_EVICTED_TO_CHANNEL_NANOS, new Instrument() {
@Override
public void sample() {
if (nrecordsEvictedToChannel > 0) {
/*
* Note: records are evicted a buffer at a time. Therefore
* we use the same divisor here as we do for the
* AVERAGE_BUFFER_EVICTED_TO_CHANNEL_NANOS.
*/
final double d = elapsedBufferEvictedToChannelNanos / nrecordsEvictedToChannel;
setValue(((long) (d * 100)) / 100d);
}
}
});
root.addCounter(AVERAGE_RANDOM_WRITES_PER_SECOND, new Instrument() {
@Override
public void sample() {
if (nrecordsEvictedToChannel > 0) {
/*
* Note: records are evicted a buffer at a time. Therefore
* we use the same divisor here as we do for the
* AVERAGE_BUFFER_EVICTED_TO_CHANNEL_NANOS.
*/
// records written / second.
final double d = TimeUnit.NANOSECONDS.toSeconds(elapsedBufferEvictedToChannelNanos)
/ ((double) nrecordsEvictedToChannel);
// two decimal places of precision.
final double v = ((long) (d * 100)) / 100d;
setValue(v);
}
}
});
root.addCounter(NCOMPACT, new Instrument() {
@Override
public void sample() {
setValue(ncompact);
}
});
root.addCounter(NCACHE_WRITES, new Instrument() {
@Override
public void sample() {
setValue(ncacheWrites);
}
});
root.addCounter(ELAPSED_CACHE_WRITES_NANOS, new Instrument() {
@Override
public void sample() {
setValue(elapsedCacheWriteNanos);
}
});
root.addCounter(AVERAGE_CACHE_WRITE_NANOS, new Instrument() {
@Override
public void sample() {
if (ncacheWrites > 0) {
final double d = elapsedCacheWriteNanos / ncacheWrites;
setValue(((long) (d * 100)) / 100d);
}
}
});
root.addCounter(NCLEAR_ADDR_REQUESTS, new Instrument() {
@Override
public void sample() {
setValue(nclearAddrRequests);
}
});
root.addCounter(NCLEAR_ADDR_CLEARED, new Instrument() {
@Override
public void sample() {
setValue(nclearAddrCleared);
}
});
root.addCounter(MB_PER_SEC, new Instrument() {
@Override
public void sample() {
final double mbPerSec = (((double) bytesWritten)
/ Bytes.megabyte32 / (TimeUnit.NANOSECONDS
.toSeconds(elapsedWriteNanos)));
setValue(((long) (mbPerSec * 100)) / 100d);
}
});
/*
* Read Cache.
*/
root.addCounter(NREAD_NOT_INSTALLED, new Instrument() {
@Override
public void sample() {
setValue(nreadNotInstalled.get());
}
});
root.addCounter(MEMO_CACHE_SIZE, new Instrument() {
@Override
public void sample() {
setValue(memoCacheSize.get());
}
});
return root;
}
} // class WriteCacheServiceCounters