mirror of
https://github.com/nosqlbench/nosqlbench.git
synced 2025-02-25 18:55:28 -06:00
improve rate specs
This commit is contained in:
@@ -18,10 +18,15 @@ package io.nosqlbench.engine.api.activityapi.simrate;
|
|||||||
|
|
||||||
import io.nosqlbench.nb.api.engine.activityimpl.ParameterMap;
|
import io.nosqlbench.nb.api.engine.activityimpl.ParameterMap;
|
||||||
import io.nosqlbench.nb.api.engine.util.Unit;
|
import io.nosqlbench.nb.api.engine.util.Unit;
|
||||||
|
import io.nosqlbench.nb.api.errors.BasicError;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
|
||||||
import java.time.temporal.ChronoUnit;
|
import java.time.temporal.ChronoUnit;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <H2>Rate Limiter Specifications</H2>
|
* <H2>Rate Limiter Specifications</H2>
|
||||||
@@ -127,6 +132,7 @@ public class SimRateSpec {
|
|||||||
public static final double DEFAULT_RATE_OPS_S = 1.0D;
|
public static final double DEFAULT_RATE_OPS_S = 1.0D;
|
||||||
public static final double DEFAULT_BURST_RATIO = 1.1D;
|
public static final double DEFAULT_BURST_RATIO = 1.1D;
|
||||||
public static Verb DEFAULT_VERB = Verb.start;
|
public static Verb DEFAULT_VERB = Verb.start;
|
||||||
|
|
||||||
public enum Scope {
|
public enum Scope {
|
||||||
thread,
|
thread,
|
||||||
activity
|
activity
|
||||||
@@ -162,9 +168,9 @@ public class SimRateSpec {
|
|||||||
// }
|
// }
|
||||||
return switch (unit) {
|
return switch (unit) {
|
||||||
case NANOS -> (int) newNanoTokens;
|
case NANOS -> (int) newNanoTokens;
|
||||||
case MICROS -> (int) (newNanoTokens/1_000L);
|
case MICROS -> (int) (newNanoTokens / 1_000L);
|
||||||
case MILLIS -> (int) (newNanoTokens/1_000_000L);
|
case MILLIS -> (int) (newNanoTokens / 1_000_000L);
|
||||||
case SECONDS -> (int) (newNanoTokens/1_000_000_000L);
|
case SECONDS -> (int) (newNanoTokens / 1_000_000_000L);
|
||||||
default -> throw new RuntimeException("invalid ChronoUnit for nanosToTicks:" + unit);
|
default -> throw new RuntimeException("invalid ChronoUnit for nanosToTicks:" + unit);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -172,9 +178,9 @@ public class SimRateSpec {
|
|||||||
public long ticksToNanos(int newTicks) {
|
public long ticksToNanos(int newTicks) {
|
||||||
return switch (unit) {
|
return switch (unit) {
|
||||||
case NANOS -> newTicks;
|
case NANOS -> newTicks;
|
||||||
case MICROS -> newTicks*1_000L;
|
case MICROS -> newTicks * 1_000L;
|
||||||
case MILLIS -> newTicks*1_000_000L;
|
case MILLIS -> newTicks * 1_000_000L;
|
||||||
case SECONDS -> newTicks*1_000_000_000L;
|
case SECONDS -> newTicks * 1_000_000_000L;
|
||||||
default -> throw new RuntimeException("invalid ChronoUnit for ticksToNanos:" + unit);
|
default -> throw new RuntimeException("invalid ChronoUnit for ticksToNanos:" + unit);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -216,12 +222,15 @@ public class SimRateSpec {
|
|||||||
public SimRateSpec(double opsPerSec, double burstRatio) {
|
public SimRateSpec(double opsPerSec, double burstRatio) {
|
||||||
this(opsPerSec, burstRatio, DEFAULT_VERB);
|
this(opsPerSec, burstRatio, DEFAULT_VERB);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SimRateSpec(double opsPerSec, double burstRatio, Verb verb) {
|
public SimRateSpec(double opsPerSec, double burstRatio, Verb verb) {
|
||||||
apply(opsPerSec, burstRatio, verb, Scope.activity);
|
apply(opsPerSec, burstRatio, verb, Scope.activity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SimRateSpec(double opsPerSec, double burstRatio, Scope scope) {
|
public SimRateSpec(double opsPerSec, double burstRatio, Scope scope) {
|
||||||
apply(opsPerSec, burstRatio, DEFAULT_VERB, scope);
|
apply(opsPerSec, burstRatio, DEFAULT_VERB, scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SimRateSpec(double opsPerSec, double burstRatio, Verb verb, Scope scope) {
|
public SimRateSpec(double opsPerSec, double burstRatio, Verb verb, Scope scope) {
|
||||||
apply(opsPerSec, burstRatio, verb, scope);
|
apply(opsPerSec, burstRatio, verb, scope);
|
||||||
}
|
}
|
||||||
@@ -256,31 +265,57 @@ public class SimRateSpec {
|
|||||||
|
|
||||||
public SimRateSpec(String spec) {
|
public SimRateSpec(String spec) {
|
||||||
String[] specs = spec.split("[,:;]");
|
String[] specs = spec.split("[,:;]");
|
||||||
|
int offset=0;
|
||||||
double opsPerSec;
|
double opsPerSec;
|
||||||
double burstRatio = DEFAULT_BURST_RATIO;
|
double burstRatio = DEFAULT_BURST_RATIO;
|
||||||
Verb verb = Verb.start;
|
Verb verb = Verb.start;
|
||||||
Scope scope = Scope.activity;
|
Scope scope = Scope.activity;
|
||||||
switch (specs.length) {
|
String oprateSpec = specs[offset++];
|
||||||
case 4:
|
opsPerSec = Unit.doubleCountFor(oprateSpec).orElseThrow(() -> new RuntimeException("Unparsable:" + oprateSpec));
|
||||||
scope = Scope.valueOf(specs[3].toLowerCase());
|
if (specs.length >= 2) {
|
||||||
case 3:
|
try {
|
||||||
try {
|
burstRatio = Double.parseDouble(specs[1]);
|
||||||
scope = Scope.valueOf(specs[2].toLowerCase());
|
offset++;
|
||||||
logger.debug("selected rate limiter scope: " + scope);
|
} catch (NumberFormatException ignored) {
|
||||||
} catch (IllegalArgumentException iae) {
|
}
|
||||||
verb = Verb.valueOf(specs[2].toLowerCase());
|
}
|
||||||
logger.debug("selected rate limiter type: " + verb);
|
|
||||||
}
|
for (int i = offset; i < specs.length; i++) {
|
||||||
case 2:
|
String specword = specs[i].toLowerCase();
|
||||||
burstRatio = Double.valueOf(specs[1]);
|
|
||||||
if (burstRatio < 1.0) {
|
try {
|
||||||
throw new RuntimeException("burst ratios less than 1.0 are invalid.");
|
scope = Scope.valueOf(specword);
|
||||||
}
|
specword = null;
|
||||||
case 1:
|
logger.debug("selected rate limiter scope: " + scope);
|
||||||
opsPerSec = Unit.doubleCountFor(specs[0]).orElseThrow(() -> new RuntimeException("Unparsable:" + specs[0]));
|
continue;
|
||||||
break;
|
} catch (IllegalArgumentException ignored) {
|
||||||
default:
|
}
|
||||||
throw new RuntimeException("Rate specs must be either '<rate>' or '<rate>:<burstRatio>' as in 5000.0 or 5000.0:1.0");
|
|
||||||
|
try {
|
||||||
|
verb = Verb.valueOf(specword);
|
||||||
|
specword = null;
|
||||||
|
logger.debug("selected rate limiter type: " + verb);
|
||||||
|
continue;
|
||||||
|
} catch (IllegalArgumentException ignored) {
|
||||||
|
}
|
||||||
|
|
||||||
|
if (specword != null) {
|
||||||
|
String msg = """
|
||||||
|
Spec format 'SPECFORMAT' was not recognized for FORTYPE.
|
||||||
|
Use the format <ops/s>[,<burst ratio][,<verb>][,<scope>]
|
||||||
|
Examples:
|
||||||
|
100 (100 ops per second)
|
||||||
|
100,1.1 (with a burst ratio of 10% over)
|
||||||
|
100,start (start the rate limiter automatically)
|
||||||
|
100,thread (scope the rate limiter to each thread in an activity)
|
||||||
|
100,1.1,start,thread (all of the above)
|
||||||
|
Defaults: burst_ratio=1.1 verb=start scope=activity
|
||||||
|
"""
|
||||||
|
.replaceAll("SPECFORMAT", spec)
|
||||||
|
.replaceAll("FORTYPE", this.getClass().getSimpleName());
|
||||||
|
throw new BasicError(msg);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
apply(opsPerSec, burstRatio, verb, scope);
|
apply(opsPerSec, burstRatio, verb, scope);
|
||||||
}
|
}
|
||||||
@@ -312,6 +347,8 @@ public class SimRateSpec {
|
|||||||
SimRateSpec simRateSpec = (SimRateSpec) o;
|
SimRateSpec simRateSpec = (SimRateSpec) o;
|
||||||
|
|
||||||
if (Double.compare(simRateSpec.opsPerSec, opsPerSec) != 0) return false;
|
if (Double.compare(simRateSpec.opsPerSec, opsPerSec) != 0) return false;
|
||||||
|
if (verb!=simRateSpec.verb) return false;
|
||||||
|
if (scope!=simRateSpec.scope) return false;
|
||||||
return Double.compare(simRateSpec.burstRatio, burstRatio) == 0;
|
return Double.compare(simRateSpec.burstRatio, burstRatio) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -343,5 +380,4 @@ public class SimRateSpec {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,17 +48,31 @@ public class SimRateSpecTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testScopeSelection() {
|
public void testVariantFormats() {
|
||||||
SimRateSpec asd = new SimRateSpec("12345,1.4");
|
assertThat(new SimRateSpec("12345"))
|
||||||
assertThat(asd.getScope()).isEqualTo(SimRateSpec.Scope.activity);
|
.isEqualTo(new SimRateSpec(
|
||||||
SimRateSpec ts = new SimRateSpec("12345,1.4,start,thread");
|
12345.0d, 1.1d, SimRateSpec.Verb.start, SimRateSpec.Scope.activity
|
||||||
assertThat(ts.getScope()).isEqualTo(SimRateSpec.Scope.thread);
|
));
|
||||||
SimRateSpec as = new SimRateSpec("12345,1.4,start,activity");
|
assertThat(new SimRateSpec("12345,1.4"))
|
||||||
assertThat(as.getScope()).isEqualTo(SimRateSpec.Scope.activity);
|
.isEqualTo(new SimRateSpec(
|
||||||
SimRateSpec asa = new SimRateSpec("12345,1.4,activity");
|
12345.0d, 1.4d, SimRateSpec.Verb.start, SimRateSpec.Scope.activity
|
||||||
assertThat(asa.getScope()).isEqualTo(SimRateSpec.Scope.activity);
|
));
|
||||||
SimRateSpec ast = new SimRateSpec("12345,1.4,thread");
|
assertThat(new SimRateSpec("12345,configure"))
|
||||||
assertThat(ast.getScope()).isEqualTo(SimRateSpec.Scope.thread);
|
.isEqualTo(new SimRateSpec(
|
||||||
|
12345.0d, 1.1d, SimRateSpec.Verb.configure, SimRateSpec.Scope.activity
|
||||||
|
));
|
||||||
|
assertThat(new SimRateSpec("12345,thread"))
|
||||||
|
.isEqualTo(new SimRateSpec(
|
||||||
|
12345.0d, 1.1d, SimRateSpec.Verb.start, SimRateSpec.Scope.thread
|
||||||
|
));
|
||||||
|
assertThat(new SimRateSpec("12345,1.4,thread"))
|
||||||
|
.isEqualTo(new SimRateSpec(
|
||||||
|
12345.0d, 1.4d, SimRateSpec.Verb.start, SimRateSpec.Scope.thread
|
||||||
|
));
|
||||||
|
assertThat(new SimRateSpec("12345,configure,activity"))
|
||||||
|
.isEqualTo(new SimRateSpec(
|
||||||
|
12345.0d, 1.1d, SimRateSpec.Verb.configure, SimRateSpec.Scope.activity
|
||||||
|
));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user