diff --git a/adapter-cqld4/pom.xml b/adapter-cqld4/pom.xml index 63cf79d6c..f38d09d41 100644 --- a/adapter-cqld4/pom.xml +++ b/adapter-cqld4/pom.xml @@ -92,8 +92,8 @@ org.bouncycastle - bcprov-jdk15on - 1.70 + bcprov-jdk18on + 1.75 com.fasterxml.jackson.core diff --git a/adapters-api/src/main/java/io/nosqlbench/adapters/api/activityimpl/BaseOpDispenser.java b/adapters-api/src/main/java/io/nosqlbench/adapters/api/activityimpl/BaseOpDispenser.java index 04d19a2c5..ac061671c 100644 --- a/adapters-api/src/main/java/io/nosqlbench/adapters/api/activityimpl/BaseOpDispenser.java +++ b/adapters-api/src/main/java/io/nosqlbench/adapters/api/activityimpl/BaseOpDispenser.java @@ -57,6 +57,7 @@ public abstract class BaseOpDispenser implements OpDispenser private final String opName; protected final DriverAdapter adapter; private final NBLabels labels; + public final Timer verifierTimer; private boolean instrument; private Timer successTimer; private Timer errorTimer; @@ -97,7 +98,8 @@ public abstract class BaseOpDispenser implements OpDispenser List> verifiers = new ArrayList<>(); verifiers = configureVerifiers(op); this._verifier = CycleFunctions.of((a, b) -> a && b, verifiers, true); - this.tlVerifier = ThreadLocal.withInitial(() -> _verifier.newInstance()); + this.tlVerifier = ThreadLocal.withInitial(_verifier::newInstance); + this.verifierTimer = ActivityMetrics.timer(this,"verifier",3); } private CycleFunction cloneVerifiers() { diff --git a/engine-api/src/main/java/io/nosqlbench/engine/api/activityapi/core/ActivityInstrumentation.java b/engine-api/src/main/java/io/nosqlbench/engine/api/activityapi/core/ActivityInstrumentation.java index 11682c3c0..4a3ce0550 100644 --- a/engine-api/src/main/java/io/nosqlbench/engine/api/activityapi/core/ActivityInstrumentation.java +++ b/engine-api/src/main/java/io/nosqlbench/engine/api/activityapi/core/ActivityInstrumentation.java @@ -133,4 +133,6 @@ public interface ActivityInstrumentation { * @return a new or existing {@link Histogram} */ Histogram getOrCreateTriesHistogram(); + + Timer getOrCreateVerifierTimer(); } diff --git a/engine-api/src/main/java/io/nosqlbench/engine/api/activityapi/core/CoreActivityInstrumentation.java b/engine-api/src/main/java/io/nosqlbench/engine/api/activityapi/core/CoreActivityInstrumentation.java index 8e9a90866..ad7c72352 100644 --- a/engine-api/src/main/java/io/nosqlbench/engine/api/activityapi/core/CoreActivityInstrumentation.java +++ b/engine-api/src/main/java/io/nosqlbench/engine/api/activityapi/core/CoreActivityInstrumentation.java @@ -113,4 +113,10 @@ public class CoreActivityInstrumentation implements ActivityInstrumentation { public synchronized Histogram getOrCreateTriesHistogram() { return ActivityMetrics.histogram(this.activity,"tries", this.activity.getHdrDigits()); } + + @Override + public Timer getOrCreateVerifierTimer() { + return ActivityMetrics.timer(this.activity,"verifier", this.activity.getHdrDigits()); + + } } diff --git a/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/input/AtomicInput.java b/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/input/AtomicInput.java index f54c27f34..e64323562 100644 --- a/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/input/AtomicInput.java +++ b/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/input/AtomicInput.java @@ -63,14 +63,15 @@ public class AtomicInput implements Input, ActivityDefObserver, Gauge, NBL this.parent = parent; this.activityDef = activityDef; onActivityDefUpdate(activityDef); - ActivityMetrics.gauge(this, "input_cycles_first", new NBFunctionGauge(this, () -> (double)this.cycles_min.get())); - ActivityMetrics.gauge(this, "input_cycles_last", new NBFunctionGauge(this, () -> (double)this.cycles_max.get())); - ActivityMetrics.gauge(this, "input_cycle", new NBFunctionGauge(this, () -> (double)this.cycle_value.get())); - ActivityMetrics.gauge(this, "input_cycles_total", new NBFunctionGauge(this, this::getTotalCycles)); - ActivityMetrics.gauge(this, "input_recycles_first", new NBFunctionGauge(this, () -> (double)this.recycles_min.get())); - ActivityMetrics.gauge(this, "input_recycles_last", new NBFunctionGauge(this, () -> (double)this.recycles_max.get())); - ActivityMetrics.gauge(this, "input_recycle", new NBFunctionGauge(this, () -> (double) this.recycle_value.get())); - ActivityMetrics.gauge(this, "input_recycles_total", new NBFunctionGauge(this, this::getTotalRecycles)); + + ActivityMetrics.register(new NBFunctionGauge(this, () -> (double)this.cycles_min.get(),"input_cycles_first")); + ActivityMetrics.register(new NBFunctionGauge(this, () -> (double)this.cycles_max.get(), "input_cycles_last")); + ActivityMetrics.register(new NBFunctionGauge(this, () -> (double)this.cycle_value.get(), "input_cycle")); + ActivityMetrics.register(new NBFunctionGauge(this, this::getTotalCycles, "input_cycles_total")); + ActivityMetrics.register(new NBFunctionGauge(this, () -> (double)this.recycles_min.get(), "input_recycles_first")); + ActivityMetrics.register(new NBFunctionGauge(this, () -> (double)this.recycles_max.get(), "input_recycles_last")); + ActivityMetrics.register(new NBFunctionGauge(this, () -> (double) this.recycle_value.get(),"input_recycle")); + ActivityMetrics.register(new NBFunctionGauge(this, this::getTotalRecycles,"input_recycles_total")); } private double getTotalRecycles() { diff --git a/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/uniform/StandardActivity.java b/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/uniform/StandardActivity.java index 1cf1c9ec9..6a3a07dc6 100644 --- a/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/uniform/StandardActivity.java +++ b/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/uniform/StandardActivity.java @@ -98,7 +98,7 @@ public class StandardActivity extends SimpleActivity implements for (OpTemplate ot : opTemplates) { ParsedOp incompleteOpDef = new ParsedOp(ot, NBConfiguration.empty(), List.of(), this); String driverName = incompleteOpDef.takeOptionalStaticValue("driver", String.class) - .or(() -> incompleteOpDef.takeOptionalStaticValue("type",String.class)) + .or(() -> incompleteOpDef.takeOptionalStaticValue("type", String.class)) .or(() -> defaultDriverOption) .orElseThrow(() -> new OpConfigError("Unable to identify driver name for op template:\n" + ot)); @@ -152,12 +152,14 @@ public class StandardActivity extends SimpleActivity implements throw new OpConfigError("Error mapping workload template to operations: " + e.getMessage(), null, e); } - this.pendingOpsGauge= ActivityMetrics.gauge(this,"ops_pending", - new NBFunctionGauge(this,() -> this.getProgressMeter().getSummary().pending())); - this.activeOpsGauge = ActivityMetrics.gauge(this,"ops_active", - new NBFunctionGauge(this,() -> this.getProgressMeter().getSummary().current())); - this.completeOpsGauge= ActivityMetrics.gauge(this,"ops_complete", - new NBFunctionGauge(this,() -> this.getProgressMeter().getSummary().complete())); + this.pendingOpsGauge = ActivityMetrics.register( + new NBFunctionGauge(this, () -> this.getProgressMeter().getSummary().pending(), "ops_pending") + ); + this.activeOpsGauge = ActivityMetrics.register( + new NBFunctionGauge(this, () -> this.getProgressMeter().getSummary().current(),"ops_active") + ); + this.completeOpsGauge = ActivityMetrics.register( + new NBFunctionGauge(this, () -> this.getProgressMeter().getSummary().complete(),"ops_complete")); } @Override @@ -217,7 +219,7 @@ public class StandardActivity extends SimpleActivity implements public void shutdownActivity() { for (Map.Entry entry : adapters.entrySet()) { String adapterName = entry.getKey(); - DriverAdapter adapter = entry.getValue(); + DriverAdapter adapter = entry.getValue(); adapter.getSpaceCache().getElements().forEach((spaceName, space) -> { if (space instanceof AutoCloseable autocloseable) { try { diff --git a/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/uniform/actions/StandardAction.java b/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/uniform/actions/StandardAction.java index 6c06d308d..b8a3d0cac 100644 --- a/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/uniform/actions/StandardAction.java +++ b/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/uniform/actions/StandardAction.java @@ -59,6 +59,7 @@ public class StandardAction, R extends Op> impl private final NBErrorHandler errorHandler; private final OpSequence> opsequence; private final int maxTries; + private final Timer verifierTimer; public StandardAction(A activity, int slot) { this.activity = activity; @@ -71,6 +72,7 @@ public class StandardAction, R extends Op> impl resultTimer = activity.getInstrumentation().getOrCreateResultTimer(); resultSuccessTimer = activity.getInstrumentation().getOrCreateResultSuccessTimer(); errorHandler = activity.getErrorHandler(); + verifierTimer = activity.getInstrumentation().getOrCreateVerifierTimer(); } @Override @@ -109,16 +111,18 @@ public class StandardAction, R extends Op> impl "one of [RunnableOp, CycleOp, or ChainingOp]"); } - CycleFunction verifier = dispenser.getVerifier(); - try { - verifier.setVariable("result", result); - verifier.setVariable("cycle",cycle); - Boolean isGood = verifier.apply(cycle); - if (!isGood) { - throw new ResultVerificationError("result verification failed", maxTries - tries, verifier.getExpressionDetails()); + try (Timer.Context ignored = verifierTimer.time()) { + CycleFunction verifier = dispenser.getVerifier(); + try { + verifier.setVariable("result", result); + verifier.setVariable("cycle",cycle); + Boolean isGood = verifier.apply(cycle); + if (!isGood) { + throw new ResultVerificationError("result verification failed", maxTries - tries, verifier.getExpressionDetails()); + } + } catch (Exception e) { + throw new ResultVerificationError(e, maxTries - tries, verifier.getExpressionDetails()); } - } catch (Exception e) { - throw new ResultVerificationError(e, maxTries - tries, verifier.getExpressionDetails()); } } catch (Exception e) { error = e; diff --git a/engine-api/src/main/java/io/nosqlbench/engine/api/metrics/ExceptionTimerMetrics.java b/engine-api/src/main/java/io/nosqlbench/engine/api/metrics/ExceptionTimerMetrics.java index 2d49f8706..7f64a4033 100644 --- a/engine-api/src/main/java/io/nosqlbench/engine/api/metrics/ExceptionTimerMetrics.java +++ b/engine-api/src/main/java/io/nosqlbench/engine/api/metrics/ExceptionTimerMetrics.java @@ -41,7 +41,7 @@ public class ExceptionTimerMetrics { this.allerrors = ActivityMetrics.timer( parentLabels, - "errortimers.ALL", + "errortimers_ALL", activityDef.getParams().getOptionalInteger("hdr_digits").orElse(4) ); } diff --git a/engine-api/src/test/java/io/nosqlbench/engine/api/metrics/ActivityMetricsTest.java b/engine-api/src/test/java/io/nosqlbench/engine/api/metrics/ActivityMetricsTest.java index abf5cc22c..fae9e7b3d 100644 --- a/engine-api/src/test/java/io/nosqlbench/engine/api/metrics/ActivityMetricsTest.java +++ b/engine-api/src/test/java/io/nosqlbench/engine/api/metrics/ActivityMetricsTest.java @@ -55,4 +55,9 @@ public class ActivityMetricsTest { } + @Test + public void testSanityCheckSanitize() { + String result = ActivityMetrics.sanitize("test-dynamic-params.input_cycles_first"); + assertThat(result).isEqualTo("test_dynamic_params__input_cycles_first"); + } } diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivityExecutor.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivityExecutor.java index e047374ff..949d47f02 100644 --- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivityExecutor.java +++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivityExecutor.java @@ -15,6 +15,9 @@ */ package io.nosqlbench.engine.core.lifecycle.activity; +import com.codahale.metrics.Gauge; +import io.nosqlbench.api.engine.metrics.ActivityMetrics; +import io.nosqlbench.api.engine.metrics.instruments.NBFunctionGauge; import io.nosqlbench.api.labels.NBLabeledElement; import io.nosqlbench.api.labels.NBLabels; import io.nosqlbench.engine.api.activityapi.core.*; @@ -72,6 +75,7 @@ public class ActivityExecutor implements NBLabeledElement, ActivityController, P private long stoppedAt = 0L; private ActivityExecutorShutdownHook shutdownHook = null; + private NBFunctionGauge threadsGauge; public ActivityExecutor(Activity activity, String sessionId) { this.activity = activity; @@ -409,6 +413,7 @@ public class ActivityExecutor implements NBLabeledElement, ActivityController, P // before threads start running such as metrics instruments activity.initActivity(); startMotorExecutorService(); + registerMetrics(); startRunningActivityThreads(); awaitMotorsAtLeastRunning(); logger.debug("STARTED " + activityDef.getAlias()); @@ -417,6 +422,7 @@ public class ActivityExecutor implements NBLabeledElement, ActivityController, P this.exception = e; } finally { stoppedAt=System.currentTimeMillis(); + unregisterMetrics(); activity.shutdownActivity(); activity.closeAutoCloseables(); ExecutionResult result = new ExecutionResult(startedAt, stoppedAt, "", exception); @@ -442,14 +448,22 @@ public class ActivityExecutor implements NBLabeledElement, ActivityController, P } } - public synchronized void startActivity() { - RunStateImage startable = tally.awaitNoneOther(1000L, RunState.Uninitialized, RunState.Stopped); - if (startable.isTimeout()) { - throw new RuntimeException("Unable to start activity '" + getActivity().getAlias() + "' which is in state " + startable); - } - startMotorExecutorService(); - startRunningActivityThreads(); - awaitMotorsAtLeastRunning(); +// public synchronized void startActivity() { +// RunStateImage startable = tally.awaitNoneOther(1000L, RunState.Uninitialized, RunState.Stopped); +// if (startable.isTimeout()) { +// throw new RuntimeException("Unable to start activity '" + getActivity().getAlias() + "' which is in state " + startable); +// } +// startMotorExecutorService(); +// startRunningActivityThreads(); +// awaitMotorsAtLeastRunning(); +// } + + private void registerMetrics() { + this.threadsGauge = ActivityMetrics.register(new NBFunctionGauge(activity, () -> (double) this.motors.size(), "threads")); + } + private void unregisterMetrics() { + ActivityMetrics.unregister(this.threadsGauge); + this.threadsGauge=null; } private boolean shutdownExecutorService(int secondsToWait) { @@ -567,6 +581,16 @@ public class ActivityExecutor implements NBLabeledElement, ActivityController, P .build()); } + private class ThreadsGauge implements Gauge { + public ThreadsGauge(ActivityExecutor activityExecutor) { + ActivityExecutor ae = activityExecutor; + } + + @Override + public Double getValue() { + return (double) ActivityExecutor.this.motors.size(); + } + } } diff --git a/engine-core/src/test/java/io/nosqlbench/engine/core/ActivityExecutorTest.java b/engine-core/src/test/java/io/nosqlbench/engine/core/ActivityExecutorTest.java index f00d25731..fb62f960c 100644 --- a/engine-core/src/test/java/io/nosqlbench/engine/core/ActivityExecutorTest.java +++ b/engine-core/src/test/java/io/nosqlbench/engine/core/ActivityExecutorTest.java @@ -16,18 +16,18 @@ package io.nosqlbench.engine.core; -import io.nosqlbench.api.labels.NBLabeledElement; import io.nosqlbench.api.engine.activityimpl.ActivityDef; -import io.nosqlbench.engine.api.activityapi.core.*; -import io.nosqlbench.engine.api.activityapi.input.Input; +import io.nosqlbench.api.labels.NBLabeledElement; +import io.nosqlbench.engine.api.activityapi.core.ActionDispenser; +import io.nosqlbench.engine.api.activityapi.core.Activity; +import io.nosqlbench.engine.api.activityapi.core.MotorDispenser; +import io.nosqlbench.engine.api.activityapi.core.SyncAction; import io.nosqlbench.engine.api.activityapi.input.InputDispenser; import io.nosqlbench.engine.api.activityapi.output.OutputDispenser; import io.nosqlbench.engine.api.activityimpl.CoreServices; import io.nosqlbench.engine.api.activityimpl.SimpleActivity; import io.nosqlbench.engine.api.activityimpl.action.CoreActionDispenser; -import io.nosqlbench.engine.api.activityimpl.input.AtomicInput; import io.nosqlbench.engine.api.activityimpl.input.CoreInputDispenser; -import io.nosqlbench.engine.api.activityimpl.motor.CoreMotor; import io.nosqlbench.engine.api.activityimpl.motor.CoreMotorDispenser; import io.nosqlbench.engine.core.lifecycle.ExecutionResult; import io.nosqlbench.engine.core.lifecycle.activity.ActivityExecutor; @@ -37,11 +37,9 @@ import org.apache.logging.log4j.Logger; import org.junit.jupiter.api.Test; import java.util.Map; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ForkJoinTask; -import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; class ActivityExecutorTest { @@ -85,41 +83,41 @@ class ActivityExecutorTest { // // } - @Test - synchronized void testDelayedStartSanity() { - - ActivityDef activityDef = ActivityDef.parseActivityDef("driver=diag;alias=test-delayed-start;cycles=1000;initdelay=2000;"); - new ActivityTypeLoader().load(activityDef, NBLabeledElement.EMPTY); - - Activity activity = new DelayedInitActivity(activityDef); - final InputDispenser inputDispenser = new CoreInputDispenser(activity); - final ActionDispenser actionDispenser = new CoreActionDispenser(activity); - final OutputDispenser outputDispenser = CoreServices.getOutputDispenser(activity).orElse(null); - - MotorDispenser motorDispenser = new CoreMotorDispenser(activity, inputDispenser, actionDispenser, outputDispenser); - activity.setActionDispenserDelegate(actionDispenser); - activity.setOutputDispenserDelegate(outputDispenser); - activity.setInputDispenserDelegate(inputDispenser); - activity.setMotorDispenserDelegate(motorDispenser); - - ActivityExecutor activityExecutor = new ActivityExecutor(activity, "test-delayed-start"); - - ExecutorService testExecutor = Executors.newCachedThreadPool(); - Future future = testExecutor.submit(activityExecutor); - - - try { - activityDef.setThreads(1); - activityExecutor.startActivity(); - future.get(); - testExecutor.shutdownNow(); - - } catch (final Exception e) { - fail("Unexpected exception", e); - } - - assertThat(inputDispenser.getInput(10).getInputSegment(3)).isNull(); - } +// @Test +// synchronized void testDelayedStartSanity() { +// +// ActivityDef activityDef = ActivityDef.parseActivityDef("driver=diag;alias=test-delayed-start;cycles=1000;initdelay=2000;"); +// new ActivityTypeLoader().load(activityDef, NBLabeledElement.EMPTY); +// +// Activity activity = new DelayedInitActivity(activityDef); +// final InputDispenser inputDispenser = new CoreInputDispenser(activity); +// final ActionDispenser actionDispenser = new CoreActionDispenser(activity); +// final OutputDispenser outputDispenser = CoreServices.getOutputDispenser(activity).orElse(null); +// +// MotorDispenser motorDispenser = new CoreMotorDispenser(activity, inputDispenser, actionDispenser, outputDispenser); +// activity.setActionDispenserDelegate(actionDispenser); +// activity.setOutputDispenserDelegate(outputDispenser); +// activity.setInputDispenserDelegate(inputDispenser); +// activity.setMotorDispenserDelegate(motorDispenser); +// +// ActivityExecutor activityExecutor = new ActivityExecutor(activity, "test-delayed-start"); +// +// ExecutorService testExecutor = Executors.newCachedThreadPool(); +// Future future = testExecutor.submit(activityExecutor); +// +// +// try { +// activityDef.setThreads(1); +// activityExecutor.startActivity(); +// future.get(); +// testExecutor.shutdownNow(); +// +// } catch (final Exception e) { +// fail("Unexpected exception", e); +// } +// +// assertThat(inputDispenser.getInput(10).getInputSegment(3)).isNull(); +// } @Test synchronized void testNewActivityExecutor() { @@ -129,7 +127,7 @@ class ActivityExecutorTest { Activity simpleActivity = new SimpleActivity(activityDef, NBLabeledElement.forMap(Map.of())); - this.getActivityMotorFactory(this.motorActionDelay(999), new AtomicInput(simpleActivity,activityDef)); +// this.getActivityMotorFactory(this.motorActionDelay(999), new AtomicInput(simpleActivity,activityDef)); final InputDispenser inputDispenser = new CoreInputDispenser(simpleActivity); final ActionDispenser actionDispenser = new CoreActionDispenser(simpleActivity); @@ -144,7 +142,9 @@ class ActivityExecutorTest { ActivityExecutor activityExecutor = new ActivityExecutor(simpleActivity, "test-new-executor"); activityDef.setThreads(5); - activityExecutor.startActivity(); + ForkJoinTask executionResultForkJoinTask = ForkJoinPool.commonPool().submit(activityExecutor); + +// activityExecutor.startActivity(); final int[] speeds = {1, 50, 5, 50, 2, 50}; for (int offset = 0; offset < speeds.length; offset += 2) { @@ -160,6 +160,7 @@ class ActivityExecutorTest { fail("Not expecting exception", e); } } + executionResultForkJoinTask.cancel(true); // Used for slowing the roll due to state transitions in test. try { @@ -170,18 +171,6 @@ class ActivityExecutorTest { } } - private MotorDispenser getActivityMotorFactory(final Action lc, Input ls) { - return new MotorDispenser<>() { - @Override - public Motor getMotor(final ActivityDef activityDef, final int slotId) { - final Activity activity = new SimpleActivity(activityDef, NBLabeledElement.forMap(Map.of())); - final Motor cm = new CoreMotor<>(activity, slotId, ls); - cm.setAction(lc); - return cm; - } - }; - } - private SyncAction motorActionDelay(long delay) { return new SyncAction() { @Override diff --git a/mvn-defaults/pom.xml b/mvn-defaults/pom.xml index 1fe5ef5b2..950d45ca4 100644 --- a/mvn-defaults/pom.xml +++ b/mvn-defaults/pom.xml @@ -26,7 +26,7 @@ - 5.21.1-SNAPSHOT + 5.17.4-SNAPSHOT INFO diff --git a/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/ActivityMetrics.java b/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/ActivityMetrics.java index 49877615d..2744a4059 100644 --- a/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/ActivityMetrics.java +++ b/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/ActivityMetrics.java @@ -34,6 +34,7 @@ import java.util.DoubleSummaryStatistics; import java.util.List; import java.util.ServiceLoader; import java.util.concurrent.TimeUnit; +import java.util.prefs.BackingStoreException; import java.util.regex.Pattern; public class ActivityMetrics { @@ -76,10 +77,10 @@ public class ActivityMetrics { @SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter") private static Metric register(NBLabels labels, MetricProvider metricProvider) { - labels = labelFilter!=null ? labelFilter.apply(labels) : labels; + labels = labelFilter != null ? labelFilter.apply(labels) : labels; labels = labelValidator != null ? labelValidator.apply(labels) : labels; - final String graphiteName = labels.linearizeValues('.',"[activity]","[space]","[op]","name"); + final String graphiteName = labels.linearizeValues('.', "[activity]", "[space]", "[op]", "name"); Metric metric = get().getMetrics().get(graphiteName); if (null == metric) { @@ -96,6 +97,49 @@ public class ActivityMetrics { return metric; } + /** + * Calls to this version of register must be done with a pre-built metric instrument. + * This means that it is not suitable for lazily creating metric objects directly on + * instances which are one of many. Instead, call this to register metrics at the start + * of an owning element. + * + * This version of register expects that you have fully labeled a metric, including + * addint the 'name' field, also known as the metric family name in some specifications. + * + * It is due to be replaced by a different registry format soon. + * + * @param labeledMetric + * @return the metric instance + */ + public static M register(M labeledMetric) { + NBLabels labels = labeledMetric.getLabels(); + labels = labelFilter != null ? labelFilter.apply(labels) : labels; + labels = labelValidator != null ? labelValidator.apply(labels) : labels; + + final String graphiteName = labels.linearizeValues('.', "[activity]", "[space]", "[op]", "name"); +// String sanitized = sanitize(graphiteName); +// if (!graphiteName.equals(sanitized)) { +// throw new RuntimeException("Attempted to register a metric which was not compatible with labeled metric forms. Submitted as '" + graphiteName + "', but should likely be '" + sanitized + "'"); +// } + Metric metric = get().getMetrics().get(graphiteName); + + metric = get().getMetrics().get(graphiteName); + if (metric!=null) { + logger.warn("Metric already registered for '" + graphiteName + "', probably logic error which could invalidate metric values."); + } else { + get().register(graphiteName, labeledMetric); + } + return labeledMetric; + } + + public static void unregister(NBLabeledElement element) { + final String graphiteName = element.getLabels().linearizeValues('.', "[activity]", "[space]", "[op]", "name"); + if (!get().getMetrics().containsKey(graphiteName)) { + logger.warn("Removing non-extant metric by name: '"+ graphiteName + "'"); + } + get().remove(graphiteName); + } + /** *

Create a timer associated with an activity.

* @@ -112,7 +156,7 @@ public class ActivityMetrics { * @return the timer, perhaps a different one if it has already been registered */ public static Timer timer(NBLabeledElement parent, String metricFamilyName, int hdrdigits) { - final NBLabels labels = parent.getLabels().and("name",sanitize(metricFamilyName)); + final NBLabels labels = parent.getLabels().and("name", sanitize(metricFamilyName)); Timer registeredTimer = (Timer) register(labels, () -> @@ -164,7 +208,7 @@ public class ActivityMetrics { * @return the counter, perhaps a different one if it has already been registered */ public static Counter counter(NBLabeledElement parent, String metricFamilyName) { - final NBLabels labels = parent.getLabels().and("name",metricFamilyName); + final NBLabels labels = parent.getLabels().and("name", metricFamilyName); return (Counter) register(labels, () -> new NBMetricCounter(labels)); } @@ -180,7 +224,7 @@ public class ActivityMetrics { * @return the meter, perhaps a different one if it has already been registered */ public static Meter meter(NBLabeledElement parent, String metricFamilyName) { - final NBLabels labels = parent.getLabels().and("name",sanitize(metricFamilyName)); + final NBLabels labels = parent.getLabels().and("name", sanitize(metricFamilyName)); return (Meter) register(labels, () -> new NBMetricMeter(labels)); } @@ -201,27 +245,30 @@ public class ActivityMetrics { * and so on. It uses the same data reservoir for all views, but only returns one of them as a handle to the metric. * This has the effect of leaving some of the metric objects unreferencable from the caller side. This may need * to be changed in a future update in the even that full inventory management is required on metric objects here. - * @param parent The labeled element the metric pertains to - * @param metricFamilyName The name of the measurement + * + * @param parent + * The labeled element the metric pertains to + * @param metricFamilyName + * The name of the measurement * @return One of the created metrics, suitable for calling {@link DoubleSummaryGauge#accept(double)} on. */ public static DoubleSummaryGauge summaryGauge(NBLabeledElement parent, String metricFamilyName) { DoubleSummaryStatistics stats = new DoubleSummaryStatistics(); DoubleSummaryGauge anyGauge = null; - for (DoubleSummaryGauge.Stat statName: DoubleSummaryGauge.Stat.values()){ + for (DoubleSummaryGauge.Stat statName : DoubleSummaryGauge.Stat.values()) { final NBLabels labels = parent.getLabels() - .and("name",sanitize(metricFamilyName)) - .modifyValue("name", n -> n+"_"+statName.name().toLowerCase()); - anyGauge= (DoubleSummaryGauge) register(labels, () -> new DoubleSummaryGauge(labels,statName,stats)); + .and("name", sanitize(metricFamilyName)) + .modifyValue("name", n -> n + "_" + statName.name().toLowerCase()); + anyGauge = (DoubleSummaryGauge) register(labels, () -> new DoubleSummaryGauge(labels, statName, stats)); } return anyGauge; } + @SuppressWarnings("unchecked") public static Gauge gauge(NBLabeledElement parent, String metricFamilyName, Gauge gauge) { - final NBLabels labels = parent.getLabels().and("name",sanitize(metricFamilyName)); - - return (Gauge) register(labels, () -> new NBMetricGaugeWrapper<>(labels,gauge)); + final NBLabels labels = parent.getLabels().and("name", sanitize(metricFamilyName)); + return (Gauge) register(labels, () -> new NBMetricGaugeWrapper<>(labels, gauge)); } private static MetricRegistry lookupRegistry() { @@ -375,10 +422,11 @@ public class ActivityMetrics { .forEach(get()::remove); } + public static String sanitize(String word) { String sanitized = word; - sanitized = sanitized.replaceAll("\\..+$", ""); - sanitized = sanitized.replaceAll("-","_"); + sanitized = sanitized.replaceAll("\\.", "__"); + sanitized = sanitized.replaceAll("-", "_"); sanitized = sanitized.replaceAll("[^a-zA-Z0-9_]+", ""); if (!word.equals(sanitized)) { diff --git a/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBFunctionGauge.java b/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBFunctionGauge.java index 72841e246..5f5913e68 100644 --- a/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBFunctionGauge.java +++ b/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBFunctionGauge.java @@ -19,6 +19,7 @@ package io.nosqlbench.api.engine.metrics.instruments; import io.nosqlbench.api.labels.NBLabeledElement; import io.nosqlbench.api.labels.NBLabels; +import java.util.Map; import java.util.function.Supplier; public class NBFunctionGauge implements NBMetricGauge { @@ -27,11 +28,14 @@ public class NBFunctionGauge implements NBMetricGauge { private final NBLabeledElement parent; private final NBLabels labels; - public NBFunctionGauge(NBLabeledElement parent, Supplier source, Object... labels) { + public NBFunctionGauge(NBLabeledElement parent, Supplier source, String metricFamilyName, Map additionalLabels) { this.parent = parent; - this.labels = NBLabels.forKV(labels); + this.labels = NBLabels.forMap(additionalLabels).and("name",metricFamilyName); this.source = source; } + public NBFunctionGauge(NBLabeledElement parent, Supplier source, String metricFamilyName) { + this(parent, source, metricFamilyName,Map.of()); + } @Override public Double getValue() { return source.get(); diff --git a/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBLabeledMetric.java b/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBLabeledMetric.java new file mode 100644 index 000000000..62c0caeb0 --- /dev/null +++ b/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBLabeledMetric.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023 nosqlbench + * + * 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 io.nosqlbench.api.engine.metrics.instruments; + +import com.codahale.metrics.Metric; +import io.nosqlbench.api.labels.NBLabeledElement; + +public interface NBLabeledMetric extends Metric, NBLabeledElement { +} diff --git a/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBMetricCounter.java b/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBMetricCounter.java index 809e2207e..5e4013702 100644 --- a/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBMetricCounter.java +++ b/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBMetricCounter.java @@ -17,10 +17,9 @@ package io.nosqlbench.api.engine.metrics.instruments; import com.codahale.metrics.Counter; -import io.nosqlbench.api.labels.NBLabeledElement; import io.nosqlbench.api.labels.NBLabels; -public class NBMetricCounter extends Counter implements NBLabeledElement { +public class NBMetricCounter extends Counter implements NBLabeledMetric { private final NBLabels labels; diff --git a/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBMetricGauge.java b/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBMetricGauge.java index 1d3ebd51c..e9e018e0c 100644 --- a/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBMetricGauge.java +++ b/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBMetricGauge.java @@ -17,8 +17,7 @@ package io.nosqlbench.api.engine.metrics.instruments; import com.codahale.metrics.Gauge; -import io.nosqlbench.api.labels.NBLabeledElement; -public interface NBMetricGauge extends Gauge, NBLabeledElement { +public interface NBMetricGauge extends Gauge, NBLabeledMetric { } diff --git a/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBMetricHistogram.java b/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBMetricHistogram.java index 2247a3c79..f495de6d9 100644 --- a/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBMetricHistogram.java +++ b/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBMetricHistogram.java @@ -17,15 +17,14 @@ package io.nosqlbench.api.engine.metrics.instruments; import com.codahale.metrics.Histogram; -import io.nosqlbench.api.labels.NBLabeledElement; -import io.nosqlbench.api.labels.NBLabels; import io.nosqlbench.api.engine.metrics.*; +import io.nosqlbench.api.labels.NBLabels; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; -public class NBMetricHistogram extends Histogram implements DeltaSnapshotter, HdrDeltaHistogramAttachment, HistogramAttachment, NBLabeledElement { +public class NBMetricHistogram extends Histogram implements DeltaSnapshotter, HdrDeltaHistogramAttachment, HistogramAttachment, NBLabeledMetric { private final DeltaHdrHistogramReservoir hdrDeltaReservoir; private final NBLabels labels; diff --git a/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBMetricMeter.java b/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBMetricMeter.java index a374a889a..3a3afb47c 100644 --- a/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBMetricMeter.java +++ b/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBMetricMeter.java @@ -17,10 +17,9 @@ package io.nosqlbench.api.engine.metrics.instruments; import com.codahale.metrics.Meter; -import io.nosqlbench.api.labels.NBLabeledElement; import io.nosqlbench.api.labels.NBLabels; -public class NBMetricMeter extends Meter implements NBLabeledElement { +public class NBMetricMeter extends Meter implements NBLabeledMetric { private final NBLabels labels; diff --git a/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBMetricTimer.java b/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBMetricTimer.java index 0802c0eb8..bbcd16fe2 100644 --- a/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBMetricTimer.java +++ b/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBMetricTimer.java @@ -17,16 +17,15 @@ package io.nosqlbench.api.engine.metrics.instruments; import com.codahale.metrics.Timer; -import io.nosqlbench.api.labels.NBLabeledElement; -import io.nosqlbench.api.labels.NBLabels; import io.nosqlbench.api.engine.metrics.*; +import io.nosqlbench.api.labels.NBLabels; import org.HdrHistogram.Histogram; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.TimeUnit; -public class NBMetricTimer extends Timer implements DeltaSnapshotter, HdrDeltaHistogramAttachment, TimerAttachment, NBLabeledElement { +public class NBMetricTimer extends Timer implements DeltaSnapshotter, HdrDeltaHistogramAttachment, TimerAttachment, NBLabeledMetric { private final DeltaHdrHistogramReservoir deltaHdrHistogramReservoir; private long cacheExpiry; private List mirrors;