// Copyright 2017 JanusGraph Authors
//
// 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.janusgraph.diskstorage.util;
import java.io.IOException;
import com.google.common.base.Preconditions;
import org.janusgraph.diskstorage.StaticBuffer;
import org.janusgraph.diskstorage.Entry;
import org.janusgraph.diskstorage.keycolumnvalue.KeyIterator;
import org.apache.commons.lang.StringUtils;
/**
* This class is used by {@code MetricInstrumentedStore} to measure wallclock
* time, method invocation counts, and exceptions thrown by the methods on
* {@link RecordIterator} instances returned from
* {@link MetricInstrumentedStore#getSlice(org.janusgraph.diskstorage.keycolumnvalue.KeySliceQuery, org.janusgraph.diskstorage.keycolumnvalue.StoreTransaction)}.
*
* @author Dan LaRocque <dalaro@hopcount.org>
*/
public class MetricInstrumentedIterator implements KeyIterator {
private final KeyIterator iterator;
private final String p;
private static final String M_HAS_NEXT = "hasNext";
private static final String M_NEXT = "next";
private static final String M_CLOSE = "close";
/**
* If the iterator argument is non-null, then return a new
* {@code MetricInstrumentedIterator} wrapping it. Metrics for method calls
* on the wrapped instance will be prefixed with the string {@code prefix}
* which must be non-null. If the iterator argument is null, then return
* null.
*
* @param keyIterator
* the iterator to wrap with Metrics measurements
* @param prefix
* the Metrics name prefix string
*
* @return a wrapper around {@code keyIterator} or null if
* {@code keyIterator} is null
*/
public static MetricInstrumentedIterator of(KeyIterator keyIterator, String... prefix) {
if (keyIterator == null) {
return null;
}
Preconditions.checkNotNull(prefix);
return new MetricInstrumentedIterator(keyIterator, StringUtils.join(prefix,"."));
}
private MetricInstrumentedIterator(KeyIterator i, String p) {
this.iterator = i;
this.p = p;
}
@Override
public boolean hasNext() {
return MetricInstrumentedStore.runWithMetrics(p, null, M_HAS_NEXT,
new UncheckedCallable<Boolean>() {
public Boolean call() {
return Boolean.valueOf(iterator.hasNext());
}
}
);
}
@Override
public StaticBuffer next() {
return MetricInstrumentedStore.runWithMetrics(p, null, M_NEXT,
new UncheckedCallable<StaticBuffer>() {
public StaticBuffer call() {
return iterator.next();
}
}
);
}
@Override
public void close() throws IOException {
MetricInstrumentedStore.runWithMetrics(p, null, M_CLOSE,
new IOCallable<Void>() {
public Void call() throws IOException {
iterator.close();
return null;
}
}
);
}
@Override
public RecordIterator<Entry> getEntries() {
// TODO: add metrics to entries if ever needed
return iterator.getEntries();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}