replace ActivityDef with NBConfigurable

This commit is contained in:
Jonathan Shook 2025-01-02 12:15:11 -06:00
parent 3ab18635bb
commit 97e7b16d77
61 changed files with 1316 additions and 1373 deletions

View File

@ -70,14 +70,14 @@ public class DiagDriverAdapter extends BaseDriverAdapter<DiagOp, DiagSpace> impl
@Override @Override
public NBConfigModel getConfigModel() { public NBConfigModel getConfigModel() {
NBConfigModel model = super.getConfigModel(); NBConfigModel model = getConfigModel();
model.add(DiagSpace.getConfigModel()); model.add(DiagSpace.getStaticConfigModel());
return model; return model;
} }
@Override @Override
public NBConfigModel getReconfigModel() { public NBConfigModel getReconfigModel() {
NBConfigModel model = super.getReconfigModel(); NBConfigModel model = getReconfigModel();
NBConfigModel mapperModel = NBReconfigurable.collectModels(DiagDriverAdapter.class, List.of(mapper)); NBConfigModel mapperModel = NBReconfigurable.collectModels(DiagDriverAdapter.class, List.of(mapper));
return model.add(mapperModel); return model.add(mapperModel);
} }

View File

@ -20,6 +20,7 @@ import io.nosqlbench.adapter.diag.optasks.DiagTask;
import io.nosqlbench.adapters.api.activityimpl.BaseOpDispenser; import io.nosqlbench.adapters.api.activityimpl.BaseOpDispenser;
import io.nosqlbench.adapters.api.templating.ParsedOp; import io.nosqlbench.adapters.api.templating.ParsedOp;
import io.nosqlbench.nb.api.config.standard.NBConfigModel; import io.nosqlbench.nb.api.config.standard.NBConfigModel;
import io.nosqlbench.nb.api.config.standard.NBConfigurable;
import io.nosqlbench.nb.api.config.standard.NBConfiguration; import io.nosqlbench.nb.api.config.standard.NBConfiguration;
import io.nosqlbench.nb.api.config.standard.NBReconfigurable; import io.nosqlbench.nb.api.config.standard.NBReconfigurable;
import io.nosqlbench.nb.api.components.core.NBParentComponentInjection; import io.nosqlbench.nb.api.components.core.NBParentComponentInjection;
@ -102,6 +103,16 @@ public class DiagOpDispenser extends BaseOpDispenser<DiagOp,DiagSpace> implement
return opFunc.getReconfigModel(); return opFunc.getReconfigModel();
} }
@Override
public void applyConfig(NBConfiguration cfg) {
}
@Override
public NBConfigModel getConfigModel() {
return null;
}
private final static class OpFunc implements LongFunction<DiagOp>, NBReconfigurable { private final static class OpFunc implements LongFunction<DiagOp>, NBReconfigurable {
private final List<DiagTask> tasks; private final List<DiagTask> tasks;
private final LongFunction<DiagSpace> spaceF; private final LongFunction<DiagSpace> spaceF;
@ -126,6 +137,17 @@ public class DiagOpDispenser extends BaseOpDispenser<DiagOp,DiagSpace> implement
public NBConfigModel getReconfigModel() { public NBConfigModel getReconfigModel() {
return NBReconfigurable.collectModels(DiagTask.class, tasks); return NBReconfigurable.collectModels(DiagTask.class, tasks);
} }
@Override
public void applyConfig(NBConfiguration cfg) {
NBConfigurable.applyMatching(cfg, tasks);
}
@Override
public NBConfigModel getConfigModel() {
return NBConfigurable.collectModels(DiagTask.class, tasks);
}
} }
@Override @Override

View File

@ -20,9 +20,7 @@ import io.nosqlbench.adapters.api.activityimpl.OpDispenser;
import io.nosqlbench.adapters.api.activityimpl.OpMapper; import io.nosqlbench.adapters.api.activityimpl.OpMapper;
import io.nosqlbench.adapters.api.templating.ParsedOp; import io.nosqlbench.adapters.api.templating.ParsedOp;
import io.nosqlbench.nb.api.components.core.NBComponent; import io.nosqlbench.nb.api.components.core.NBComponent;
import io.nosqlbench.nb.api.config.standard.NBConfigModel; import io.nosqlbench.nb.api.config.standard.*;
import io.nosqlbench.nb.api.config.standard.NBConfiguration;
import io.nosqlbench.nb.api.config.standard.NBReconfigurable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
@ -32,6 +30,7 @@ import java.util.function.LongFunction;
public class DiagOpMapper implements OpMapper<DiagOp,DiagSpace>, NBReconfigurable { public class DiagOpMapper implements OpMapper<DiagOp,DiagSpace>, NBReconfigurable {
private final Map<String,DiagOpDispenser> dispensers = new LinkedHashMap<>(); private final Map<String,DiagOpDispenser> dispensers = new LinkedHashMap<>();
private final DiagDriverAdapter adapter; private final DiagDriverAdapter adapter;
private NBConfiguration config;
public DiagOpMapper(DiagDriverAdapter adapter) { public DiagOpMapper(DiagDriverAdapter adapter) {
this.adapter = adapter; this.adapter = adapter;
@ -45,6 +44,16 @@ public class DiagOpMapper implements OpMapper<DiagOp,DiagSpace>, NBReconfigurabl
return dispenser; return dispenser;
} }
@Override
public NBConfigModel getConfigModel() {
return ConfigModel.of(DiagOpMapper.class).asReadOnly();
}
@Override
public void applyConfig(NBConfiguration cfg) {
this.config = cfg;
NBConfigurable.applyMatching(cfg, dispensers.values());
}
@Override @Override
public void applyReconfig(NBConfiguration recfg) { public void applyReconfig(NBConfiguration recfg) {

View File

@ -17,17 +17,12 @@
package io.nosqlbench.adapter.diag; package io.nosqlbench.adapter.diag;
import io.nosqlbench.adapters.api.activityimpl.uniform.BaseSpace; import io.nosqlbench.adapters.api.activityimpl.uniform.BaseSpace;
import io.nosqlbench.engine.api.activityapi.core.ActivityDefObserver;
import io.nosqlbench.engine.api.activityapi.simrate.RateLimiter; import io.nosqlbench.engine.api.activityapi.simrate.RateLimiter;
import io.nosqlbench.nb.api.engine.activityimpl.ActivityDef; import io.nosqlbench.nb.api.config.standard.*;
import io.nosqlbench.nb.api.config.standard.ConfigModel;
import io.nosqlbench.nb.api.config.standard.NBConfigModel;
import io.nosqlbench.nb.api.config.standard.NBConfiguration;
import io.nosqlbench.nb.api.config.standard.Param;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
public class DiagSpace extends BaseSpace<DiagSpace> implements ActivityDefObserver { public class DiagSpace extends BaseSpace<DiagSpace> implements NBConfigurable {
private final Logger logger = LogManager.getLogger(DiagSpace.class); private final Logger logger = LogManager.getLogger(DiagSpace.class);
private final NBConfiguration cfg; private final NBConfiguration cfg;
@ -47,7 +42,10 @@ public class DiagSpace extends BaseSpace<DiagSpace> implements ActivityDefObserv
this.errorOnClose = cfg.get("erroronclose",boolean.class); this.errorOnClose = cfg.get("erroronclose",boolean.class);
} }
public static NBConfigModel getConfigModel() { public NBConfigModel getConfigModel() {
return getStaticConfigModel();
}
public static NBConfigModel getStaticConfigModel() {
return ConfigModel.of(DiagSpace.class) return ConfigModel.of(DiagSpace.class)
.add(Param.defaultTo("interval",1000)) .add(Param.defaultTo("interval",1000))
.add(Param.defaultTo("erroronclose", false)) .add(Param.defaultTo("erroronclose", false))
@ -60,11 +58,6 @@ public class DiagSpace extends BaseSpace<DiagSpace> implements ActivityDefObserv
} }
} }
@Override
public void onActivityDefUpdate(ActivityDef activityDef) {
NBConfiguration cfg = getConfigModel().apply(activityDef.getParams().getStringStringMap());
this.applyConfig(cfg);
}
@Override @Override
public void close() throws Exception { public void close() throws Exception {
@ -73,4 +66,5 @@ public class DiagSpace extends BaseSpace<DiagSpace> implements ActivityDefObserv
throw new RuntimeException("diag space was configured to throw this error when it was configured."); throw new RuntimeException("diag space was configured to throw this error when it was configured.");
} }
} }
} }

View File

@ -144,55 +144,6 @@ public abstract class BaseDriverAdapter<RESULT
return cfg; return cfg;
} }
@Override
public void applyConfig(NBConfiguration cfg) {
this.cfg = cfg;
}
@Override
public void applyReconfig(NBConfiguration reconf) {
this.cfg = getReconfigModel().apply(reconf.getMap());
}
/**
* In order to be provided with config information, it is required
* that the driver adapter specify the valid configuration options,
* their types, and so on.
*/
@Override
public NBConfigModel getConfigModel() {
return ConfigModel.of(BaseDriverAdapter.class)
.add(Param.optional("alias"))
.add(Param.optional("labels", String.class, "Labels which will apply to metrics and annotations for this activity only"))
.add(Param.defaultTo("strict", true, "strict op field mode, which requires that provided op fields are recognized and used"))
.add(Param.optional(List.of("op", "stmt", "statement"), String.class, "op template in statement form"))
.add(Param.optional("tags", String.class, "tags to be used to filter operations"))
.add(Param.defaultTo("errors", "stop", "error handler configuration"))
.add(Param.optional("threads").setRegex("\\d+|\\d+x|auto").setDescription("number of concurrent operations, controlled by threadpool"))
.add(Param.optional("stride").setRegex("\\d+"))
.add(Param.optional("striderate", String.class, "rate limit for strides per second"))
.add(Param.optional("cycles").setRegex("\\d+[KMBGTPE]?|\\d+[KMBGTPE]?\\.\\.\\d+[KMBGTPE]?").setDescription("cycle interval to use"))
.add(Param.optional("recycles").setDescription("allow cycles to be re-used this many times"))
.add(Param.optional(List.of("cyclerate", "targetrate", "rate"), String.class, "rate limit for cycles per second"))
.add(Param.optional("seq", String.class, "sequencing algorithm"))
.add(Param.optional("instrument", Boolean.class))
.add(Param.optional(List.of("workload", "yaml"), String.class, "location of workload yaml file"))
.add(Param.optional("driver", String.class))
.add(Param.defaultTo("dryrun", "none").setRegex("(op|jsonnet|emit|none)"))
.add(Param.optional("maxtries", Integer.class))
.asReadOnly();
}
@Override
public NBConfigModel getReconfigModel() {
return ConfigModel.of(BaseDriverAdapter.class)
.add(Param.optional("threads").setRegex("\\d+|\\d+x|auto").setDescription("number of concurrent operations, controlled by threadpool"))
.add(Param.optional("striderate", String.class, "rate limit for strides per second"))
.add(Param.optional(List.of("cyclerate", "targetrate", "rate"), String.class, "rate limit for cycles per second"))
.asReadOnly();
}
@Override @Override
public LongFunction<SPACE> getSpaceFunc(ParsedOp pop) { public LongFunction<SPACE> getSpaceFunc(ParsedOp pop) {
@ -233,4 +184,30 @@ public abstract class BaseDriverAdapter<RESULT
} }
super.beforeDetach(); super.beforeDetach();
} }
@Override
public void applyConfig(NBConfiguration cfg) {
this.cfg = cfg;
}
@Override
public void applyReconfig(NBConfiguration reconf) {
this.cfg = getReconfigModel().apply(reconf.getMap());
}
/// These are implemented here as _unit_ values, meaning, you shouldn't be asking
/// "Does this element have a configuration model", but instead you should be asking
/// "What is the (possibly empty?) configuration model of this element?"
@Override
public NBConfigModel getConfigModel() {
return ConfigModel.of(BaseDriverAdapter.class).asReadOnly();
}
/// These are implemented here as _unit_ values, meaning, you shouldn't be asking
/// "Does this element have a reconfiguration model", but instead you should be asking
/// "What is the (possibly empty?) reconfiguration model of this element?"
@Override
public NBConfigModel getReconfigModel() {
return ConfigModel.of(BaseDriverAdapter.class).asReadOnly();
}
} }

View File

@ -394,28 +394,24 @@ public class ParsedOp extends NBBaseComponent implements LongFunction<Map<String
private final List<CapturePoint> captures = new ArrayList<>(); private final List<CapturePoint> captures = new ArrayList<>();
private final OpTemplate _opTemplate; private final OpTemplate _opTemplate;
private final NBConfiguration activityCfg; private final Map<String,Object> activityCfg;
private final ParsedTemplateMap tmap; private final ParsedTemplateMap tmap;
private final NBLabels labels; private final NBLabels labels;
private final List<Function<Map<String, Object>, Map<String, Object>>> preprocessors; private final List<Function<Map<String, Object>, Map<String, Object>>> preprocessors;
/** public ParsedOp(ParsedOp pop, NBConfiguration config) {
Create a parsed command from an Op template. This version is exactly like this(pop._opTemplate,new LinkedHashMap<>(pop.activityCfg) {{ this.putAll(config.getMap());}},List.of(),pop.parent);
except that it allows }
preprocessors. Preprocessors are all applied to the the op template before /// Create a parsed command from an Op template. Preprocessors are all applied to the the op template before
it is applied to the parsed command fields, allowing you to combine or destructure /// it is applied to the parsed command fields, allowing you to combine or destructure
fields from more tha one representation into a single canonical representation /// fields from more tha one representation into a single canonical representation
for processing. /// for processing.
@param opTemplate /// @param opTemplate The OpTemplate as provided by a user via YAML, JSON, or API (data structure)
The OpTemplate as provided by a user via YAML, JSON, or API (data structure) /// @param activityCfg The activity configuration, used to resolve nested config parameters
@param activityCfg /// @param preprocessors Map->Map transformers.
The activity configuration, used to resolve nested config parameters
@param preprocessors
Map->Map transformers.
*/
public ParsedOp( public ParsedOp(
OpTemplate opTemplate, NBConfiguration activityCfg, OpTemplate opTemplate,
Map<String,Object> activityCfg,
List<Function<Map<String, Object>, Map<String, Object>>> preprocessors, List<Function<Map<String, Object>, Map<String, Object>>> preprocessors,
NBComponent parent NBComponent parent
) { ) {
@ -439,7 +435,7 @@ public class ParsedOp extends NBBaseComponent implements LongFunction<Map<String
this.tmap = new ParsedTemplateMap( this.tmap = new ParsedTemplateMap(
getName(), map, opTemplate.getBindings(), getName(), map, opTemplate.getBindings(),
List.of(opTemplate.getParams(), activityCfg.getMap()) List.of(opTemplate.getParams(), activityCfg)
); );
NBLabels opLabels = parent.getLabels().and( NBLabels opLabels = parent.getLabels().and(

View File

@ -20,7 +20,7 @@ import com.google.gson.Gson;
import io.nosqlbench.nb.api.advisor.NBAdvisorBuilder; import io.nosqlbench.nb.api.advisor.NBAdvisorBuilder;
import io.nosqlbench.nb.api.advisor.NBAdvisorPoint; import io.nosqlbench.nb.api.advisor.NBAdvisorPoint;
import io.nosqlbench.nb.api.advisor.conditions.Conditions; import io.nosqlbench.nb.api.advisor.conditions.Conditions;
import io.nosqlbench.nb.api.engine.activityimpl.ActivityDef; import io.nosqlbench.nb.api.config.standard.NBConfiguration;
import io.nosqlbench.nb.api.errors.OpConfigError; import io.nosqlbench.nb.api.errors.OpConfigError;
import io.nosqlbench.nb.api.nbio.Content; import io.nosqlbench.nb.api.nbio.Content;
import io.nosqlbench.nb.api.nbio.NBIO; import io.nosqlbench.nb.api.nbio.NBIO;
@ -53,9 +53,9 @@ public class StrInterpolator implements Function<String, String> {
private final Pattern COMMENT = Pattern.compile("^\\s*#.*"); private final Pattern COMMENT = Pattern.compile("^\\s*#.*");
private final Pattern INSERT = Pattern.compile("^(\\s*)INSERT:\\s+(.+)$"); private final Pattern INSERT = Pattern.compile("^(\\s*)INSERT:\\s+(.+)$");
public StrInterpolator(ActivityDef... activityDefs) { public StrInterpolator(NBConfiguration... activityDefs) {
Arrays.stream(activityDefs) Arrays.stream(activityDefs)
.map(ad -> ad.getParams().getStringStringMap()) .map(ad -> ad.getMap())
.forEach(multimap::add); .forEach(multimap::add);
} }

View File

@ -37,39 +37,27 @@ import static org.assertj.core.api.Assertions.assertThat;
public class ParsedOpTest { public class ParsedOpTest {
private NBComponent getParent() { private NBComponent getParent() {
return new TestComponent("opparent","opparent"); return new TestComponent("opparent", "opparent");
} }
private ParsedOp getOp() { private ParsedOp getOp() {
ParsedOp pc = new ParsedOp( OpData opTemplate = new OpData().applyFields(Map.of(
new OpData().applyFields( "op", Map.of(
Map.of( "stmt", "test", "dyna1", "{dyna1}", "dyna2", "{{NumberNameToString()}}", "identity",
"op", Map.of( "{{Identity()}}"), "bindings", Map.of("dyna1", "NumberNameToString()")));
"stmt", "test",
"dyna1", "{dyna1}", NBConfiguration nbcfg = ConfigModel.of(ParsedOpTest.class)
"dyna2", "{{NumberNameToString()}}", .add(Param.defaultTo("testcfg", "testval")).asReadOnly().apply(Map.of());
"identity", "{{Identity()}}"
), ParsedOp pc = new ParsedOp(opTemplate, nbcfg.getMap(), List.of(), getParent());
"bindings", Map.of(
"dyna1", "NumberNameToString()"
)
)
),
ConfigModel.of(ParsedOpTest.class)
.add(Param.defaultTo("testcfg", "testval"))
.asReadOnly()
.apply(Map.of()),
List.of(),
getParent()
);
return pc; return pc;
} }
@Test @Test
public void testFieldDelegationFromDynamicToStaticToConfig() { public void testFieldDelegationFromDynamicToStaticToConfig() {
final NBConfiguration cfg = ConfigModel.of(ParsedOpTest.class) final NBConfiguration cfg = ConfigModel.of(ParsedOpTest.class)
.add(Param.defaultTo("puppy", "dog")) .add(Param.defaultTo("puppy", "dog")).add(Param.required("surname", String.class))
.add(Param.required("surname", String.class))
.asReadOnly().apply(Map.of("surname", "yes")); .asReadOnly().apply(Map.of("surname", "yes"));
final String opt = """ final String opt = """
@ -80,10 +68,11 @@ public class ParsedOpTest {
params: params:
ps1: "param-one" ps1: "param-one"
"""; """;
final OpsDocList stmtsDocs = OpsLoader.loadString(opt, OpTemplateFormat.yaml, cfg.getMap(), null); final OpsDocList stmtsDocs = OpsLoader.loadString(
assertThat(stmtsDocs.getOps().matching("",true).size()).isEqualTo(1); opt, OpTemplateFormat.yaml, cfg.getMap(), null);
final OpTemplate opTemplate = stmtsDocs.getOps().matching("",true).get(0); assertThat(stmtsDocs.getOps().matching("", true).size()).isEqualTo(1);
final ParsedOp parsedOp = new ParsedOp(opTemplate, cfg, List.of(), getParent()); final OpTemplate opTemplate = stmtsDocs.getOps().matching("", true).get(0);
final ParsedOp parsedOp = new ParsedOp(opTemplate, cfg.getMap(), List.of(), getParent());
assertThat(parsedOp.getAsFunctionOr("d1", "invalid").apply(1L)).isEqualTo("one"); assertThat(parsedOp.getAsFunctionOr("d1", "invalid").apply(1L)).isEqualTo("one");
assertThat(parsedOp.getAsFunctionOr("s1", "invalid").apply(1L)).isEqualTo("static-one"); assertThat(parsedOp.getAsFunctionOr("s1", "invalid").apply(1L)).isEqualTo("static-one");
@ -104,31 +93,20 @@ public class ParsedOpTest {
final ParsedOp parsedOp = new ParsedOp( final ParsedOp parsedOp = new ParsedOp(
new OpData().applyFields(Map.of( new OpData().applyFields(Map.of(
"op", Map.of( "op", Map.of(
"field1-literal", "literalvalue1", "field1-literal", "literalvalue1", "field2-object", "{{NumberNameToString()}}",
"field2-object", "{{NumberNameToString()}}", "field3-template", "pre-{dyna1}-post", "field4-map-template",
"field3-template", "pre-{dyna1}-post", Map.of("subfield1-object", "{{Identity(); ToString()}}"), "field5-map-literal",
"field4-map-template", Map.of( Map.of("subfield2-literal", "LiteralValue")), "bindings",
"subfield1-object", "{{Identity(); ToString()}}" Map.of("dyna1", "NumberNameToString()"))),
), "field5-map-literal", Map.of( ConfigModel.of(ParsedOpTest.class).add(Param.defaultTo("testcfg", "testval"))
"subfield2-literal", "LiteralValue" .asReadOnly().apply(Map.of()).getMap(), List.of(), getParent());
)
),
"bindings", Map.of(
"dyna1", "NumberNameToString()"
))
),
ConfigModel.of(ParsedOpTest.class)
.add(Param.defaultTo("testcfg", "testval"))
.asReadOnly()
.apply(Map.of()),
List.of(),
getParent()
);
final LongFunction<? extends String> f1 = parsedOp.getAsRequiredFunction("field1-literal"); final LongFunction<? extends String> f1 = parsedOp.getAsRequiredFunction("field1-literal");
final LongFunction<? extends String> f2 = parsedOp.getAsRequiredFunction("field2-object"); final LongFunction<? extends String> f2 = parsedOp.getAsRequiredFunction("field2-object");
final LongFunction<? extends String> f3 = parsedOp.getAsRequiredFunction("field3-template"); final LongFunction<? extends String> f3 = parsedOp.getAsRequiredFunction("field3-template");
final LongFunction<? extends Map> f4 = parsedOp.getAsRequiredFunction("field4-map-template", Map.class); final LongFunction<? extends Map> f4 = parsedOp.getAsRequiredFunction(
final LongFunction<? extends Map> f5 = parsedOp.getAsRequiredFunction("field5-map-literal", Map.class); "field4-map-template", Map.class);
final LongFunction<? extends Map> f5 = parsedOp.getAsRequiredFunction(
"field5-map-literal", Map.class);
assertThat(f1.apply(1)).isNotNull(); assertThat(f1.apply(1)).isNotNull();
assertThat(f2.apply(2)).isNotNull(); assertThat(f2.apply(2)).isNotNull();
assertThat(f3.apply(3)).isNotNull(); assertThat(f3.apply(3)).isNotNull();
@ -148,21 +126,25 @@ public class ParsedOpTest {
@Test @Test
public void testNewListBinder() { public void testNewListBinder() {
final LongFunction<List<Object>> lb = getOp().newListBinder("dyna1", "identity", "dyna2", "identity"); final LongFunction<List<Object>> lb = getOp().newListBinder(
"dyna1", "identity", "dyna2", "identity");
final List<Object> objects = lb.apply(1); final List<Object> objects = lb.apply(1);
assertThat(objects).isEqualTo(List.of("one", 1L, "one", 1L)); assertThat(objects).isEqualTo(List.of("one", 1L, "one", 1L));
} }
@Test @Test
public void testNewMapBinder() { public void testNewMapBinder() {
final LongFunction<Map<String, Object>> mb = getOp().newOrderedMapBinder("dyna1", "identity", "dyna2"); final LongFunction<Map<String, Object>> mb = getOp().newOrderedMapBinder(
"dyna1", "identity", "dyna2");
final Map<String, Object> objects = mb.apply(2); final Map<String, Object> objects = mb.apply(2);
assertThat(objects).isEqualTo(Map.<String, Object>of("dyna1", "two", "identity", 2L, "dyna2", "two")); assertThat(objects).isEqualTo(
Map.<String, Object>of("dyna1", "two", "identity", 2L, "dyna2", "two"));
} }
@Test @Test
public void testNewAryBinder() { public void testNewAryBinder() {
final LongFunction<Object[]> ab = getOp().newArrayBinder("dyna1", "dyna1", "identity", "identity"); final LongFunction<Object[]> ab = getOp().newArrayBinder(
"dyna1", "dyna1", "identity", "identity");
final Object[] objects = ab.apply(3); final Object[] objects = ab.apply(3);
assertThat(objects).isEqualTo(new Object[]{"three", "three", 3L, 3L}); assertThat(objects).isEqualTo(new Object[]{"three", "three", 3L, 3L});
} }
@ -170,45 +152,21 @@ public class ParsedOpTest {
@Test @Test
public void testLayeredListBinder() { public void testLayeredListBinder() {
ParsedOp pc = new ParsedOp( ParsedOp pc = new ParsedOp(
new OpData().applyFields( new OpData().applyFields(Map.of(
Map.of( "op", Map.of(
"op", Map.of( "alist",
"alist", List.of( List.of(
List.of( List.of("item1", "item2-{dyna1}"),
"item1", Map.of("akey", "avalue", "akey2", "a {dyna1} value2"))), "bindings",
"item2-{dyna1}" Map.of("dyna1", "NumberNameToString()"))),
), ConfigModel.of(ParsedOpTest.class).add(Param.defaultTo("testcfg", "testval"))
Map.of( .asReadOnly().apply(Map.of()).getMap(), List.of(), getParent());
"akey", "avalue",
"akey2", "a {dyna1} value2"
)
)
),
"bindings", Map.of(
"dyna1", "NumberNameToString()"
)
)
),
ConfigModel.of(ParsedOpTest.class)
.add(Param.defaultTo("testcfg", "testval"))
.asReadOnly()
.apply(Map.of()),
List.of(),
getParent()
);
Map<String, Object> result = pc.getTemplateMap().apply(1); Map<String, Object> result = pc.getTemplateMap().apply(1);
assertThat(result).isEqualTo( assertThat(result).isEqualTo(Map.of(
Map.of( "alist", List.of(
"alist", List.of( List.of("item1", "item2-one"),
List.of("item1", "item2-one"), Map.of("akey", "avalue", "akey2", "a one value2"))));
Map.of(
"akey", "avalue",
"akey2", "a one value2"
)
)
)
);
} }

View File

@ -18,6 +18,7 @@ package io.nosqlbench.nb.api.config.standard;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.List;
/** /**
* All implementation types which wish to have a type-marshalled configuration * All implementation types which wish to have a type-marshalled configuration
@ -65,6 +66,15 @@ public interface NBConfigurable extends NBCanConfigure, NBConfigModelProvider {
} }
} }
static void applyMatchingCollection(NBConfiguration cfg, Collection<?> configurables) {
for (Object configurable : configurables) {
if (configurable instanceof NBConfigurable c) {
NBConfiguration partial = c.getConfigModel().matchConfig(cfg);
c.applyConfig(partial);
}
}
}
static NBConfigModel collectModels(Class<?> of, Collection<?> configurables) { static NBConfigModel collectModels(Class<?> of, Collection<?> configurables) {
ConfigModel model = ConfigModel.of(of); ConfigModel model = ConfigModel.of(of);
for (Object configurable : configurables) { for (Object configurable : configurables) {

View File

@ -18,25 +18,22 @@ package io.nosqlbench.nb.api.config.standard;
import io.nosqlbench.nb.api.system.NBEnvironment; import io.nosqlbench.nb.api.system.NBEnvironment;
import java.util.Arrays; import java.util.*;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;
public class NBConfiguration { public class NBConfiguration {
private final LinkedHashMap<String, Object> data; private final LinkedHashMap<String, Object> data;
private final NBConfigModel model; private final NBConfigModel model;
private final List<NBReconfigurable> listeners = new ArrayList<>();
/** /**
* Create a NBConfigReader from a known valid configuration and a config model. Create a NBConfigReader from a known valid configuration and a config model.
* This method is restricted to encourage construction of readers only by passing This method is restricted to encourage construction of readers only by passing
* through the friendly {@link NBConfigModel#apply(Map)} method. through the friendly {@link NBConfigModel#apply(Map)} method.
* @param model
* @param model A configuration model, describing what is allowed to be configured by name and type.
* A configuration model, describing what is allowed to be configured by name and type. @param validConfig
* @param validConfig A valid config reader.
* A valid config reader.
*/ */
protected NBConfiguration(NBConfigModel model, LinkedHashMap<String, Object> validConfig) { protected NBConfiguration(NBConfigModel model, LinkedHashMap<String, Object> validConfig) {
this.data = validConfig; this.data = validConfig;
@ -48,16 +45,17 @@ public class NBConfiguration {
} }
public static NBConfiguration empty() { public static NBConfiguration empty() {
return new NBConfiguration(ConfigModel.of(Object.class).asReadOnly(), new LinkedHashMap<>()); return new NBConfiguration(
ConfigModel.of(Object.class).asReadOnly(),
new LinkedHashMap<>());
} }
/** /**
* Returns the value of the named parameter as {@link #getOptional(String)}, so long Returns the value of the named parameter as {@link #getOptional(String)}, so long
* as no env vars were reference OR all env var references were found. as no env vars were reference OR all env var references were found.
* @param name
* @param name The name of the variable to look up
* The name of the variable to look up @return An optional value, if present and (optionally) interpolated correctly from the environment
* @return An optional value, if present and (optionally) interpolated correctly from the environment
*/ */
public Optional<String> getEnvOptional(String name) { public Optional<String> getEnvOptional(String name) {
Optional<String> optionalValue = getOptional(name); Optional<String> optionalValue = getOptional(name);
@ -84,44 +82,56 @@ public class NBConfiguration {
if (value instanceof String) { if (value instanceof String) {
Optional<String> interpolated = NBEnvironment.INSTANCE.interpolate(value.toString()); Optional<String> interpolated = NBEnvironment.INSTANCE.interpolate(value.toString());
if (interpolated.isEmpty()) { if (interpolated.isEmpty()) {
throw new NBConfigError("Unable to interpolate env and sys props in '" + value + "'"); throw new NBConfigError("Unable to interpolate env and sys props in '" +
value +
"'");
} }
String result = interpolated.get(); String result = interpolated.get();
return ConfigModel.convertValueTo(this.getClass().getSimpleName(), name, result, vclass); return ConfigModel.convertValueTo(
this.getClass().getSimpleName(),
name,
result,
vclass);
} else { } else {
return value; return value;
} }
} }
/** /**
* Get a config value or object by name. This uses type inference (as a generic method) Get a config value or object by name. This uses type inference (as a generic method)
* in addition to the internal model for type checking and ergonomic use. If you do not in addition to the internal model for type checking and ergonomic use. If you do not
* call this within an assignment or context where the Java compiler knows what type you call this within an assignment or context where the Java compiler knows what type you
* are expecting, then use {@link #get(String, Class)} instead. are expecting, then use {@link #get(String, Class)} instead.
* @param name
* @param name The name of the configuration parameter
* The name of the configuration parameter @param <T>
* @param <T> The (inferred) generic type of the configuration value
* The (inferred) generic type of the configuration value @return The value of type T, matching the config model type for the provided field name
* @return The value of type T, matching the config model type for the provided field name
*/ */
public <T> T get(String name) { public <T> T get(String name) {
Param<T> param = (Param<T>) model.getNamedParams().get(name); Param<T> param = (Param<T>) model.getNamedParams().get(name);
if (param == null) { if (param == null) {
throw new NBConfigError("Attempted to get parameter for name '" + name + "' but this parameter has no " + throw new NBConfigError("Attempted to get parameter for name '" +
"model defined for " + this.getModel().getOf()); name +
"' but this parameter has no " +
"model defined for " +
this.getModel().getOf());
} }
// if (param.isRequired() && (param.getDefaultValue()==null) && ) // if (param.isRequired() && (param.getDefaultValue()==null) && )
Object object = this.data.get(name); Object object = this.data.get(name);
object = object != null ? object : param.getDefaultValue(); object = object != null ? object : param.getDefaultValue();
if (object == null && param.isRequired()) { if (object == null && param.isRequired()) {
throw new NBConfigError("An object by name '" + name + "' was requested as required, and no value was" + throw new NBConfigError("An object by name '" +
" defined for it. This user provided value must be set or otherwise marked optional or given a" + name +
" default value in the parameter model."); "' was requested as required, and no value was" +
" defined for it. This user provided value must be set or otherwise marked optional or given a" +
" default value in the parameter model.");
} else if (object == null && !param.isRequired()) { } else if (object == null && !param.isRequired()) {
throw new NBConfigError("An object by name '" + name + "' was requested as given by the config layer," + throw new NBConfigError("An object by name '" +
" but no value was present, and no default was found in the config model. This is an ambiguous " + name +
"scenario. Either access the object as optional, or give it a default value. (code change)"); "' was requested as given by the config layer," +
" but no value was present, and no default was found in the config model. This is an ambiguous " +
"scenario. Either access the object as optional, or give it a default value. (code change)");
} }
if (param.type.isInstance(object)) { if (param.type.isInstance(object)) {
return (T) object; return (T) object;
@ -130,7 +140,14 @@ public class NBConfiguration {
} else if (NBTypeConverter.canConvert(object, param.type)) { } else if (NBTypeConverter.canConvert(object, param.type)) {
return NBTypeConverter.convert(object, param.type); return NBTypeConverter.convert(object, param.type);
} else { } else {
throw new NBConfigError("Unable to assign config value for field '" + name + "' of type '" + object.getClass().getCanonicalName() + "' to the required return type '" + param.type.getCanonicalName() + "' as specified in the config model for '" + model.getOf().getCanonicalName()); throw new NBConfigError("Unable to assign config value for field '" +
name +
"' of type '" +
object.getClass().getCanonicalName() +
"' to the required return type '" +
param.type.getCanonicalName() +
"' as specified in the config model for '" +
model.getOf().getCanonicalName());
} }
} }
@ -138,12 +155,20 @@ public class NBConfiguration {
Param<T> param = model.getParam(name); Param<T> param = model.getParam(name);
if (param == null) { if (param == null) {
throw new NBConfigError("Parameter named '" + name + "' is not valid for " + model.getOf().getSimpleName() + "."); throw new NBConfigError("Parameter named '" +
name +
"' is not valid for " +
model.getOf().getSimpleName() +
".");
} }
if ((!param.isRequired()) && param.getDefaultValue() == null) { if ((!param.isRequired()) && param.getDefaultValue() == null) {
throw new RuntimeException("Non-optional get on optional parameter " + name + "' which has no default value while configuring " + model.getOf() + "." + throw new RuntimeException("Non-optional get on optional parameter " +
"\nTo avoid user impact, ensure that ConfigModel and NBConfigurable usage are aligned."); name +
"' which has no default value while configuring " +
model.getOf() +
"." +
"\nTo avoid user impact, ensure that ConfigModel and NBConfigurable usage are aligned.");
} }
Object o = data.get(name); Object o = data.get(name);
@ -178,7 +203,9 @@ public class NBConfiguration {
} }
} }
} else { } else {
throw new NBConfigError("Parameter definition was not found for " + Arrays.toString(names) + "."); throw new NBConfigError("Parameter definition was not found for " +
Arrays.toString(names) +
".");
} }
} }
if (o == null) { if (o == null) {
@ -195,7 +222,11 @@ public class NBConfiguration {
} else if (NBTypeConverter.canConvert(o, type)) { } else if (NBTypeConverter.canConvert(o, type)) {
return Optional.of((T) NBTypeConverter.convert(o, type)); return Optional.of((T) NBTypeConverter.convert(o, type));
} else { } else {
throw new NBConfigError("config param " + Arrays.toString(names) + " was not assignable to class '" + type.getCanonicalName() + "'"); throw new NBConfigError("config param " +
Arrays.toString(names) +
" was not assignable to class '" +
type.getCanonicalName() +
"'");
} }
} }
@ -208,7 +239,11 @@ public class NBConfiguration {
if (defaultValue.getClass().isAssignableFrom(o.getClass())) { if (defaultValue.getClass().isAssignableFrom(o.getClass())) {
return (T) o; return (T) o;
} }
throw new NBConfigError("config parameter '" + name + "' is not assignable to required type '" + defaultValue.getClass() + "'"); throw new NBConfigError("config parameter '" +
name +
"' is not assignable to required type '" +
defaultValue.getClass() +
"'");
} }
public <T> T param(String name, Class<? extends T> vclass) { public <T> T param(String name, Class<? extends T> vclass) {
@ -238,4 +273,36 @@ public class NBConfiguration {
return data; return data;
} }
/// see [#update(Map)]
public <T> NBConfiguration update(String fieldName, T value) {
return update(Map.of(fieldName,value));
}
/// This will create a new configuration without modifying the existing one,
/// retaining the same config model and all other values except for the modified ones.
/// Further, any reconfig listeners which are registered will be notified via the
/// [NBReconfigurable#applyConfig(NBConfiguration)] method
///
/// This eventing will occur whether or not the value was actually changed. Spurious
/// evenging of duplicate values should be considered an design bug.
///
/// Any holders of an updated configurations must maintain their own copies if necessary for
/// deltas.
public <T> NBConfiguration update(Map<String,Object> entries) {
NBConfiguration updated = model.apply(new LinkedHashMap<>(this.data) {
{
putAll(entries);
}
});
for (NBReconfigurable listener : this.listeners) {
listener.applyReconfig(updated);
}
return updated;
}
public NBConfiguration addListener(NBReconfigurable reconfigurable) {
this.listeners.add(reconfigurable);
return this;
}
} }

View File

@ -39,7 +39,7 @@ import java.util.Collection;
* {@link #applyMatching(NBConfiguration, Collection)} can be used to apply * {@link #applyMatching(NBConfiguration, Collection)} can be used to apply
* reconfigurations to groups of elements with a shared configuration model. * reconfigurations to groups of elements with a shared configuration model.
*/ */
public interface NBReconfigurable extends NBCanReconfigure, NBReconfigModelProvider { public interface NBReconfigurable extends NBConfigurable, NBCanReconfigure, NBReconfigModelProvider {
/** /**
* This applies a configuration to an element <EM>AFTER</EM> the initial * This applies a configuration to an element <EM>AFTER</EM> the initial

View File

@ -0,0 +1,113 @@
package io.nosqlbench.nb.api.engine.activityimpl;
/*
* Copyright (c) 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.
*/
import io.nosqlbench.nb.api.config.standard.NBConfigModel;
import io.nosqlbench.nb.api.config.standard.NBConfiguration;
import io.nosqlbench.nb.api.labels.NBLabelSpec;
import io.nosqlbench.nb.api.labels.NBLabels;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.LinkedHashMap;
import java.util.Optional;
public class ActivityConfig extends NBConfiguration {
public static final String DEFAULT_ALIAS = "UNNAMEDACTIVITY";
public static final String DEFAULT_ATYPE = "stdout";
public static final String DEFAULT_CYCLES = "0";
public static final String DEFAULT_RECYCLES = "1";
public static final int DEFAULT_THREADS = 1;
public static final Logger logger = LogManager.getLogger(ActivityConfig.class);
// an alias with which to control the activity while it is running
public static final String FIELD_ALIAS = "alias";
// a file or URL containing the activity: op templates, generator bindings, ...
public static final String FIELD_ATYPE = "type";
// cycles for this activity in either "M" or "N..M" form. "M" form implies "0..M"
public static final String FIELD_CYCLES = "cycles";
public static final String FIELD_RECYCLES = "recycles";
// initial thread concurrency for this activity
public static final String FIELD_THREADS = "threads";
public static final String FIELD_LABELS = "labels";
public static final String[] field_list = {
FIELD_ALIAS, FIELD_ATYPE, FIELD_CYCLES, FIELD_THREADS, FIELD_RECYCLES
};
public ActivityConfig(NBConfiguration config) {
this(config.getModel(), config.getMap());
}
public ActivityConfig(NBConfigModel model, LinkedHashMap<String, Object> validConfig)
{
super(model, validConfig);
Optional<String> directAlias = getOptional("alias");
if (!directAlias.isPresent()) {
String indirectAlias = getOptional(ActivityConfig.FIELD_ALIAS).or(
() -> getOptional("workload")).or(() -> getOptional("driver"))
.orElse("ACTIVITYNAME");
getMap().put("alias", indirectAlias);
}
}
public String getAlias() {
return get("alias");
}
public NBLabels auxLabels() {
Optional<String> auxLabelSpec = getOptional(FIELD_LABELS);
if (auxLabelSpec.isPresent()) {
return NBLabelSpec.parseLabels(auxLabelSpec.get());
}
return NBLabels.forKV();
}
public Optional<String> getDriver() {
return getOptional("driver", "type");
// .orElseThrow(() -> new BasicError("The parameter " +
// "'driver=' is required."));
}
public void setThreads(int i) {
update("threads", i);
}
public int getThreads() {
return get(FIELD_THREADS, Integer.class);
}
public String summary() {
return String.valueOf(this);
}
public void updateLastCycle(long maxValue) {
CyclesSpec spec = CyclesSpec.parse(get("cycles", String.class));
spec = spec.withLast(maxValue);
update("cycles", spec.toString());
}
public CyclesSpec getCyclesSpec() {
return CyclesSpec.parse(get("cycles", String.class));
}
}

View File

@ -1,263 +0,0 @@
/*
* Copyright (c) 2022-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.nb.api.engine.activityimpl;
import io.nosqlbench.nb.api.components.core.NBNamedElement;
import io.nosqlbench.nb.api.config.standard.ConfigModel;
import io.nosqlbench.nb.api.config.standard.NBConfigModel;
import io.nosqlbench.nb.api.config.standard.Param;
import io.nosqlbench.nb.api.errors.BasicError;
import io.nosqlbench.nb.api.labels.NBLabelSpec;
import io.nosqlbench.nb.api.labels.NBLabels;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.security.InvalidParameterException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicLong;
/**
* <p>A runtime definition for an activity.</p>
* <p>Instances of ActivityDef hold control values for the execution of a single activity.
* Each thread of the related activity is initialized with the associated ActivityDef.
* When the ActivityDef is modified, interested activity threads are notified so that
* they can dynamically adjust.</p>
* <p>The canonical values for all parameters are kept internally in the parameter map.
* Essentially, ActivityDef is just a type-aware wrapper around a thread-safe parameter map,
* with an atomic change counter which can be used to signal changes to observers.</p>
*/
public class ActivityDef implements NBNamedElement {
// milliseconds between cycles per thread, for slow tests only
public static final String DEFAULT_ALIAS = "UNNAMEDACTIVITY";
public static final String DEFAULT_ATYPE = "stdout";
public static final String DEFAULT_CYCLES = "0";
public static final String DEFAULT_RECYCLES = "1";
public static final int DEFAULT_THREADS = 1;
public static final Logger logger = LogManager.getLogger(ActivityDef.class);
// an alias with which to control the activity while it is running
public static final String FIELD_ALIAS = "alias";
// a file or URL containing the activity: op templates, generator bindings, ...
public static final String FIELD_ATYPE = "type";
// cycles for this activity in either "M" or "N..M" form. "M" form implies "0..M"
public static final String FIELD_CYCLES = "cycles";
public static final String FIELD_RECYCLES = "recycles";
// initial thread concurrency for this activity
public static final String FIELD_THREADS = "threads";
public static final String[] field_list = {
FIELD_ALIAS, FIELD_ATYPE, FIELD_CYCLES, FIELD_THREADS, FIELD_RECYCLES
};
// parameter map has its own internal atomic map
private final ParameterMap parameterMap;
private CyclesSpec cyclesSpec;
private CyclesSpec reCyclesSpec;
public ActivityDef(ParameterMap parameterMap) {
this.parameterMap = parameterMap;
}
//public static Optional<ActivityDef> parseActivityDefOptionally(String namedActivitySpec) {
// try {
// ActivityDef activityDef = parseActivityDef(namedActivitySpec);
// return Optional.of(activityDef);
// } catch (Exception e) {
// return Optional.empty();
// }
//}
public static ActivityDef parseActivityDef(String namedActivitySpec) {
Optional<ParameterMap> activityParameterMap = ParameterMap.parseParams(namedActivitySpec);
ActivityDef activityDef = new ActivityDef(activityParameterMap.orElseThrow(
() -> new RuntimeException("Unable to parse:" + namedActivitySpec)
));
logger.info("parsed activityDef {} to-> {}", namedActivitySpec, activityDef);
return activityDef;
}
public String toString() {
return "ActivityDef:" + parameterMap.toString();
}
/**
* The alias that the associated activity instance is known by.
*
* @return the alias
*/
public String getAlias() {
return parameterMap.getOptionalString("alias").orElse(DEFAULT_ALIAS);
}
/**
* The first cycle that will be used for execution of this activity, inclusive.
* If the value is provided as a range as in 0..10, then the first number is the start cycle
* and the second number is the end cycle +1. Effectively, cycle ranges
* are [closed,open) intervals, as in [min..max)
*
* @return the long start cycle
*/
public long getStartCycle() {
return getCyclesSpec().first_inclusive();
}
public void setStartCycle(long firstCycleInclusive) {
cyclesSpec=getCyclesSpec().withFirst(firstCycleInclusive);
}
public void setStartCycle(String firstCycleInclusive) {
cyclesSpec=getCyclesSpec().withFirst(firstCycleInclusive);
}
public void setEndCycle(long lastCycleExclusive) {
cyclesSpec=getCyclesSpec().withLast(lastCycleExclusive);
}
public void setEndCycle(String lastCycleExclusive) {
cyclesSpec=getCyclesSpec().withLast(lastCycleExclusive);
}
/**
* The last cycle that will be used for execution of this activity, inclusive.
*
* @return the long end cycle
*/
public long getEndCycle() {
return getCyclesSpec().last_exclusive();
}
/**
* The number of threads (AKA slots) that the associated activity should currently be using.
*
* @return target thread count
*/
public int getThreads() {
return parameterMap.getOptionalInteger(FIELD_THREADS).orElse(DEFAULT_THREADS);
}
public void setThreads(int threads) {
parameterMap.set(FIELD_THREADS, threads);
}
/**
* Get the parameter map, which is the backing-store for all data within an ActivityDef.
*
* @return the parameter map
*/
public ParameterMap getParams() {
return parameterMap;
}
public AtomicLong getChangeCounter() {
return parameterMap.getChangeCounter();
}
public void setCycles(String cycles) {
parameterMap.set(FIELD_CYCLES, cycles);
this.cyclesSpec=CyclesSpec.parse(cycles);
checkInvariants();
}
public String getCycleSummary() {
return getCyclesSpec().summary();
}
public synchronized long getCycleCount() {
return getCyclesSpec().cycle_count();
}
public synchronized CyclesSpec getCyclesSpec() {
if (this.cyclesSpec==null) {
this.cyclesSpec = CyclesSpec.parse(parameterMap.getOptionalString(FIELD_CYCLES).orElse(DEFAULT_CYCLES));
}
return this.cyclesSpec;
}
public synchronized CyclesSpec getRecyclesSpec() {
if (this.reCyclesSpec==null) {
this.reCyclesSpec = CyclesSpec.parse(parameterMap.getOptionalString(FIELD_RECYCLES).orElse(DEFAULT_RECYCLES));
}
return this.reCyclesSpec;
}
private void checkInvariants() {
if (getStartCycle() >= getEndCycle()) {
throw new InvalidParameterException("Start cycle must be strictly less than end cycle, but they are [" + getStartCycle() + ',' + getEndCycle() + ')');
}
}
@Override
public String getName() {
return getAlias();
}
public ActivityDef deprecate(String deprecatedName, String newName) {
Object deprecatedParam = this.parameterMap.get(deprecatedName);
if (null == deprecatedParam) {
return this;
}
if (deprecatedParam instanceof CharSequence chars) {
if (this.parameterMap.containsKey(newName)) {
throw new BasicError("You have specified activity param '" + deprecatedName + "' in addition to the valid name '" + newName + "'. Remove '" + deprecatedName + "'.");
}
if (!newName.equals("driver")) {
logger.warn("Auto replacing deprecated activity param '{}={}' with new '{}={}'.", deprecatedName, chars, newName, chars);
}
parameterMap.put(newName, parameterMap.remove(deprecatedName));
} else {
throw new BasicError("Can't replace deprecated name with value of type " + deprecatedName.getClass().getCanonicalName());
}
return this;
}
public NBLabels auxLabels() {
Optional<String> auxLabelSpec = getParams().getOptionalString("labels");
if (auxLabelSpec.isPresent()) {
return NBLabelSpec.parseLabels(auxLabelSpec.get());
}
return NBLabels.forKV();
}
public NBConfigModel getConfigModel() {
ConfigModel cfgmodel = ConfigModel.of(this.getClass());
Map<String, String> params = parameterMap.getStringStringMap();
params.forEach((k, v) -> {
cfgmodel.add(Param.defaultTo(k, v, "activity parameter found on command line"));
});
cfgmodel.add(Param.defaultTo(FIELD_ALIAS, DEFAULT_ALIAS).setDescription("The alias for the operations"));
cfgmodel.add(Param.defaultTo(FIELD_ATYPE, DEFAULT_ATYPE).setDescription("The default adapter type is 'stdout'"));
cfgmodel.add(Param.defaultTo(FIELD_CYCLES, DEFAULT_CYCLES).setDescription("The default number of cycles to test is '0'"));
cfgmodel.add(Param.defaultTo(FIELD_THREADS, DEFAULT_THREADS).setDescription("The default number of threads for testing is '1'"));
cfgmodel.add(Param.defaultTo(FIELD_RECYCLES, DEFAULT_RECYCLES).setDescription("The default number of recycles to test is '1'"));
cfgmodel.add(Param.optional("labels", String.class).setDescription("Metric labels for this activity"));
cfgmodel.add(Param.optional("tags", String.class).setDescription("Tags for selecting workload op templates"));
cfgmodel.add(Param.defaultTo("driver", DEFAULT_ATYPE).setDescription("The default adapter driver is 'stdout'"));
cfgmodel.add(Param.optional("workload", String.class).setDescription("The test workload"));
cfgmodel.add(Param.optional("yaml", String.class).setDescription("The test workload"));
cfgmodel.add(Param.defaultTo("async", 1,"Inflight Ops"));
cfgmodel.add(Param.defaultTo("maxtries", 10,"Maximum number of retries"));
cfgmodel.add(Param.defaultTo("interval", 1000,"Action interval"));
cfgmodel.add(Param.defaultTo("hdr_digits", 4,"HDR Digits"));
cfgmodel.add(Param.optional("errors").setDescription("Error handling method"));
cfgmodel.add(Param.optional("striderate").setDescription("Rate limiting stride"));
List<String> rates = Arrays.asList("cyclerate", "targetrate", "rate");
cfgmodel.add(Param.optional(rates, String.class, "Rate limit"));
return cfgmodel.asReadOnly();
}
}

View File

@ -74,7 +74,8 @@ public class GrafanaRegionAnalyzer implements Runnable {
//[2020-12-15T05:04:37.232Z[GMT] - 2020-12-15T05:04:37.232Z[GMT]] //[2020-12-15T05:04:37.232Z[GMT] - 2020-12-15T05:04:37.232Z[GMT]]
//span:interval //span:interval
//details: //details:
// params: ActivityDef:(4)/{keycount=5000000000L, hosts=node1, main-cycles=500, threads=1, workload=./keyvalue.yaml, cycles=2, stride=2, tags=block:'schema.*', password=cassandra, rf=3, pooling=16:16:500, driver=cql, rampup-cycles=5000000000, alias=keyvalue_default_schema, valuecount=5000000000L, errors=count, username=cassandra} // params: ActivityConfig:(4)/{keycount=5000000000L, hosts=node1, main-cycles=500,
// threads=1, workload=./keyvalue.yaml, cycles=2, stride=2, tags=block:'schema.*', password=cassandra, rf=3, pooling=16:16:500, driver=cql, rampup-cycles=5000000000, alias=keyvalue_default_schema, valuecount=5000000000L, errors=count, username=cassandra}
//labels: //labels:
// layer: StandardActivity // layer: StandardActivity
// alias: keyvalue_default_schema // alias: keyvalue_default_schema

View File

@ -1,36 +0,0 @@
/*
* Copyright (c) 2022-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.engine.api.activityapi.core;
import io.nosqlbench.nb.api.engine.activityimpl.ActivityDef;
/**
* Decorator interface for getting notified when an activities parameters are changed at runtime.
*
* This can be optionally implemented by Any Motor, Input, or Action. The eventing is mediated
* through the ActivityExecutor in order to isolate the programmatic API from the internal API.
*/
public interface ActivityDefObserver {
void onActivityDefUpdate(ActivityDef activityDef);
static void apply(ActivityDef def, Object... candidates) {
for (Object candidate : candidates) {
if (candidate instanceof ActivityDefObserver observer) {
observer.onActivityDefUpdate(def);
}
}
}
}

View File

@ -19,7 +19,6 @@ package io.nosqlbench.engine.api.activityapi.core;
import com.codahale.metrics.Counter; import com.codahale.metrics.Counter;
import com.codahale.metrics.Timer; import com.codahale.metrics.Timer;
import io.nosqlbench.engine.api.activityimpl.uniform.Activity; import io.nosqlbench.engine.api.activityimpl.uniform.Activity;
import io.nosqlbench.nb.api.engine.activityimpl.ActivityDef;
import io.nosqlbench.nb.api.engine.activityimpl.ParameterMap; import io.nosqlbench.nb.api.engine.activityimpl.ParameterMap;
import io.nosqlbench.nb.api.engine.metrics.instruments.*; import io.nosqlbench.nb.api.engine.metrics.instruments.*;
@ -30,8 +29,6 @@ public class ComponentActivityInstrumentation {
private static final String RESPONSE_TIME = "_responsetime"; private static final String RESPONSE_TIME = "_responsetime";
private final Activity activity; private final Activity activity;
private final ActivityDef def;
private final ParameterMap params;
private final int hdrdigits; private final int hdrdigits;
private NBMetricTimer readInputTimer; private NBMetricTimer readInputTimer;
private NBMetricTimer stridesServiceTimer; private NBMetricTimer stridesServiceTimer;
@ -53,9 +50,7 @@ public class ComponentActivityInstrumentation {
public ComponentActivityInstrumentation(final Activity activity) { public ComponentActivityInstrumentation(final Activity activity) {
this.activity = activity; this.activity = activity;
def = activity.getActivityDef();
this.hdrdigits = activity.getComponentProp("hdr_digits").map(Integer::parseInt).orElse(3); this.hdrdigits = activity.getComponentProp("hdr_digits").map(Integer::parseInt).orElse(3);
params = this.def.getParams();
initMetrics(); initMetrics();
} }

View File

@ -23,7 +23,7 @@ import io.nosqlbench.engine.api.activityapi.input.InputDispenser;
import io.nosqlbench.engine.api.activityapi.output.OutputDispenser; import io.nosqlbench.engine.api.activityapi.output.OutputDispenser;
import io.nosqlbench.engine.api.activityimpl.uniform.Activity; import io.nosqlbench.engine.api.activityimpl.uniform.Activity;
import io.nosqlbench.nb.api.components.core.NBComponent; import io.nosqlbench.nb.api.components.core.NBComponent;
import io.nosqlbench.nb.api.engine.activityimpl.ActivityDef; import io.nosqlbench.nb.api.engine.activityimpl.ActivityConfig;
import java.io.InputStream; import java.io.InputStream;
import java.io.PrintWriter; import java.io.PrintWriter;
@ -32,9 +32,9 @@ import java.io.PrintWriter;
* Provides the components needed to build and run an activity a runtime. * Provides the components needed to build and run an activity a runtime.
* The easiest way to build a useful StandardActivity is to extend {@link Activity}. * The easiest way to build a useful StandardActivity is to extend {@link Activity}.
*/ */
public interface IActivityWiring extends Comparable<IActivityWiring>, ActivityDefObserver, ProgressCapable, StateCapable, NBComponent { public interface IActivityWiring extends Comparable<IActivityWiring>, ProgressCapable, StateCapable, NBComponent {
ActivityDef getActivityDef(); ActivityConfig getActivityConfig();
MotorDispenser<?> getMotorDispenserDelegate(); MotorDispenser<?> getMotorDispenserDelegate();

View File

@ -15,7 +15,8 @@
*/ */
package io.nosqlbench.engine.api.activityapi.core; package io.nosqlbench.engine.api.activityapi.core;
import io.nosqlbench.nb.api.engine.activityimpl.ActivityDef; import io.nosqlbench.nb.api.config.standard.NBConfiguration;
import io.nosqlbench.nb.api.engine.activityimpl.ActivityConfig;
/** /**
* A MotorDispenser is created for each StandardActivity instance within a scenario. * A MotorDispenser is created for each StandardActivity instance within a scenario.
@ -29,9 +30,10 @@ public interface MotorDispenser<T> {
* Resolve (find or create) a Motor instance for the slot specified. * Resolve (find or create) a Motor instance for the slot specified.
* The motor is not required to be per-slot (per-thread), but any shared inputs motors be thread safe. * The motor is not required to be per-slot (per-thread), but any shared inputs motors be thread safe.
* *
* @param activityDef the ActivityDef which will be used to parameterize the returned motor * @param activityConfig the activity config which will be used to parameterize the returned
* motor
* @param slot The numbered slot within the activity instance for this motor * @param slot The numbered slot within the activity instance for this motor
* @return A new or cached Motor for the specified slot. * @return A new or cached Motor for the specified slot.
*/ */
Motor<T> getMotor(ActivityDef activityDef, int slot); Motor<T> getMotor(ActivityConfig activityConfig, int slot);
} }

View File

@ -52,9 +52,9 @@ public class CycleLogInput extends NBBaseComponent implements Input, AutoCloseab
public CycleLogInput(Activity activity) { public CycleLogInput(Activity activity) {
super(activity, NBLabels.forKV("input","cyclelog")); super(activity, NBLabels.forKV("input","cyclelog"));
SimpleConfig conf = new SimpleConfig(activity.getActivityDef(), "input"); SimpleConfig conf = new SimpleConfig(activity, "input");
mbb = mbb =
initMappedBuffer(conf.getString("file").orElse(activity.getActivityDef().getAlias()) + initMappedBuffer(conf.getString("file").orElse(activity.getAlias()) +
".cyclelog"); ".cyclelog");
cycleResultSegmentIterator = iterator(); cycleResultSegmentIterator = iterator();
segmentIter = cycleResultSegmentIterator.next().iterator(); segmentIter = cycleResultSegmentIterator.next().iterator();

View File

@ -68,7 +68,7 @@ public class CycleLogOutput extends NBBaseComponent implements Output, CanFilter
SimpleConfig conf = new SimpleConfig(wiring, "output"); SimpleConfig conf = new SimpleConfig(wiring, "output");
this.extentSizeInSpans = conf.getInteger("extentSize").orElse(1000); this.extentSizeInSpans = conf.getInteger("extentSize").orElse(1000);
this.outputFile = new File(conf.getString("file").orElse(wiring.getActivityDef().getAlias()) + this.outputFile = new File(conf.getString("file").orElse(wiring.getConfig().getAlias()) +
".cyclelog"); ".cyclelog");

View File

@ -35,7 +35,7 @@ public class LoggingMarkerDispenser implements OutputDispenser {
@Override @Override
public Output getOutput(long slot) { public Output getOutput(long slot) {
return new LoggingOutput(activity.getActivityDef(), slot); return new LoggingOutput(activity.getConfig() , slot);
} }
} }

View File

@ -19,7 +19,7 @@ package io.nosqlbench.engine.api.activityapi.cyclelog.outputs.logger;
import io.nosqlbench.engine.api.activityapi.cyclelog.buffers.results.ResultReadable; import io.nosqlbench.engine.api.activityapi.cyclelog.buffers.results.ResultReadable;
import io.nosqlbench.engine.api.activityapi.cyclelog.inputs.cyclelog.CanFilterResultValue; import io.nosqlbench.engine.api.activityapi.cyclelog.inputs.cyclelog.CanFilterResultValue;
import io.nosqlbench.engine.api.activityapi.output.Output; import io.nosqlbench.engine.api.activityapi.output.Output;
import io.nosqlbench.nb.api.engine.activityimpl.ActivityDef; import io.nosqlbench.nb.api.config.standard.NBConfiguration;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
@ -28,12 +28,12 @@ import java.util.function.Predicate;
public class LoggingOutput implements Output, CanFilterResultValue { public class LoggingOutput implements Output, CanFilterResultValue {
private final static Logger logger = LogManager.getLogger(LoggingOutput.class); private final static Logger logger = LogManager.getLogger(LoggingOutput.class);
private final ActivityDef def; private final NBConfiguration def;
private final long slot; private final long slot;
private final ThreadLocal<StringBuilder> sb = ThreadLocal.withInitial(StringBuilder::new); private final ThreadLocal<StringBuilder> sb = ThreadLocal.withInitial(StringBuilder::new);
private Predicate<ResultReadable> filter; private Predicate<ResultReadable> filter;
public LoggingOutput(ActivityDef def, long slot) { public LoggingOutput(NBConfiguration def, long slot) {
this.def = def; this.def = def;
this.slot = slot; this.slot = slot;
} }
@ -45,7 +45,7 @@ public class LoggingOutput implements Output, CanFilterResultValue {
} }
sb.get().setLength(0); sb.get().setLength(0);
sb.get() sb.get()
.append("activity=").append(def.getAlias()) .append("activity=").append(def.get("alias",String.class))
.append(",cycle=").append(completedCycle) .append(",cycle=").append(completedCycle)
.append(",result=").append((byte) (result & 127)); .append(",result=").append((byte) (result & 127));
logger.info(() -> sb.get().toString()); logger.info(() -> sb.get().toString());

View File

@ -16,7 +16,7 @@
package io.nosqlbench.engine.api.activityapi.errorhandling; package io.nosqlbench.engine.api.activityapi.errorhandling;
import io.nosqlbench.nb.api.engine.activityimpl.ActivityDef; import io.nosqlbench.engine.api.activityimpl.uniform.Activity;
import io.nosqlbench.nb.api.components.core.NBComponent; import io.nosqlbench.nb.api.components.core.NBComponent;
import io.nosqlbench.engine.api.metrics.ExceptionCountMetrics; import io.nosqlbench.engine.api.metrics.ExceptionCountMetrics;
import io.nosqlbench.engine.api.metrics.ExceptionExpectedResultVerificationMetrics; import io.nosqlbench.engine.api.metrics.ExceptionExpectedResultVerificationMetrics;
@ -46,7 +46,7 @@ public class ErrorMetrics {
public synchronized ExceptionHistoMetrics getExceptionHistoMetrics() { public synchronized ExceptionHistoMetrics getExceptionHistoMetrics() {
if (null == exceptionHistoMetrics) if (null == exceptionHistoMetrics)
this.exceptionHistoMetrics = new ExceptionHistoMetrics(this.parent, ActivityDef.parseActivityDef("")); this.exceptionHistoMetrics = new ExceptionHistoMetrics(this.parent, Activity.configFor(""));
return this.exceptionHistoMetrics; return this.exceptionHistoMetrics;
} }
@ -57,7 +57,7 @@ public class ErrorMetrics {
public synchronized ExceptionTimerMetrics getExceptionTimerMetrics() { public synchronized ExceptionTimerMetrics getExceptionTimerMetrics() {
if (null == exceptionTimerMetrics) if (null == exceptionTimerMetrics)
this.exceptionTimerMetrics = new ExceptionTimerMetrics(this.parent, ActivityDef.parseActivityDef("")); this.exceptionTimerMetrics = new ExceptionTimerMetrics(this.parent, Activity.configFor(""));
return this.exceptionTimerMetrics; return this.exceptionTimerMetrics;
} }

View File

@ -53,8 +53,8 @@ public class CoreServices {
} }
public static <A> Optional<Predicate<ResultReadable>> getOutputFilter(ActivityWiring activity) { public static <A> Optional<Predicate<ResultReadable>> getOutputFilter(ActivityWiring activity) {
String paramdata= activity.getParams().getOptionalString("of") String paramdata= activity.getConfig().getOptional("of")
.orElse(activity.getParams().getOptionalString("outputfilter").orElse(null)); .orElse(activity.getConfig().getOptional("outputfilter").orElse(null));
if (paramdata==null) { if (paramdata==null) {
return Optional.empty(); return Optional.empty();
} }
@ -81,8 +81,8 @@ public class CoreServices {
} }
public static <A> Optional<Predicate<ResultReadable>> getInputFilter(Activity activity) { public static <A> Optional<Predicate<ResultReadable>> getInputFilter(Activity activity) {
String paramdata= activity.getParams().getOptionalString("if") String paramdata= activity.getConfig().getOptional("if")
.orElse(activity.getParams().getOptionalString("inputfilter").orElse(null)); .orElse(activity.getConfig().getOptional("inputfilter").orElse(null));
if (paramdata==null) { if (paramdata==null) {
return Optional.empty(); return Optional.empty();
} }

View File

@ -17,7 +17,7 @@
package io.nosqlbench.engine.api.activityimpl.action; package io.nosqlbench.engine.api.activityimpl.action;
import io.nosqlbench.engine.api.activityapi.core.SyncAction; import io.nosqlbench.engine.api.activityapi.core.SyncAction;
import io.nosqlbench.nb.api.engine.activityimpl.ActivityDef; import io.nosqlbench.nb.api.engine.activityimpl.ActivityConfig;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
@ -26,12 +26,12 @@ public class CoreAction implements SyncAction {
private final int interval; private final int interval;
private final int slot; private final int slot;
private final ActivityDef activityDef; private final ActivityConfig activityDef;
public CoreAction(ActivityDef activityDef, int slot) { public CoreAction(ActivityConfig activityDef, int slot) {
this.activityDef = activityDef; this.activityDef = activityDef;
this.slot = slot; this.slot = slot;
this.interval = activityDef.getParams().getOptionalInteger("interval").orElse(1000); this.interval = activityDef.getOptional("interval").map(Integer::parseInt).orElse(1000);
} }
@Override @Override

View File

@ -36,6 +36,6 @@ public class CoreActionDispenser implements ActionDispenser {
@Override @Override
public SyncAction getAction(int slot) { public SyncAction getAction(int slot) {
return new CoreAction(activity.getActivityDef(), slot); return new CoreAction(activity.getConfig(), slot);
} }
} }

View File

@ -16,11 +16,11 @@
package io.nosqlbench.engine.api.activityimpl.input; package io.nosqlbench.engine.api.activityimpl.input;
import com.codahale.metrics.Gauge; import com.codahale.metrics.Gauge;
import io.nosqlbench.nb.api.engine.activityimpl.ActivityDef; import io.nosqlbench.engine.api.activityimpl.uniform.Activity;
import io.nosqlbench.nb.api.config.standard.*;
import io.nosqlbench.nb.api.engine.activityimpl.ActivityConfig;
import io.nosqlbench.nb.api.engine.activityimpl.CyclesSpec; import io.nosqlbench.nb.api.engine.activityimpl.CyclesSpec;
import io.nosqlbench.nb.api.components.core.NBComponent;
import io.nosqlbench.nb.api.components.core.NBBaseComponent; import io.nosqlbench.nb.api.components.core.NBBaseComponent;
import io.nosqlbench.engine.api.activityapi.core.ActivityDefObserver;
import io.nosqlbench.engine.api.activityapi.cyclelog.buffers.results.CycleSegment; import io.nosqlbench.engine.api.activityapi.cyclelog.buffers.results.CycleSegment;
import io.nosqlbench.engine.api.activityapi.input.Input; import io.nosqlbench.engine.api.activityapi.input.Input;
import io.nosqlbench.nb.api.engine.metrics.instruments.MetricCategory; import io.nosqlbench.nb.api.engine.metrics.instruments.MetricCategory;
@ -30,20 +30,21 @@ import org.apache.logging.log4j.Logger;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
/** /**
* <p>TODO: This documentation is out of date as of 2.0.0 <p>TODO: This documentation is out of date as of 2.0.0
* <p>This input will provide threadsafe access to a sequence of long values.</p> <p>This input will provide threadsafe access to a sequence of long values.</p>
* <p>Changes to the cycles or the targetrate will affect the provided inputs. <p>Changes to the cycles or the targetrate will affect the provided inputs.
* If the min or max cycle is changed, then these are re-applied first to the If the min or max cycle is changed, then these are re-applied first to the
* max cycle and then to the min cycle. If the min cycle is changed, then the max cycle and then to the min cycle. If the min cycle is changed, then the
* next cycle value is set to the assigned min value. Otherwise, the cycle next cycle value is set to the assigned min value. Otherwise, the cycle
* will continue as usual till it reaches the max value. The ability to start will continue as usual till it reaches the max value. The ability to start
* the input while running by applying a new set of parameters makes it possible the input while running by applying a new set of parameters makes it possible
* to re-trigger a sequence of inputs during a test.</p> to re-trigger a sequence of inputs during a test.</p>
* <p>This input, and Inputs in general do not actively prevent usage of values <p>This input, and Inputs in general do not actively prevent usage of values
* after the max value. They simply expose it to callers. It is up to the after the max value. They simply expose it to callers. It is up to the
* caller to check the value to determine when the input is deemed "used up."</p> caller to check the value to determine when the input is deemed "used up."</p> */
*/ public class AtomicInput extends NBBaseComponent
public class AtomicInput extends NBBaseComponent implements Input, ActivityDefObserver, Gauge<Long> { implements Input, NBConfigurable, NBReconfigurable, Gauge<Long>
{
private final static Logger logger = LogManager.getLogger(AtomicInput.class); private final static Logger logger = LogManager.getLogger(AtomicInput.class);
private final AtomicLong cycle_value = new AtomicLong(0L); private final AtomicLong cycle_value = new AtomicLong(0L);
@ -54,69 +55,43 @@ public class AtomicInput extends NBBaseComponent implements Input, ActivityDefOb
private final AtomicLong recycle_value = new AtomicLong(0L); private final AtomicLong recycle_value = new AtomicLong(0L);
private final AtomicLong recycles_max = new AtomicLong(0L); private final AtomicLong recycles_max = new AtomicLong(0L);
private final long startedAt = System.currentTimeMillis(); private final long startedAt = System.currentTimeMillis();
private NBConfiguration config;
private final ActivityDef activityDef; public AtomicInput(Activity parent) {
public AtomicInput(NBComponent parent, ActivityDef activityDef) {
super(parent); super(parent);
this.activityDef = activityDef; applyConfig(parent.getConfig());
onActivityDefUpdate(activityDef);
create().gauge( create().gauge(
"input_cycles_first", "input_cycles_first", () -> (double) this.cycles_min.get(), MetricCategory.Config,
() -> (double) this.cycles_min.get(), "The first cycle of the cycle interval, inclusive");
MetricCategory.Config,
"The first cycle of the cycle interval, inclusive"
);
create().gauge( create().gauge(
"input_cycles_last", "input_cycles_last", () -> (double) this.cycles_max.get(), MetricCategory.Config,
() -> (double) this.cycles_max.get(), "The last cycle of the cycle interval, exclusive");
MetricCategory.Config,
"The last cycle of the cycle interval, exclusive"
);
create().gauge( create().gauge(
"input_cycle", "input_cycle", () -> (double) this.cycle_value.get(), MetricCategory.Core,
() -> (double) this.cycle_value.get(), "The next input cycle that will be dispatched to a thread");
MetricCategory.Core,
"The next input cycle that will be dispatched to a thread"
);
create().gauge( create().gauge(
"input_cycles_total", "input_cycles_total", this::getTotalCycles, MetricCategory.Config,
this::getTotalCycles, "The total number of cycles to be executed");
MetricCategory.Config,
"The total number of cycles to be executed"
);
create().gauge( create().gauge(
"input_recycles_first", "input_recycles_first", () -> (double) this.recycles_min.get(), MetricCategory.Config,
() -> (double) this.recycles_min.get(), "The first recycle value, inclusive");
MetricCategory.Config,
"The first recycle value, inclusive"
);
create().gauge( create().gauge(
"input_recycles_last", "input_recycles_last", () -> (double) this.recycles_max.get(), MetricCategory.Config,
() -> (double) this.recycles_max.get(), "The last recycle value, exclusive");
MetricCategory.Config,
"The last recycle value, exclusive"
);
create().gauge( create().gauge(
"input_recycle", "input_recycle", () -> (double) this.recycle_value.get(), MetricCategory.Core,
() -> (double) this.recycle_value.get(), "The next recycle value that will be dispatched once cycles are completed");
MetricCategory.Core,
"The next recycle value that will be dispatched once cycles are completed"
);
create().gauge( create().gauge(
"input_recycles_total", "input_recycles_total", this::getTotalRecycles, MetricCategory.Config,
this::getTotalRecycles, "The total number of recycles to be executed, within which each set of cycles will be executed");
MetricCategory.Config,
"The total number of recycles to be executed, within which each set of cycles will be executed"
);
} }
private double getTotalRecycles() { private double getTotalRecycles() {
return ((double)this.recycles_max.get())-((double)this.recycles_min.get()); return ((double) this.recycles_max.get()) - ((double) this.recycles_min.get());
} }
private double getTotalCycles() { private double getTotalCycles() {
return ((double)this.cycles_max.get())-((double)this.cycles_min.get()); return ((double) this.cycles_max.get()) - ((double) this.cycles_min.get());
} }
@Override @Override
@ -124,60 +99,114 @@ public class AtomicInput extends NBBaseComponent implements Input, ActivityDefOb
while (true) { while (true) {
long currentStrideStart = this.cycle_value.get(); long currentStrideStart = this.cycle_value.get();
long nextStrideStart = currentStrideStart + stride; long nextStrideStart = currentStrideStart + stride;
if (nextStrideStart > cycles_max.get()) { // This indicates a stride boundary crossing the end if (nextStrideStart >
cycles_max.get())
{ // This indicates a stride boundary crossing the end
recycle_value.getAndIncrement(); recycle_value.getAndIncrement();
if (recycle_value.get() >= recycles_max.get()) { if (recycle_value.get() >= recycles_max.get()) {
logger.trace(() -> "Exhausted input for " + activityDef.getAlias() + " at " + currentStrideStart + ", recycle " + logger.trace(() -> "Exhausted input for " +
"count " + recycle_value.get()); description() +
" at " +
currentStrideStart +
", recycle " +
"count " +
recycle_value.get());
return null; return null;
} else { } else {
cycle_value.set(cycles_min.get()); cycle_value.set(cycles_min.get());
logger.trace(() -> "recycling input for " + activityDef.getAlias() + " recycle:" + recycle_value.get()); logger.trace(() -> "recycling input for " +
description() +
" recycle:" +
recycle_value.get());
continue; continue;
} }
} }
if (cycle_value.compareAndSet(currentStrideStart, nextStrideStart)) { if (cycle_value.compareAndSet(currentStrideStart, nextStrideStart)) {
return new InputInterval.Segment(recycle_value.get(), currentStrideStart, nextStrideStart); return new InputInterval.Segment(
recycle_value.get(), currentStrideStart,
nextStrideStart);
} }
} }
} }
@Override @Override
public String toString() { public String toString() {
return "AtomicInput{" + return "AtomicInput(" +
"cycleValue=" + cycle_value + description() +
", min=" + cycles_min + "){cycleValue=" +
", max=" + cycles_max + cycle_value +
", activity=" + activityDef.getAlias() + ", min=" +
'}'; cycles_min +
", max=" +
cycles_max +
'}';
} }
@Override @Override
public void onActivityDefUpdate(ActivityDef activityDef) { public void applyConfig(NBConfiguration cfg) {
CyclesSpec recyclesSpec = activityDef.getRecyclesSpec(); this.config = this.getConfigModel().matchConfig(cfg);
CyclesSpec cyclesSpec = activityDef.getCyclesSpec(); CyclesSpec recyclesSpec = CyclesSpec.parse(cfg.get(ActivityConfig.FIELD_RECYCLES));
CyclesSpec cyclesSpec = CyclesSpec.parse(cfg.get(ActivityConfig.FIELD_CYCLES));
if (cyclesSpec.cycle_count() == 0) {
throw new RuntimeException("You specified cycles, but the range specified means zero " +
"cycles: " +
cyclesSpec);
}
if (recyclesSpec.cycle_count() == 0) {
throw new RuntimeException("You specified recycles, but the range specified means " +
"zero " +
"recycles: " +
recyclesSpec);
}
cycles_max.set(cyclesSpec.last_exclusive()); cycles_max.set(cyclesSpec.last_exclusive());
if (cycles_min.get() != cyclesSpec.first_inclusive()) { if (cycles_min.get() != cyclesSpec.first_inclusive()) {
logger.info(() -> "resetting first cycle (inclusive) value to: cycle[" + cycles_min.get() + "->" + cyclesSpec.first_inclusive() + "] " + logger.info(() -> "resetting first cycle (inclusive) value to: cycle[" +
" start[" + cycle_value.get() + "->" + cycles_min.get() + "]"); cycles_min.get() +
"->" +
cyclesSpec.first_inclusive() +
"] " +
" start[" +
cycle_value.get() +
"->" +
cycles_min.get() +
"]");
cycles_min.set(cyclesSpec.first_inclusive()); cycles_min.set(cyclesSpec.first_inclusive());
cycle_value.set(cycles_min.get()); cycle_value.set(cycles_min.get());
} }
if (cycles_max.get() != cyclesSpec.last_exclusive()) { if (cycles_max.get() != cyclesSpec.last_exclusive()) {
logger.info(() -> "resetting last cycle (exclusive) value to: cycle[" + cycles_max.get() + "->" + cyclesSpec.last_exclusive() + "]"); logger.info(() -> "resetting last cycle (exclusive) value to: cycle[" +
cycles_max.get() +
"->" +
cyclesSpec.last_exclusive() +
"]");
cycles_max.set(cyclesSpec.last_exclusive()); cycles_max.set(cyclesSpec.last_exclusive());
} }
recycles_max.set(recyclesSpec.last_exclusive()); recycles_max.set(recyclesSpec.last_exclusive());
if (recycles_min.get() != recyclesSpec.first_inclusive()) { if (recycles_min.get() != recyclesSpec.first_inclusive()) {
logger.info(() -> "resetting recycle value to new start: recycle[" + recycles_min.get() + "->" + recyclesSpec.first_inclusive() + "] " + logger.info(() -> "resetting recycle value to new start: recycle[" +
" start[" + recycle_value.get() + "->" + recycles_min.get() + "]"); recycles_min.get() +
"->" +
recyclesSpec.first_inclusive() +
"] " +
" start[" +
recycle_value.get() +
"->" +
recycles_min.get() +
"]");
recycles_min.set(recyclesSpec.first_inclusive()); recycles_min.set(recyclesSpec.first_inclusive());
recycle_value.set(recyclesSpec.first_inclusive()); recycle_value.set(recyclesSpec.first_inclusive());
} }
if (recycles_max.get() != recyclesSpec.last_exclusive()) { if (recycles_max.get() != recyclesSpec.last_exclusive()) {
logger.info(() -> "resetting last recycle (exclusive) value to: recycle[" + recycles_max.get() + "->" + recyclesSpec.last_exclusive() + "]"); logger.info(() -> "resetting last recycle (exclusive) value to: recycle[" +
recycles_max.get() +
"->" +
recyclesSpec.last_exclusive() +
"]");
recycles_max.set(recyclesSpec.last_exclusive()); recycles_max.set(recyclesSpec.last_exclusive());
} }
@ -196,4 +225,22 @@ public class AtomicInput extends NBBaseComponent implements Input, ActivityDefOb
public Long getValue() { public Long getValue() {
return this.cycle_value.get(); return this.cycle_value.get();
} }
@Override
public void applyReconfig(NBConfiguration recfg) {
this.applyConfig(recfg);
}
@Override
public NBConfigModel getReconfigModel() {
return getConfigModel();
}
@Override
public NBConfigModel getConfigModel() {
return ConfigModel.of(AtomicInput.class)
.add(Param.required(ActivityConfig.FIELD_CYCLES, String.class))
.add(Param.required(ActivityConfig.FIELD_RECYCLES, String.class)).asReadOnly();
}
} }

View File

@ -44,7 +44,7 @@ public class CoreInputDispenser implements InputDispenser, ActivitiesAware {
} }
private synchronized Input createInput(long slot) { private synchronized Input createInput(long slot) {
SimpleConfig conf = new SimpleConfig(activity.getActivityDef(), "input"); SimpleConfig conf = new SimpleConfig(activity, "input");
String inputType = conf.getString("type").orElse("atomicseq"); String inputType = conf.getString("type").orElse("atomicseq");
InputType inputTypeImpl = InputType.FINDER.getOrThrow(inputType); InputType inputTypeImpl = InputType.FINDER.getOrThrow(inputType);
InputDispenser inputDispenser = inputTypeImpl.getInputDispenser(activity); InputDispenser inputDispenser = inputTypeImpl.getInputDispenser(activity);

View File

@ -37,7 +37,7 @@ public class TargetRateInputType implements InputType {
public Dispenser(Activity activity) { public Dispenser(Activity activity) {
this.activity = activity; this.activity = activity;
this.input = new AtomicInput(activity, activity.getActivityDef()); this.input = new AtomicInput(activity);
} }
@Override @Override

View File

@ -80,9 +80,9 @@ public class ContiguousOutputChunker implements Output {
// // efficient marker extent handling. The ability to use segmented inputs with markers will // // efficient marker extent handling. The ability to use segmented inputs with markers will
// // come in a future append. // // come in a future append.
// } // }
this.min = new AtomicLong(activity.getActivityDef().getStartCycle()); this.min = new AtomicLong(activity.getCyclesSpec().first_inclusive());
this.nextMin = new AtomicLong(activity.getActivityDef().getEndCycle()); this.nextMin = new AtomicLong(activity.getCyclesSpec().last_exclusive());
long stride = activity.getParams().getOptionalLong("stride").orElse(1L); long stride = activity.getConfig().getOptional(Long.class,"stride").orElse(1L);
long cycleCount = nextMin.get() - min.get(); long cycleCount = nextMin.get() - min.get();
if ((cycleCount % stride) != 0) { if ((cycleCount % stride) != 0) {
throw new RuntimeException("stride must evenly divide into cycles."); throw new RuntimeException("stride must evenly divide into cycles.");

View File

@ -27,7 +27,7 @@ import io.nosqlbench.engine.api.activityapi.output.Output;
import io.nosqlbench.engine.api.activityapi.simrate.RateLimiter; import io.nosqlbench.engine.api.activityapi.simrate.RateLimiter;
import io.nosqlbench.engine.api.activityimpl.uniform.Activity; import io.nosqlbench.engine.api.activityimpl.uniform.Activity;
import io.nosqlbench.nb.api.components.core.NBBaseComponent; import io.nosqlbench.nb.api.components.core.NBBaseComponent;
import io.nosqlbench.nb.api.engine.activityimpl.ActivityDef; import io.nosqlbench.nb.api.config.standard.*;
import io.nosqlbench.nb.api.labels.NBLabels; import io.nosqlbench.nb.api.labels.NBLabels;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
@ -47,7 +47,7 @@ import static io.nosqlbench.engine.api.activityapi.core.RunState.*;
This motor implementation splits the handling of sync and async actions with a hard This motor implementation splits the handling of sync and async actions with a hard
fork in the middle to limit potential breakage of the prior sync implementation fork in the middle to limit potential breakage of the prior sync implementation
with new async logic. */ with new async logic. */
public class CoreMotor<D> extends NBBaseComponent implements ActivityDefObserver, Motor<D>, Stoppable { public class CoreMotor<D> extends NBBaseComponent implements Motor<D>, Stoppable, NBReconfigurable {
private static final Logger logger = LogManager.getLogger(CoreMotor.class); private static final Logger logger = LogManager.getLogger(CoreMotor.class);
@ -74,7 +74,7 @@ public class CoreMotor<D> extends NBBaseComponent implements ActivityDefObserver
private int stride = 1; private int stride = 1;
private OpTracker<D> opTracker; private OpTracker<D> opTracker;
private NBConfiguration config;
/** /**
@ -87,15 +87,20 @@ public class CoreMotor<D> extends NBBaseComponent implements ActivityDefObserver
A LongSupplier which provides the cycle number inputs. A LongSupplier which provides the cycle number inputs.
*/ */
public CoreMotor( public CoreMotor(
Activity activity, long slotId, Input input, SyncAction action, Activity activity,
Output output) { long slotId,
super(activity, NBLabels.forKV("motor", "coremotor")); Input input,
SyncAction action,
Output output
)
{
super(activity, NBLabels.forKV("motor", slotId));
this.activity = activity; this.activity = activity;
this.slotId = slotId; this.slotId = slotId;
setInput(input); setInput(input);
setResultOutput(output); setResultOutput(output);
motorState = new MotorState(slotId, activity.getRunStateTally()); motorState = new MotorState(slotId, activity.getRunStateTally());
onActivityDefUpdate(activity.getActivityDef()); applyConfig(activity.getConfig());
this.action = action; this.action = action;
int hdrdigits = activity.getComponentProp("hdr_digits").map(Integer::parseInt).orElse(3); int hdrdigits = activity.getComponentProp("hdr_digits").map(Integer::parseInt).orElse(3);
@ -150,8 +155,9 @@ public class CoreMotor<D> extends NBBaseComponent implements ActivityDefObserver
cycleRateLimiter = activity.getCycleLimiter(); cycleRateLimiter = activity.getCycleLimiter();
if (motorState.get() == Finished) { if (motorState.get() == Finished) {
logger.warn( logger.warn(() -> "Input was already exhausted for slot " +
() -> "Input was already exhausted for slot " + slotId + ", remaining in finished state."); slotId +
", remaining in finished state.");
} }
action.init(); action.init();
@ -174,13 +180,15 @@ public class CoreMotor<D> extends NBBaseComponent implements ActivityDefObserver
CycleSegment cycleSegment = null; CycleSegment cycleSegment = null;
CycleResultSegmentBuffer segBuffer = new CycleResultSegmentBuffer(stride); CycleResultSegmentBuffer segBuffer = new CycleResultSegmentBuffer(stride);
try (Timer.Context inputTime = inputTimer.time()) { try (Timer.Context inputTime = activity.metrics.inputTimer.time()) {
cycleSegment = input.getInputSegment(stride); cycleSegment = input.getInputSegment(stride);
} }
if (cycleSegment == null) { if (cycleSegment == null) {
logger.trace( logger.trace(() -> "input exhausted (input " +
() -> "input exhausted (input " + input + ") via null segment, stopping motor thread " + slotId); input +
") via null segment, stopping motor thread " +
slotId);
motorState.enterState(Finished); motorState.enterState(Finished);
continue; continue;
} }
@ -198,16 +206,20 @@ public class CoreMotor<D> extends NBBaseComponent implements ActivityDefObserver
long cyclenum = cycleSegment.nextCycle(); long cyclenum = cycleSegment.nextCycle();
if (cyclenum < 0) { if (cyclenum < 0) {
if (cycleSegment.isExhausted()) { if (cycleSegment.isExhausted()) {
logger.trace( logger.trace(() -> "input exhausted (input " +
() -> "input exhausted (input " + input + ") via negative read, stopping motor thread " + slotId); input +
") via negative read, stopping motor thread " +
slotId);
motorState.enterState(Finished); motorState.enterState(Finished);
continue; continue;
} }
} }
if (motorState.get() != Running) { if (motorState.get() != Running) {
logger.trace( logger.trace(() -> "motor stopped after input (input " +
() -> "motor stopped after input (input " + cyclenum + "), stopping motor thread " + slotId); cyclenum +
"), stopping motor thread " +
slotId);
continue; continue;
} }
int result = -1; int result = -1;
@ -226,7 +238,7 @@ public class CoreMotor<D> extends NBBaseComponent implements ActivityDefObserver
throw e; throw e;
} finally { } finally {
long cycleEnd = System.nanoTime(); long cycleEnd = System.nanoTime();
cycleServiceTimer.update( activity.metrics.cycleServiceTimer.update(
(cycleEnd - cycleStart) + cycleDelay, TimeUnit.NANOSECONDS); (cycleEnd - cycleStart) + cycleDelay, TimeUnit.NANOSECONDS);
} }
segBuffer.append(cyclenum, result); segBuffer.append(cyclenum, result);
@ -234,10 +246,9 @@ public class CoreMotor<D> extends NBBaseComponent implements ActivityDefObserver
} finally { } finally {
long strideEnd = System.nanoTime(); long strideEnd = System.nanoTime();
stridesServiceTimer.update( activity.metrics.stridesServiceTimer.update(
(strideEnd - strideStart) + strideDelay, (strideEnd - strideStart) + strideDelay,
TimeUnit.NANOSECONDS TimeUnit.NANOSECONDS);
);
} }
if (output != null) { if (output != null) {
@ -245,8 +256,12 @@ public class CoreMotor<D> extends NBBaseComponent implements ActivityDefObserver
try { try {
output.onCycleResultSegment(outputBuffer); output.onCycleResultSegment(outputBuffer);
} catch (Exception t) { } catch (Exception t) {
logger.error( logger.error(() -> "Error while feeding result segment " +
() -> "Error while feeding result segment " + outputBuffer + " to output '" + output + "', error:" + t); outputBuffer +
" to output '" +
output +
"', error:" +
t);
throw t; throw t;
} }
} }
@ -254,11 +269,13 @@ public class CoreMotor<D> extends NBBaseComponent implements ActivityDefObserver
if (motorState.get() == Stopping) { if (motorState.get() == Stopping) {
motorState.enterState(Stopped); motorState.enterState(Stopped);
logger.trace( logger.trace(() -> Thread.currentThread().getName() +
() -> Thread.currentThread().getName() + " shutting down as " + motorState.get()); " shutting down as " +
motorState.get());
} else if (motorState.get() == Finished) { } else if (motorState.get() == Finished) {
logger.trace( logger.trace(() -> Thread.currentThread().getName() +
() -> Thread.currentThread().getName() + " shutting down as " + motorState.get()); " shutting down as " +
motorState.get());
} else { } else {
logger.warn( logger.warn(
() -> "Unexpected motor state for CoreMotor shutdown: " + motorState.get()); () -> "Unexpected motor state for CoreMotor shutdown: " + motorState.get());
@ -277,18 +294,11 @@ public class CoreMotor<D> extends NBBaseComponent implements ActivityDefObserver
} }
@Override @Override
public void onActivityDefUpdate(ActivityDef activityDef) { public void applyConfig(NBConfiguration cfg) {
NBConfigurable.applyMatching(cfg, new Object[]{input, opTracker, action, output});
for (Object component : (new Object[]{input, opTracker, action, output})) { this.config = getConfigModel().matchConfig(cfg);
if (component instanceof ActivityDefObserver) {
((ActivityDefObserver) component).onActivityDefUpdate(activityDef);
}
}
this.stride = activityDef.getParams().getOptionalInteger("stride").orElse(1);
strideRateLimiter = activity.getStrideLimiter(); strideRateLimiter = activity.getStrideLimiter();
cycleRateLimiter = activity.getCycleLimiter(); cycleRateLimiter = activity.getCycleLimiter();
} }
@Override @Override
@ -298,8 +308,10 @@ public class CoreMotor<D> extends NBBaseComponent implements ActivityDefObserver
Stoppable.stop(input, action); Stoppable.stop(input, action);
motorState.enterState(Stopping); motorState.enterState(Stopping);
} else { } else {
logger.warn( logger.warn(() -> "attempted to stop motor " +
() -> "attempted to stop motor " + this.getSlotId() + ": from non Running state:" + currentState); this.getSlotId() +
": from non Running state:" +
currentState);
} }
} }
@ -307,4 +319,20 @@ public class CoreMotor<D> extends NBBaseComponent implements ActivityDefObserver
this.output = resultOutput; this.output = resultOutput;
} }
@Override
public NBConfigModel getConfigModel() {
return ConfigModel.of(CoreMotor.class).add(Param.required("stride", Integer.class))
.asReadOnly();
}
@Override
public void applyReconfig(NBConfiguration recfg) {
applyConfig(recfg);
}
@Override
public NBConfigModel getReconfigModel() {
return getConfigModel();
}
} }

View File

@ -16,7 +16,7 @@
package io.nosqlbench.engine.api.activityimpl.motor; package io.nosqlbench.engine.api.activityimpl.motor;
import io.nosqlbench.engine.api.activityimpl.uniform.Activity; import io.nosqlbench.engine.api.activityimpl.uniform.Activity;
import io.nosqlbench.nb.api.engine.activityimpl.ActivityDef; import io.nosqlbench.nb.api.engine.activityimpl.ActivityConfig;
import io.nosqlbench.engine.api.activityapi.core.*; import io.nosqlbench.engine.api.activityapi.core.*;
import io.nosqlbench.engine.api.activityapi.input.Input; import io.nosqlbench.engine.api.activityapi.input.Input;
import io.nosqlbench.engine.api.activityapi.input.InputDispenser; import io.nosqlbench.engine.api.activityapi.input.InputDispenser;
@ -49,7 +49,7 @@ public class CoreMotorDispenser<D> implements MotorDispenser<D> {
} }
@Override @Override
public Motor<D> getMotor(ActivityDef activityDef, int slotId) { public Motor<D> getMotor(ActivityConfig activityConfig, int slotId) {
SyncAction action = actionDispenser.getAction(slotId); SyncAction action = actionDispenser.getAction(slotId);
Input input = inputDispenser.getInput(slotId); Input input = inputDispenser.getInput(slotId);
Output output = null; Output output = null;

View File

@ -97,11 +97,20 @@ import org.apache.logging.log4j.Logger;
/// ///
/// The config parameters for an activity are standard, and custom behaviors afforded to activities /// The config parameters for an activity are standard, and custom behaviors afforded to activities
/// work the same across all op types. /// work the same across all op types.
public class Activity<R extends java.util.function.LongFunction, S> extends NBStatusComponent implements InvokableResult, SyntheticOpTemplateProvider, ActivityDefObserver, StateCapable, ProgressCapable, Comparable<Activity>, MotorDispenser { public class Activity<R extends java.util.function.LongFunction, S> extends NBStatusComponent
implements InvokableResult,
SyntheticOpTemplateProvider,
StateCapable,
ProgressCapable,
Comparable<Activity>,
MotorDispenser,
NBConfigurable,
NBReconfigurable
{
private static final Logger logger = LogManager.getLogger("ACTIVITY"); private static final Logger logger = LogManager.getLogger("ACTIVITY");
private final OpSequence<OpDispenser<? extends CycleOp<?>>> sequence; private final OpSequence<OpDispenser<? extends CycleOp<?>>> sequence;
private final ConcurrentHashMap<String, DriverAdapter<CycleOp<?>, Space>> adapters = new ConcurrentHashMap<>(); private final ConcurrentHashMap<String, DriverAdapter<CycleOp<?>, Space>> adapters
protected final ActivityDef activityDef; = new ConcurrentHashMap<>();
public final ActivityMetrics metrics; public final ActivityMetrics metrics;
private ActivityMetricProgressMeter progressMeter; private ActivityMetricProgressMeter progressMeter;
@ -116,28 +125,33 @@ public class Activity<R extends java.util.function.LongFunction, S> extends NBSt
private ErrorMetrics errorMetrics; private ErrorMetrics errorMetrics;
private Input input; private Input input;
private StandardAction<?, ?> action; private StandardAction<?, ?> action;
private ActivityConfig config;
public Activity(NBComponent parent, ActivityDef activityDef) { public Activity(NBComponent parent, ActivityConfig config) {
super(parent, NBLabels.forKV("activity", config.getAlias()).and(config.auxLabels()));
// NBConfiguration validConfig = getConfigModel().apply(config.getMap());
this.applyConfig(config); this.applyConfig(config);
this.sequence = initSequence(); this.sequence = initSequence();
this.metrics = new ActivityMetrics(this); this.metrics = new ActivityMetrics(this);
}
public static ActivityConfig configFor(String s) {
return configFor(ParameterMap.parseParams(s).orElseThrow());
}
getParams().set(
"alias", Optional.ofNullable(activityDef.getAlias()).or(
() -> getParams().getOptionalString("workload")).or(
() -> getParams().getOptionalString("driver")).orElseThrow(
() -> new RuntimeException(
"Unable to determine name of activity from " + activityDef))
);
private OpSequence<OpDispenser<? extends CycleOp<?>>> initSequence() { private OpSequence<OpDispenser<? extends CycleOp<?>>> initSequence() {
// this.activityDef = activityDef; // this.activityDef = activityDef;
// this.metrics = new ActivityMetrics(this); // this.metrics = new ActivityMetrics(this);
// OpsDocList workload;
Optional<String> yaml_loc = config.getOptional("yaml", "workload");
// TODO: avoid having to load this duplicitously to parse the template variables in a separate phase
NBConfigModel yamlmodel = yaml_loc.map(path -> { NBConfigModel yamlmodel = yaml_loc.map(path -> {
return OpsLoader.loadPath( return OpsLoader.loadPath(path, new LinkedHashMap<>(config.getMap()), "activities")
path, new LinkedHashMap<>(activityDef.getParams()), "activities").getConfigModel(); .getConfigModel();
}).orElse(ConfigModel.of(Activity.class).asReadOnly()); }).orElse(ConfigModel.of(Activity.class).asReadOnly());
@ -418,18 +432,6 @@ public class Activity<R extends java.util.function.LongFunction, S> extends NBSt
// return adapter.getErrorNameMapper(); // return adapter.getErrorNameMapper();
// } // }
@Override
public synchronized void onActivityDefUpdate(ActivityDef activityDef) {
for (DriverAdapter<?, ?> adapter : adapters.values()) {
if (adapter instanceof NBReconfigurable configurable) {
NBConfigModel cfgModel = configurable.getReconfigModel();
NBConfiguration cfg = cfgModel.matchConfig(activityDef.getParams());
NBReconfigurable.applyMatching(cfg, List.of(configurable));
}
}
}
@Override @Override
public OpTemplates getSyntheticOpTemplates(OpTemplates opsDocList, Map<String, Object> cfg) { public OpTemplates getSyntheticOpTemplates(OpTemplates opsDocList, Map<String, Object> cfg) {
OpTemplates accumulator = new OpTemplates(); OpTemplates accumulator = new OpTemplates();
@ -469,7 +471,7 @@ public class Activity<R extends java.util.function.LongFunction, S> extends NBSt
switch (event) { switch (event) {
case ParamChange<?> pc -> { case ParamChange<?> pc -> {
switch (pc.value()) { switch (pc.value()) {
case SetThreads st -> activityDef.setThreads(st.threads); case SetThreads st -> config.update(ActivityConfig.FIELD_THREADS, st.threads);
case CycleRateSpec crs -> createOrUpdateCycleLimiter(crs); case CycleRateSpec crs -> createOrUpdateCycleLimiter(crs);
case StrideRateSpec srs -> createOrUpdateStrideLimiter(srs); case StrideRateSpec srs -> createOrUpdateStrideLimiter(srs);
default -> super.onEvent(event); default -> super.onEvent(event);
@ -532,91 +534,94 @@ public class Activity<R extends java.util.function.LongFunction, S> extends NBSt
// } // }
/** /**
Modify the provided ActivityDef with defaults for stride and cycles, if they haven't been Modify the provided activity config with defaults for stride and cycles, if they haven't been
provided, based on the provided, based on the
length of the sequence as determined by the provided ratios. Also, modify the ActivityDef with length of the sequence as determined by the provided ratios. Also, modify the activity config
with
reasonable reasonable
defaults when requested. defaults when requested.
@param seq @param seq
- The {@link OpSequence} to derive the defaults from - The {@link OpSequence} to derive the defaults from
*/ */
private synchronized void setDefaultsFromOpSequence(OpSequence<?> seq) { private synchronized void setDefaultsFromOpSequence(OpSequence<?> seq) {
Optional<String> strideOpt = getParams().getOptionalString("stride"); Map<String, Object> updates = new LinkedHashMap<>(config.getMap());
if (strideOpt.isEmpty()) {
String stride = String.valueOf(seq.getSequence().length); updates.computeIfAbsent(
logger.info(() -> "defaulting stride to " + stride + " (the sequence length)"); "stride", k -> {
// getParams().set("stride", stride); String stride = String.valueOf(seq.getSequence().length);
getParams().setSilently("stride", stride); logger.info(() -> "defaulting stride to " + stride + " (the sequence length)");
return stride;
});
updates.computeIfAbsent(
"cycles", k -> {
String cycles = (String) updates.get("stride");
logger.info(() -> "defaulting cycles to " + cycles + " (the stride length)");
return cycles;
});
long cycles = CyclesSpec.parse(updates.get("cycles").toString()).cycle_count();
long stride = Long.parseLong(updates.get("stride").toString());
if (cycles < stride) {
throw new RuntimeException("The specified cycles (" +
cycles +
") are less than the stride (" +
stride +
"). This means there aren't enough cycles to cause a stride to be" +
" executed. If this was intended, then set stride low enough to" +
" allow it.");
} }
// CYCLES Optional<String> threadSpec = Optional.ofNullable(updates.get("threads"))
Optional<String> cyclesOpt = getParams().getOptionalString("cycles"); .map(String::valueOf);
if (cyclesOpt.isEmpty()) {
String cycles = getParams().getOptionalString("stride").orElseThrow();
logger.info(() -> "defaulting cycles to " + cycles + " (the stride length)");
this.getActivityDef().setCycles(getParams().getOptionalString("stride").orElseThrow());
} else {
if (0 == activityDef.getCycleCount()) {
throw new RuntimeException(
"You specified cycles, but the range specified means zero cycles: " + getParams().get(
"cycles"));
}
long stride = getParams().getOptionalLong("stride").orElseThrow();
long cycles = this.activityDef.getCycleCount();
if (cycles < stride) {
throw new RuntimeException(
"The specified cycles (" + cycles + ") are less than the stride (" + stride + "). This means there aren't enough cycles to cause a stride to be executed." + " If this was intended, then set stride low enough to allow it.");
}
}
long cycleCount = this.activityDef.getCycleCount();
long stride = this.activityDef.getParams().getOptionalLong("stride").orElseThrow();
if (0 < stride && 0 != cycleCount % stride) {
logger.warn(
() -> "The stride does not evenly divide cycles. Only full strides will be executed," + "leaving some cycles unused. (stride=" + stride + ", cycles=" + cycleCount + ')');
}
Optional<String> threadSpec = activityDef.getParams().getOptionalString("threads");
if (threadSpec.isPresent()) { if (threadSpec.isPresent()) {
String spec = threadSpec.get(); String spec = threadSpec.get();
int processors = Runtime.getRuntime().availableProcessors(); int processors = Runtime.getRuntime().availableProcessors();
int threads = 0;
if ("auto".equalsIgnoreCase(spec)) { if ("auto".equalsIgnoreCase(spec)) {
int threads = processors * 10; threads = processors * 10;
if (threads > activityDef.getCycleCount()) { if (threads > cycles) {
threads = (int) activityDef.getCycleCount(); threads = (int) cycles;
logger.info( logger.info(
"setting threads to {} (auto) [10xCORES, cycle count limited]", threads); "setting threads to {} (auto) [10xCORES, cycle count limited]", threads);
} else { } else {
logger.info("setting threads to {} (auto) [10xCORES]", threads); logger.info("setting threads to {} (auto) [10xCORES]", threads);
} }
// activityDef.setThreads(threads);
activityDef.getParams().setSilently("threads", threads);
} else if (spec.toLowerCase().matches("\\d+x")) { } else if (spec.toLowerCase().matches("\\d+x")) {
String multiplier = spec.substring(0, spec.length() - 1); String multiplier = spec.substring(0, spec.length() - 1);
int threads = processors * Integer.parseInt(multiplier); threads = processors * Integer.parseInt(multiplier);
logger.info(() -> "setting threads to " + threads + " (" + multiplier + "x)"); int finalThreads = threads;
// activityDef.setThreads(threads); logger.info(() -> "setting threads to " + finalThreads + " (" + multiplier + "x)");
activityDef.getParams().setSilently("threads", threads);
} else if (spec.toLowerCase().matches("\\d+")) { } else if (spec.toLowerCase().matches("\\d+")) {
logger.info(() -> "setting threads to " + spec + " (direct)"); logger.info(() -> "setting threads to " + spec + " (direct)");
// activityDef.setThreads(Integer.parseInt(spec)); } else {
activityDef.getParams().setSilently("threads", Integer.parseInt(spec)); throw new RuntimeException("Unrecognized format for threads:" + spec);
}
updates.put("threads", threads);
if (threads > cycles) {
int finalThreads1 = threads;
logger.warn(() -> "threads=" +
finalThreads1 +
" and cycles=" +
updates.get("cycles").toString() +
", you should have more cycles than threads.");
} }
if (activityDef.getThreads() > activityDef.getCycleCount()) { } else if (1000 < cycles) {
logger.warn( logger.warn(() -> "For testing at scale, it is highly recommended that you " +
() -> "threads=" + activityDef.getThreads() + " and cycles=" + activityDef.getCycleSummary() + ", you should have more cycles than threads."); "set threads to a value higher than the default of 1." +
} " hint: you can use threads=auto for reasonable default, or" +
" consult the topic on threads with `help threads` for" +
} else if (1000 < cycleCount) { " more information.");
logger.warn(
() -> "For testing at scale, it is highly recommended that you " + "set threads to a value higher than the default of 1." + " hint: you can use threads=auto for reasonable default, or" + " consult the topic on threads with `help threads` for" + " more information.");
} }
if (0 < this.activityDef.getCycleCount() && seq.getOps().isEmpty()) { if (0 < cycles && seq.getOps().isEmpty()) {
throw new BasicError( throw new BasicError(
"You have configured a zero-length sequence and non-zero cycles. It is not possible to continue with this activity."); "You have configured a zero-length sequence and non-zero cycles. It is not" +
" possible to continue with this activity.");
} }
} }
@ -696,25 +701,23 @@ public class Activity<R extends java.util.function.LongFunction, S> extends NBSt
} else if (workload != null && OpsLoader.isJson(workload)) { } else if (workload != null && OpsLoader.isJson(workload)) {
workloadSource = "commandline: (workload/json):" + workload; workloadSource = "commandline: (workload/json):" + workload;
opsDocs = OpsLoader.loadString( opsDocs = OpsLoader.loadString(
workload, OpTemplateFormat.json, activityDef.getParams(), null); workload, OpTemplateFormat.json, config.getMap(), null);
} else if (workload != null && OpsLoader.isYaml(workload)) { } else if (workload != null && OpsLoader.isYaml(workload)) {
workloadSource = "commandline: (workload/yaml):" + workload; workloadSource = "commandline: (workload/yaml):" + workload;
opsDocs= OpsLoader.loadString( opsDocs = OpsLoader.loadString(
workload, OpTemplateFormat.yaml, activityDef.getParams(), null); workload, OpTemplateFormat.yaml, config.getMap(), null);
} else if (workload != null) { } else if (workload != null) {
opsDocs= OpsLoader.loadPath(workload, activityDef.getParams(), "activities"); opsDocs = OpsLoader.loadPath(workload, config.getMap(), "activities");
} else if (stmt != null) { } else if (stmt != null) {
workloadSource = "commandline: (stmt/inline): '" + stmt + "'"; workloadSource = "commandline: (stmt/inline): '" + stmt + "'";
opsDocs= OpsLoader.loadString( opsDocs = OpsLoader.loadString(
stmt, OpTemplateFormat.inline, activityDef.getParams(), null); stmt, OpTemplateFormat.inline, config.getMap(), null);
} else if (op != null && OpsLoader.isJson(op)) { } else if (op != null && OpsLoader.isJson(op)) {
workloadSource = "commandline: (op/json): '" + op + "'"; workloadSource = "commandline: (op/json): '" + op + "'";
opsDocs= OpsLoader.loadString( opsDocs = OpsLoader.loadString(op, OpTemplateFormat.json, config.getMap(), null);
op, OpTemplateFormat.json, activityDef.getParams(), null);
} else if (op != null) { } else if (op != null) {
workloadSource = "commandline: (op/inline): '" + op + "'"; workloadSource = "commandline: (op/inline): '" + op + "'";
opsDocs= OpsLoader.loadString( opsDocs = OpsLoader.loadString(op, OpTemplateFormat.inline, config.getMap(), null);
op, OpTemplateFormat.inline, activityDef.getParams(), null);
} }
return new OpTemplates(opsDocs); return new OpTemplates(opsDocs);
@ -747,24 +750,19 @@ public class Activity<R extends java.util.function.LongFunction, S> extends NBSt
return startedAtMillis; return startedAtMillis;
} }
public ActivityDef getActivityDef() {
return activityDef;
}
public String toString() { public String toString() {
return (activityDef != null ? activityDef.getAlias() : "unset_alias") + ':' + this.runState + ':' + this.tally; return config.getAlias() + ':' + this.runState + ':' + this.tally;
} }
public synchronized void initOrUpdateRateLimiters(ActivityDef activityDef) { public synchronized void initOrUpdateRateLimiters() {
// cycleratePerThread = activityDef.getParams().takeBoolOrDefault("cyclerate_per_thread", false); // cycleratePerThread = activityDef.getParams().takeBoolOrDefault("cyclerate_per_thread", false);
activityDef.getParams().getOptionalNamedParameter("striderate").map( config.getOptional("striderate").map(StrideRateSpec::new)
StrideRateSpec::new).ifPresent(sr -> this.onEvent(new ParamChange<>(sr))); .ifPresent(sr -> this.onEvent(new ParamChange<>(sr)));
activityDef.getParams().getOptionalNamedParameter("cyclerate", "targetrate", "rate").map(
CycleRateSpec::new).ifPresent(sr -> this.onEvent(new ParamChange<>(sr)));
config.getOptional("cyclerate", "targetrate", "rate").map(CycleRateSpec::new)
.ifPresent(sr -> this.onEvent(new ParamChange<>(sr)));
} }
public void createOrUpdateStrideLimiter(SimRateSpec spec) { public void createOrUpdateStrideLimiter(SimRateSpec spec) {
@ -806,7 +804,7 @@ public class Activity<R extends java.util.function.LongFunction, S> extends NBSt
@Override @Override
public Map<String, String> asResult() { public Map<String, String> asResult() {
return Map.of("activity", this.getActivityDef().getAlias()); return Map.of("activity", config.getAlias());
} }
/** /**
@ -816,15 +814,14 @@ public class Activity<R extends java.util.function.LongFunction, S> extends NBSt
@return The number of allowable retries @return The number of allowable retries
*/ */
public int getMaxTries() { public int getMaxTries() {
return this.activityDef.getParams().getOptionalInteger("maxtries").orElse(10); return config.getOptional(Integer.class, "maxtries").orElse(10);
} }
public synchronized NBErrorHandler getErrorHandler() { public synchronized NBErrorHandler getErrorHandler() {
if (null == this.errorHandler) { if (null == this.errorHandler) {
errorHandler = new NBErrorHandler( errorHandler = new NBErrorHandler(
() -> activityDef.getParams().getOptionalString("errors").orElse("stop"), () -> config.getOptional("errors").orElse("stop"),
this::getExceptionMetrics this::getExceptionMetrics);
);
} }
return errorHandler; return errorHandler;
} }
@ -844,7 +841,7 @@ public class Activity<R extends java.util.function.LongFunction, S> extends NBSt
@Override @Override
public int compareTo(Activity o) { public int compareTo(Activity o) {
return this.getActivityDef().getAlias().compareTo(o.getActivityDef().getAlias()); return getAlias().compareTo(o.getAlias());
} }
// public void registerAutoCloseable(AutoCloseable closeable) { // public void registerAutoCloseable(AutoCloseable closeable) {
@ -860,17 +857,17 @@ public class Activity<R extends java.util.function.LongFunction, S> extends NBSt
public String getAlias() { public String getAlias() {
return getActivityDef().getAlias(); return config.getAlias();
} }
@Override @Override
public Motor getMotor(ActivityDef activityDef, int slot) { public Motor getMotor(ActivityConfig activityConfig, int slot) {
return new CoreMotor(this, slot, getInput(), getAction(), getOutput()); return new CoreMotor(this, slot, getInput(), getAction(), getOutput());
} }
public synchronized Input getInput() { public synchronized Input getInput() {
if (input == null) { if (input == null) {
this.input = new AtomicInput(this, this.getActivityDef()); this.input = new AtomicInput(this);
} }
return this.input; return this.input;
} }
@ -891,5 +888,90 @@ public class Activity<R extends java.util.function.LongFunction, S> extends NBSt
cycleLimiterSource = ThreadLocalRateLimiters.createOrUpdate(this, cycleLimiterSource, spec); cycleLimiterSource = ThreadLocalRateLimiters.createOrUpdate(this, cycleLimiterSource, spec);
} }
public ActivityConfig getConfig() {
return this.config;
}
public static ActivityConfig configFor(Map<String, ?> params) {
return new ActivityConfig(configModel.apply(params));
}
private static NBConfigModel configModel = ConfigModel.of(Activity.class)
.add(Param.optional("alias")).add(Param.optional(
"labels", String.class,
"Labels which will apply to metrics and annotations for this activity only"))
.add(Param.defaultTo(
"strict", true,
"strict op field mode, which requires that provided op fields are recognized and used"))
.add(Param.optional("op", String.class, "op template in statement form")).add(
Param.optional(
List.of("stmt", "statement"), String.class,
"op template in statement " + "form"))
.add(Param.defaultTo("tags", "", "tag filter to be used to filter operations"))
.add(Param.defaultTo("errors", "stop", "error handler configuration")).add(
Param.defaultTo("threads","1").setRegex("\\d+|\\d+x|auto")
.setDescription("number of concurrent operations, controlled by threadpool"))
.add(Param.optional("stride").setRegex("\\d+"))
.add(Param.optional("striderate", String.class, "rate limit for strides per second")).add(
Param.defaultTo("cycles", "1")
.setRegex("\\d+[KMBGTPE]?|\\d+[KMBGTPE]?\\.\\" + ".\\d+[KMBGTPE]?")
.setDescription("cycle interval to use")).add(Param.defaultTo("recycles", "1")
.setDescription("allow cycles to be re-used this many " + "times")).add(Param.optional(
List.of("cyclerate", "targetrate", "rate"), String.class,
"rate limit for cycles per second"))
.add(Param.optional("seq", String.class, "sequencing algorithm"))
.add(Param.optional("instrument", Boolean.class)).add(
Param.optional(
List.of("workload", "yaml"), String.class, "location of workload yaml file"))
.add(Param.optional("driver", String.class))
.add(Param.defaultTo("dryrun", "none").setRegex("(op|jsonnet|emit|none)"))
.add(Param.optional("maxtries", Integer.class)).add(
Param.defaultTo(
"input", "type=atomicseq", "The type of cycle input to use for this " + "activity"))
.add(Param.optional(List.of("if","inputfilter"),String.class,"an input filter"))
.add(Param.optional("output",String.class))
.asReadOnly();
@Override
public NBConfigModel getConfigModel() {
return configModel;
}
@Override
public void applyConfig(NBConfiguration config) {
Optional<String> directAlias = config.getOptional("alias");
// if (!directAlias.isPresent()) {
// String indirectAlias = config.getOptional(ActivityConfig.FIELD_ALIAS)
// .or(() -> config.getOptional("workload")).or(() -> config.getOptional("driver"))
// .orElse("ACTIVITYNAME");
//
// config.getMap().put("alias", indirectAlias);
// }
//
NBConfigurable.applyMatchingCollection(config, adapters.values());
this.config = new ActivityConfig(config);
}
@Override
public void applyReconfig(NBConfiguration reconf) {
this.config = new ActivityConfig(getReconfigModel().apply(reconf.getMap()));
}
@Override
public NBConfigModel getReconfigModel() {
return ConfigModel.of(Activity.class).add(
Param.optional("threads").setRegex("\\d+|\\d+x|auto")
.setDescription("number of concurrent operations, controlled by threadpool"))
.add(Param.optional("striderate", String.class, "rate limit for strides per second"))
.add(Param.optional(
List.of("cyclerate", "targetrate", "rate"), String.class,
"rate limit for cycles per second")).asReadOnly();
}
public CyclesSpec getCyclesSpec() {
return CyclesSpec.parse(config.get(ActivityConfig.FIELD_CYCLES));
}
} }

View File

@ -1,23 +0,0 @@
/*
* Copyright (c) 2022-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.engine.api.activityimpl.uniform;
import io.nosqlbench.nb.api.engine.activityimpl.ActivityDef;
public interface ActivityDefAware {
void setActivityDef(ActivityDef activiytDef);
}

View File

@ -2,13 +2,13 @@ package io.nosqlbench.engine.api.activityimpl.uniform;
/* /*
* Copyright (c) nosqlbench * Copyright (c) nosqlbench
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, * Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an * software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@ -23,29 +23,26 @@ import io.nosqlbench.engine.api.activityapi.core.MotorDispenser;
import io.nosqlbench.engine.api.activityapi.cyclelog.filters.IntPredicateDispenser; import io.nosqlbench.engine.api.activityapi.cyclelog.filters.IntPredicateDispenser;
import io.nosqlbench.engine.api.activityapi.input.InputDispenser; import io.nosqlbench.engine.api.activityapi.input.InputDispenser;
import io.nosqlbench.engine.api.activityapi.output.OutputDispenser; import io.nosqlbench.engine.api.activityapi.output.OutputDispenser;
import io.nosqlbench.nb.api.components.core.NBComponent; import io.nosqlbench.nb.api.engine.activityimpl.ActivityConfig;
import io.nosqlbench.nb.api.engine.activityimpl.ActivityDef;
import io.nosqlbench.nb.api.engine.activityimpl.ParameterMap;
import io.nosqlbench.nb.api.labels.NBLabels;
public class ActivityWiring { public class ActivityWiring {
private final ActivityDef activityDef; private final ActivityConfig activityDef;
private MotorDispenser<?> motorDispenser; private MotorDispenser<?> motorDispenser;
private InputDispenser inputDispenser; private InputDispenser inputDispenser;
private ActionDispenser actionDispenser; private ActionDispenser actionDispenser;
private OutputDispenser markerDispenser; private OutputDispenser markerDispenser;
private IntPredicateDispenser resultFilterDispenser; private IntPredicateDispenser resultFilterDispenser;
public ActivityWiring(ActivityDef activityDef) { public ActivityWiring(ActivityConfig activityDef) {
this.activityDef = activityDef; this.activityDef = activityDef;
} }
public static ActivityWiring of(ActivityDef activityDef) { public static ActivityWiring of(ActivityConfig activityDef) {
return new ActivityWiring(activityDef); return new ActivityWiring(activityDef);
} }
public ActivityDef getActivityDef() { public ActivityConfig getConfig() {
return activityDef; return activityDef;
} }
@ -89,8 +86,4 @@ public class ActivityWiring {
this.markerDispenser = outputDispenser; this.markerDispenser = outputDispenser;
} }
public ParameterMap getParams() {
return activityDef.getParams();
}
} }

View File

@ -19,7 +19,7 @@ package io.nosqlbench.engine.api.activityimpl.uniform;
import io.nosqlbench.adapters.api.activityimpl.uniform.DriverAdapter; import io.nosqlbench.adapters.api.activityimpl.uniform.DriverAdapter;
import io.nosqlbench.nb.api.components.core.NBComponent; import io.nosqlbench.nb.api.components.core.NBComponent;
import io.nosqlbench.nb.api.engine.activityimpl.ActivityDef; import io.nosqlbench.nb.api.engine.activityimpl.ActivityConfig;
import io.nosqlbench.engine.api.activityapi.core.ActivitiesAware; import io.nosqlbench.engine.api.activityapi.core.ActivitiesAware;
import io.nosqlbench.engine.api.activityapi.core.ActionDispenser; import io.nosqlbench.engine.api.activityapi.core.ActionDispenser;
import io.nosqlbench.engine.api.activityapi.core.MotorDispenser; import io.nosqlbench.engine.api.activityapi.core.MotorDispenser;
@ -41,9 +41,10 @@ public class StandardActivityType<A extends Activity<?,?>> {
private final Map<String, DriverAdapter> adapters = new HashMap<>(); private final Map<String, DriverAdapter> adapters = new HashMap<>();
private final NBComponent parent; private final NBComponent parent;
// private final DriverAdapter<?, ?> adapter; // private final DriverAdapter<?, ?> adapter;
private final ActivityDef activityDef; private final ActivityConfig activityDef;
public StandardActivityType(final DriverAdapter<?,?> adapter, final ActivityDef activityDef, final NBComponent parent) { public StandardActivityType(final DriverAdapter<?,?> adapter, final ActivityConfig activityDef,
final NBComponent parent) {
this.parent = parent; this.parent = parent;
// this.adapter = adapter; // this.adapter = adapter;
this.activityDef = activityDef; this.activityDef = activityDef;
@ -52,10 +53,9 @@ public class StandardActivityType<A extends Activity<?,?>> {
// .deprecate("yaml", "workload") // .deprecate("yaml", "workload")
// ); // );
adapters.put(adapter.getAdapterName(),adapter); adapters.put(adapter.getAdapterName(),adapter);
if (adapter instanceof ActivityDefAware) ((ActivityDefAware) adapter).setActivityDef(activityDef);
} }
public StandardActivityType(final ActivityDef activityDef, final NBComponent parent) { public StandardActivityType(final ActivityConfig activityDef, final NBComponent parent) {
this.parent = parent; this.parent = parent;
this.activityDef = activityDef; this.activityDef = activityDef;
@ -69,11 +69,9 @@ public class StandardActivityType<A extends Activity<?,?>> {
* @return a distinct StandardActivity instance for each call * @return a distinct StandardActivity instance for each call
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public A getActivity(final ActivityDef activityDef, public A getActivity(final ActivityConfig activityDef,
final NBComponent parent, final NBComponent parent,
final ActivityWiring wiring) { final ActivityWiring wiring) {
if (activityDef.getParams().getOptionalString("async").isPresent())
throw new RuntimeException("This driver does not support async mode yet.");
return (A) new Activity(parent, activityDef); return (A) new Activity(parent, activityDef);
} }
@ -95,7 +93,7 @@ public class StandardActivityType<A extends Activity<?,?>> {
* @return a distinct activity instance for each call * @return a distinct activity instance for each call
*/ */
public Activity getAssembledActivity( public Activity getAssembledActivity(
final NBComponent parent, final ActivityDef activityDef, final NBComponent parent, final ActivityConfig activityDef,
final Map<String, Activity> activities final Map<String, Activity> activities
) { ) {
// final A activity = this.getActivity(activityDef, parent); // final A activity = this.getActivity(activityDef, parent);
@ -122,7 +120,7 @@ public class StandardActivityType<A extends Activity<?,?>> {
if (motorDispenser instanceof ActivitiesAware) ((ActivitiesAware) motorDispenser).setActivitiesMap(activities); if (motorDispenser instanceof ActivitiesAware) ((ActivitiesAware) motorDispenser).setActivitiesMap(activities);
wiring.setMotorDispenserDelegate(motorDispenser); wiring.setMotorDispenserDelegate(motorDispenser);
return this.getActivity(activityDef,parent,wiring); return activity;
} }
/** /**

View File

@ -22,11 +22,9 @@ import io.nosqlbench.adapters.api.activityimpl.uniform.flowtypes.*;
import io.nosqlbench.adapters.api.evalctx.CycleFunction; import io.nosqlbench.adapters.api.evalctx.CycleFunction;
import io.nosqlbench.engine.api.activityimpl.uniform.Activity; import io.nosqlbench.engine.api.activityimpl.uniform.Activity;
import io.nosqlbench.nb.api.components.core.NBBaseComponent; import io.nosqlbench.nb.api.components.core.NBBaseComponent;
import io.nosqlbench.nb.api.engine.activityimpl.ActivityDef;
import io.nosqlbench.nb.api.engine.metrics.instruments.MetricCategory; import io.nosqlbench.nb.api.engine.metrics.instruments.MetricCategory;
import io.nosqlbench.nb.api.engine.metrics.instruments.NBMetricHistogram; import io.nosqlbench.nb.api.engine.metrics.instruments.NBMetricHistogram;
import io.nosqlbench.nb.api.errors.ResultVerificationError; import io.nosqlbench.nb.api.errors.ResultVerificationError;
import io.nosqlbench.engine.api.activityapi.core.ActivityDefObserver;
import io.nosqlbench.engine.api.activityapi.core.SyncAction; import io.nosqlbench.engine.api.activityapi.core.SyncAction;
import io.nosqlbench.engine.api.activityapi.errorhandling.modular.ErrorDetail; import io.nosqlbench.engine.api.activityapi.errorhandling.modular.ErrorDetail;
import io.nosqlbench.engine.api.activityapi.errorhandling.modular.NBErrorHandler; import io.nosqlbench.engine.api.activityapi.errorhandling.modular.NBErrorHandler;
@ -47,7 +45,7 @@ import java.util.concurrent.TimeUnit;
The type of activity The type of activity
@param <R> @param <R>
The type of operation */ The type of operation */
public class StandardAction<A extends Activity<R, ?>, R extends java.util.function.LongFunction> extends NBBaseComponent implements SyncAction, ActivityDefObserver { public class StandardAction<A extends Activity<R, ?>, R extends java.util.function.LongFunction> extends NBBaseComponent implements SyncAction {
private final static Logger logger = LogManager.getLogger("ACTION"); private final static Logger logger = LogManager.getLogger("ACTION");
private final NBErrorHandler errorHandler; private final NBErrorHandler errorHandler;
private final OpSequence<OpDispenser<? extends CycleOp<?>>> opsequence; private final OpSequence<OpDispenser<? extends CycleOp<?>>> opsequence;
@ -142,7 +140,7 @@ public class StandardAction<A extends Activity<R, ?>, R extends java.util.functi
} }
} }
} }
this.triesHistogram.update(tries); activity.metrics.triesHistogram.update(tries);
if (op instanceof OpGenerator) { if (op instanceof OpGenerator) {
logger.trace(() -> "GEN OP for cycle(" + cycle + ")"); logger.trace(() -> "GEN OP for cycle(" + cycle + ")");
@ -155,8 +153,4 @@ public class StandardAction<A extends Activity<R, ?>, R extends java.util.functi
return code; return code;
} }
@Override
public void onActivityDefUpdate(ActivityDef activityDef) {
}
} }

View File

@ -17,7 +17,7 @@
package io.nosqlbench.engine.api.metrics; package io.nosqlbench.engine.api.metrics;
import com.codahale.metrics.Histogram; import com.codahale.metrics.Histogram;
import io.nosqlbench.nb.api.engine.activityimpl.ActivityDef; import io.nosqlbench.nb.api.engine.activityimpl.ActivityConfig;
import io.nosqlbench.nb.api.components.core.NBComponent; import io.nosqlbench.nb.api.components.core.NBComponent;
import io.nosqlbench.nb.api.engine.metrics.instruments.MetricCategory; import io.nosqlbench.nb.api.engine.metrics.instruments.MetricCategory;
@ -34,14 +34,15 @@ public class ExceptionHistoMetrics {
private final ConcurrentHashMap<String, Histogram> histos = new ConcurrentHashMap<>(); private final ConcurrentHashMap<String, Histogram> histos = new ConcurrentHashMap<>();
private final Histogram allerrors; private final Histogram allerrors;
private final NBComponent parent; private final NBComponent parent;
private final ActivityDef activityDef; private final ActivityConfig activityDef;
public ExceptionHistoMetrics(final NBComponent parent, final ActivityDef activityDef) { public ExceptionHistoMetrics(final NBComponent parent, final ActivityConfig config) {
this.parent = parent; this.parent = parent;
this.activityDef = activityDef; this.activityDef = config;
int hdrdigits = parent.getComponentProp("hdr_digits").map(Integer::parseInt).orElse(4);
this.allerrors = parent.create().histogram( this.allerrors = parent.create().histogram(
"errorhistos_ALL", "errorhistos_ALL",
activityDef.getParams().getOptionalInteger("hdr_digits").orElse(4), hdrdigits,
MetricCategory.Errors, MetricCategory.Errors,
"A histogram for all exceptions" "A histogram for all exceptions"
); );
@ -50,11 +51,12 @@ public class ExceptionHistoMetrics {
public void update(final String name, final long magnitude) { public void update(final String name, final long magnitude) {
Histogram h = this.histos.get(name); Histogram h = this.histos.get(name);
if (null == h) synchronized (this.histos) { if (null == h) synchronized (this.histos) {
int hdrdigits = parent.getComponentProp("hdr_digits").map(Integer::parseInt).orElse(4);
h = this.histos.computeIfAbsent( h = this.histos.computeIfAbsent(
name, name,
errName -> parent.create().histogram( errName -> parent.create().histogram(
"errorhistos_"+errName, "errorhistos_"+errName,
this.activityDef.getParams().getOptionalInteger("hdr_digits").orElse(4), hdrdigits,
MetricCategory.Errors, MetricCategory.Errors,
"error histogram for exception '" + errName + "'" "error histogram for exception '" + errName + "'"
) )

View File

@ -17,7 +17,7 @@
package io.nosqlbench.engine.api.metrics; package io.nosqlbench.engine.api.metrics;
import com.codahale.metrics.Timer; import com.codahale.metrics.Timer;
import io.nosqlbench.nb.api.engine.activityimpl.ActivityDef; import io.nosqlbench.nb.api.engine.activityimpl.ActivityConfig;
import io.nosqlbench.nb.api.components.core.NBComponent; import io.nosqlbench.nb.api.components.core.NBComponent;
import io.nosqlbench.nb.api.engine.metrics.instruments.MetricCategory; import io.nosqlbench.nb.api.engine.metrics.instruments.MetricCategory;
@ -32,11 +32,11 @@ import java.util.concurrent.TimeUnit;
public class ExceptionTimerMetrics { public class ExceptionTimerMetrics {
private final ConcurrentHashMap<String, Timer> timers = new ConcurrentHashMap<>(); private final ConcurrentHashMap<String, Timer> timers = new ConcurrentHashMap<>();
private final Timer allerrors; private final Timer allerrors;
private final ActivityDef activityDef; private final ActivityConfig activityDef;
private final NBComponent parentLabels; private final NBComponent parentLabels;
public ExceptionTimerMetrics(final NBComponent parent, final ActivityDef activityDef) { public ExceptionTimerMetrics(final NBComponent parent, final ActivityConfig config) {
this.activityDef = activityDef; this.activityDef = config;
this.parentLabels = parent; this.parentLabels = parent;
this.allerrors=parent.create().timer( this.allerrors=parent.create().timer(

View File

@ -35,7 +35,7 @@ public class ConfigTuples implements Iterable<ConfigTuples.Section> {
} }
public ConfigTuples(Activity activity, String param) { public ConfigTuples(Activity activity, String param) {
this(activity.getParams().getOptionalString(param).orElse("")); this(activity.getConfig().getOptional(param).orElse(""));
} }
private List<Section> parseParams(String configdata) { private List<Section> parseParams(String configdata) {

View File

@ -18,7 +18,6 @@ package io.nosqlbench.engine.api.util;
import io.nosqlbench.engine.api.activityimpl.uniform.ActivityWiring; import io.nosqlbench.engine.api.activityimpl.uniform.ActivityWiring;
import io.nosqlbench.engine.api.activityimpl.uniform.Activity; import io.nosqlbench.engine.api.activityimpl.uniform.Activity;
import io.nosqlbench.nb.api.engine.activityimpl.ActivityDef;
import io.nosqlbench.nb.api.engine.activityimpl.ParameterMap; import io.nosqlbench.nb.api.engine.activityimpl.ParameterMap;
import java.util.Arrays; import java.util.Arrays;
@ -36,13 +35,10 @@ public class SimpleConfig {
} }
public SimpleConfig(Activity activity, String params) { public SimpleConfig(Activity activity, String params) {
this(activity.getActivityDef(),params); this(activity.getConfig().get(params));
} }
public SimpleConfig(ActivityWiring wiring, String param) { public SimpleConfig(ActivityWiring wiring, String param) {
this(wiring.getParams().getOptionalString(param).orElse("")); this(wiring.getConfig().getOptional(param).orElse(""));
}
public SimpleConfig(ActivityDef activityDef, String param) {
this(activityDef.getParams().getOptionalString(param).orElse(""));
} }
public SimpleConfig(ParameterMap parameters, String param) { public SimpleConfig(ParameterMap parameters, String param) {
this(parameters.getOptionalString(param).orElse("")); this(parameters.getOptionalString(param).orElse(""));

View File

@ -27,7 +27,7 @@ public class ActivityExceptionHandler implements Thread.UncaughtExceptionHandler
public ActivityExceptionHandler(ActivityExecutor executor) { public ActivityExceptionHandler(ActivityExecutor executor) {
this.executor = executor; this.executor = executor;
logger.debug(() -> "Activity executor exception handler starting up for executor '" + executor.getActivityDef().getAlias() + "'"); logger.debug(() -> "Activity executor exception handler starting up for executor '" + executor.getActivity().getAlias() + "'");
} }

View File

@ -16,9 +16,12 @@
package io.nosqlbench.engine.core.lifecycle.activity; package io.nosqlbench.engine.core.lifecycle.activity;
import com.codahale.metrics.Gauge; import com.codahale.metrics.Gauge;
import io.nosqlbench.engine.api.activityimpl.motor.CoreMotorDispenser;
import io.nosqlbench.engine.api.activityimpl.uniform.Activity; import io.nosqlbench.engine.api.activityimpl.uniform.Activity;
import io.nosqlbench.engine.core.lifecycle.IndexedThreadFactory; import io.nosqlbench.engine.core.lifecycle.IndexedThreadFactory;
import io.nosqlbench.nb.api.config.standard.NBConfigModel;
import io.nosqlbench.nb.api.config.standard.NBConfiguration;
import io.nosqlbench.nb.api.config.standard.NBReconfigurable;
import io.nosqlbench.nb.api.engine.activityimpl.ActivityConfig;
import io.nosqlbench.nb.api.engine.metrics.instruments.MetricCategory; import io.nosqlbench.nb.api.engine.metrics.instruments.MetricCategory;
import io.nosqlbench.nb.api.engine.metrics.instruments.NBMetricGauge; import io.nosqlbench.nb.api.engine.metrics.instruments.NBMetricGauge;
import io.nosqlbench.nb.api.labels.NBLabeledElement; import io.nosqlbench.nb.api.labels.NBLabeledElement;
@ -28,15 +31,12 @@ import io.nosqlbench.engine.api.activityapi.core.*;
import io.nosqlbench.engine.api.activityimpl.MotorState; import io.nosqlbench.engine.api.activityimpl.MotorState;
import io.nosqlbench.nb.api.annotations.Annotation; import io.nosqlbench.nb.api.annotations.Annotation;
import io.nosqlbench.nb.api.annotations.Layer; import io.nosqlbench.nb.api.annotations.Layer;
import io.nosqlbench.nb.api.engine.activityimpl.ActivityDef;
import io.nosqlbench.nb.api.engine.activityimpl.ParameterMap;
import io.nosqlbench.engine.api.activityapi.core.progress.ProgressCapable; import io.nosqlbench.engine.api.activityapi.core.progress.ProgressCapable;
import io.nosqlbench.engine.api.activityapi.core.progress.ProgressMeterDisplay; import io.nosqlbench.engine.api.activityapi.core.progress.ProgressMeterDisplay;
import io.nosqlbench.engine.api.activityimpl.motor.RunStateImage; import io.nosqlbench.engine.api.activityimpl.motor.RunStateImage;
import io.nosqlbench.engine.api.activityimpl.motor.RunStateTally; import io.nosqlbench.engine.api.activityimpl.motor.RunStateTally;
import io.nosqlbench.engine.core.annotation.Annotators; import io.nosqlbench.engine.core.annotation.Annotators;
import io.nosqlbench.engine.core.lifecycle.ExecutionResult; import io.nosqlbench.engine.core.lifecycle.ExecutionResult;
//import io.nosqlbench.virtdata.userlibs.apps.valuechecker.IndexedThreadFactory;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
@ -45,6 +45,8 @@ import java.util.List;
import java.util.concurrent.*; import java.util.concurrent.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/// TODO: Make this use nbreconfigurable events for live updates
/** /**
* <p>An ActivityExecutor is an execution harness for a single activity instance. * <p>An ActivityExecutor is an execution harness for a single activity instance.
* It is responsible for managing threads and activity settings which may be changed while the activity is running.</p> * It is responsible for managing threads and activity settings which may be changed while the activity is running.</p>
@ -61,7 +63,8 @@ import java.util.stream.Collectors;
* This allows the state tracking to work consistently for all observers.</p> * This allows the state tracking to work consistently for all observers.</p>
*/ */
public class ActivityExecutor implements NBLabeledElement, ParameterMap.Listener, ProgressCapable, Callable<ExecutionResult> { public class ActivityExecutor implements NBReconfigurable, NBLabeledElement, ProgressCapable,
Callable<ExecutionResult> {
// TODO Encapsulate valid state transitions to be only modifiable within the appropriate type view. // TODO Encapsulate valid state transitions to be only modifiable within the appropriate type view.
@ -70,7 +73,7 @@ public class ActivityExecutor implements NBLabeledElement, ParameterMap.Listener
private final LinkedList<Motor<?>> motors = new LinkedList<>(); private final LinkedList<Motor<?>> motors = new LinkedList<>();
private final Activity activity; private final Activity activity;
private final ActivityDef activityDef; private final ActivityConfig config;
private final RunStateTally tally; private final RunStateTally tally;
private final MotorDispenser motorSource; private final MotorDispenser motorSource;
private ExecutorService executorService; private ExecutorService executorService;
@ -84,9 +87,9 @@ public class ActivityExecutor implements NBLabeledElement, ParameterMap.Listener
public ActivityExecutor(Activity activity) { public ActivityExecutor(Activity activity) {
this.activity = activity; this.activity = activity;
this.activityDef = activity.getActivityDef(); this.config = activity.getConfig();
this.motorSource = activity; this.motorSource = activity;
activity.getActivityDef().getParams().addListener(this); // activity.getConfig().addListener(this);
this.tally = activity.getRunStateTally(); this.tally = activity.getRunStateTally();
} }
@ -99,7 +102,7 @@ public class ActivityExecutor implements NBLabeledElement, ParameterMap.Listener
* Simply stop the motors * Simply stop the motors
*/ */
public void stopActivity() { public void stopActivity() {
logger.info(() -> "stopping activity in progress: " + this.getActivityDef().getAlias()); logger.info(() -> "stopping activity in progress: " + activity.getAlias());
activity.setRunState(RunState.Stopping); activity.setRunState(RunState.Stopping);
motors.forEach(Motor::requestStop); motors.forEach(Motor::requestStop);
@ -109,13 +112,13 @@ public class ActivityExecutor implements NBLabeledElement, ParameterMap.Listener
tally.awaitNoneOther(RunState.Stopped, RunState.Finished, RunState.Errored); tally.awaitNoneOther(RunState.Stopped, RunState.Finished, RunState.Errored);
activity.setRunState(RunState.Stopped); activity.setRunState(RunState.Stopped);
logger.info(() -> "stopped: " + this.getActivityDef().getAlias() + " with " + motors.size() + " slots"); logger.info(() -> "stopped: " + activity.getAlias() + " with " + motors.size() + " slots");
Annotators.recordAnnotation(Annotation.newBuilder() Annotators.recordAnnotation(Annotation.newBuilder()
.element(this) .element(this)
.interval(this.startedAt, this.stoppedAt) .interval(this.startedAt, this.stoppedAt)
.layer(Layer.Activity) .layer(Layer.Activity)
.addDetail("params", getActivityDef().toString()) .addDetail("params", String.valueOf(activity.getConfig()))
.build() .build()
); );
} }
@ -124,7 +127,7 @@ public class ActivityExecutor implements NBLabeledElement, ParameterMap.Listener
* Force stop the motors without trying to wait for the activity to reach stopped/finished state * Force stop the motors without trying to wait for the activity to reach stopped/finished state
*/ */
public void forceStopActivity() { public void forceStopActivity() {
logger.info(() -> "force stopping activity in progress: " + this.getActivityDef().getAlias()); logger.info(() -> "force stopping activity in progress: " + activity.getAlias());
activity.setRunState(RunState.Stopping); activity.setRunState(RunState.Stopping);
motors.forEach(Motor::requestStop); motors.forEach(Motor::requestStop);
@ -133,21 +136,20 @@ public class ActivityExecutor implements NBLabeledElement, ParameterMap.Listener
tally.awaitNoneOther(RunState.Stopped, RunState.Finished); tally.awaitNoneOther(RunState.Stopped, RunState.Finished);
activity.setRunState(RunState.Stopped); activity.setRunState(RunState.Stopped);
logger.info(() -> "stopped: " + this.getActivityDef().getAlias() + " with " + motors.size() + " slots"); logger.info(() -> "stopped: " + activity.getAlias() + " with " + motors.size() + " slots");
Annotators.recordAnnotation(Annotation.newBuilder() Annotators.recordAnnotation(Annotation.newBuilder()
.element(this) .element(this)
.interval(this.startedAt, this.stoppedAt) .interval(this.startedAt, this.stoppedAt)
.layer(Layer.Activity) .layer(Layer.Activity)
.addDetail("params", getActivityDef().toString()) .addDetail("params", String.valueOf(activity.getConfigModel()))
.build() .build()
); );
} }
public Exception forceStopActivity(int initialMillisToWait) { public Exception forceStopActivity(int initialMillisToWait) {
activitylogger.debug("FORCE STOP/before alias=(" + activity.getActivityDef().getAlias() + activitylogger.debug("FORCE STOP/before alias=(" + activity.getAlias() + ")");
")");
activity.setRunState(RunState.Stopped); activity.setRunState(RunState.Stopped);
executorService.shutdownNow(); executorService.shutdownNow();
@ -205,36 +207,10 @@ public class ActivityExecutor implements NBLabeledElement, ParameterMap.Listener
} }
} }
/**
* Listens for changes to parameter maps, maps them to the activity instance, and notifies all eligible listeners of
* changes.
*/
@Override
public void handleParameterMapUpdate(ParameterMap parameterMap) {
activity.onActivityDefUpdate(activityDef);
// An activity must be initialized before the motors and other components are
// considered ready to handle parameter map changes. This is signaled in an activity
// by the RunState.
if (activity.getRunState() != RunState.Uninitialized) {
if (activity.getRunState() == RunState.Running) {
adjustMotorCountToThreadParam(activity.getActivityDef());
}
motors.stream()
.filter(m -> (m instanceof ActivityDefObserver))
// .filter(m -> m.getSlotStateTracker().getSlotState() != RunState.Uninitialized)
// .filter(m -> m.getSlotStateTracker().getSlotState() != RunState.Starting)
.forEach(m -> ((ActivityDefObserver) m).onActivityDefUpdate(activityDef));
}
}
public ActivityDef getActivityDef() {
return activityDef;
}
public String toString() { public String toString() {
return getClass().getSimpleName() + "~" + activityDef.getAlias(); return getClass().getSimpleName() + "~" + config.getAlias();
} }
private String getSlotStatus() { private String getSlotStatus() {
@ -243,17 +219,12 @@ public class ActivityExecutor implements NBLabeledElement, ParameterMap.Listener
.collect(Collectors.joining(",", "[", "]")); .collect(Collectors.joining(",", "[", "]"));
} }
/** private void adjustMotorCountToThreadParam(int threadCount) { // TODO: Ensure that threads area
* Stop extra motors, start missing motors // allowed to complete their current op gracefully
*
* @param activityDef
* the activityDef for this activity instance
*/
private void adjustMotorCountToThreadParam(ActivityDef activityDef) { // TODO: Ensure that threads area allowed to complete their current op gracefully
logger.trace(() -> ">-pre-adjust->" + getSlotStatus()); logger.trace(() -> ">-pre-adjust->" + getSlotStatus());
reduceActiveMotorCountDownToThreadParam(activityDef); reduceActiveMotorCountDownToThreadParam();
increaseActiveMotorCountUpToThreadParam(activityDef); increaseActiveMotorCountUpToThreadParam();
alignMotorStateToIntendedActivityState(); alignMotorStateToIntendedActivityState();
awaitAlignmentOfMotorStateToActivityState(); awaitAlignmentOfMotorStateToActivityState();
@ -261,11 +232,11 @@ public class ActivityExecutor implements NBLabeledElement, ParameterMap.Listener
} }
private void increaseActiveMotorCountUpToThreadParam(ActivityDef activityDef) { private void increaseActiveMotorCountUpToThreadParam() {
// Create motor slots // Create motor slots
try { try {
while (motors.size() < activityDef.getThreads()) { while (motors.size() < config.getThreads()) {
Motor motor = motorSource.getMotor(activityDef, motors.size()); Motor motor = motorSource.getMotor(config, motors.size());
logger.trace(() -> "Starting cycle motor thread:" + motor); logger.trace(() -> "Starting cycle motor thread:" + motor);
motors.add(motor); motors.add(motor);
} }
@ -276,24 +247,12 @@ public class ActivityExecutor implements NBLabeledElement, ParameterMap.Listener
} }
} }
private void reduceActiveMotorCountDownToThreadParam(ActivityDef activityDef) { private void reduceActiveMotorCountDownToThreadParam() {
// Stop and remove extra motor slots // Stop and remove extra motor slots
if (activityDef.getThreads()==0) { if (config.getThreads()==0) {
logger.warn("setting threads to zero is not advised. At least one thread has to be active to keep the activity alive."); logger.warn("setting threads to zero is not advised. At least one thread has to be active to keep the activity alive.");
} }
// LinkedList<Motor<?>> toremove = new LinkedList<>(); while (motors.size() > config.getThreads()) {
// while (activityDef.getThreads()>motors.size()) {
// Motor<?> motor = motors.removeLast();
// toremove.addFirst(motor);
// }
// for (Motor<?> motor : toremove) {
// motor.requestStop();
// }
// for (Motor<?> motor : toremove) {
// motor.removeState();
// }
//
while (motors.size() > activityDef.getThreads()) {
Motor motor = motors.get(motors.size() - 1); Motor motor = motors.get(motors.size() - 1);
logger.trace(() -> "Stopping cycle motor thread:" + motor); logger.trace(() -> "Stopping cycle motor thread:" + motor);
motor.requestStop(); motor.requestStop();
@ -408,7 +367,7 @@ public class ActivityExecutor implements NBLabeledElement, ParameterMap.Listener
.now() .now()
.layer(Layer.Activity) .layer(Layer.Activity)
.addDetail("event", "start-activity") .addDetail("event", "start-activity")
.addDetail("params", activityDef.toString()) .addDetail("params", String.valueOf(activity.getConfig()))
.build()); .build());
try { try {
@ -419,7 +378,7 @@ public class ActivityExecutor implements NBLabeledElement, ParameterMap.Listener
registerMetrics(); registerMetrics();
startRunningActivityThreads(); startRunningActivityThreads();
awaitMotorsAtLeastRunning(); awaitMotorsAtLeastRunning();
logger.debug("STARTED " + activityDef.getAlias()); logger.debug("STARTED " + config.getAlias());
awaitActivityCompletion(); awaitActivityCompletion();
} catch (Exception e) { } catch (Exception e) {
this.exception = e; this.exception = e;
@ -544,12 +503,12 @@ public class ActivityExecutor implements NBLabeledElement, ParameterMap.Listener
*/ */
private void startRunningActivityThreads() { private void startRunningActivityThreads() {
logger.info(() -> "starting activity " + activity.getAlias() + " for cycles " + activity.getActivityDef().getCycleSummary()); logger.info(() -> "starting activity " + activity.getAlias() + " for cycles " + activity.getCyclesSpec().summary());
Annotators.recordAnnotation(Annotation.newBuilder() Annotators.recordAnnotation(Annotation.newBuilder()
.element(this) .element(this)
.now() .now()
.layer(Layer.Activity) .layer(Layer.Activity)
.addDetail("params", getActivityDef().toString()) .addDetail("params", activity.getConfig().summary())
.build() .build()
); );
@ -558,13 +517,12 @@ public class ActivityExecutor implements NBLabeledElement, ParameterMap.Listener
try { try {
activity.setRunState(RunState.Starting); activity.setRunState(RunState.Starting);
this.startedAt = System.currentTimeMillis(); this.startedAt = System.currentTimeMillis();
activity.onActivityDefUpdate(activityDef);
} catch (Exception e) { } catch (Exception e) {
this.exception = new RuntimeException("Error initializing activity '" + activity.getAlias() + "':\n" + e.getMessage(), e); this.exception = new RuntimeException("Error initializing activity '" + activity.getAlias() + "':\n" + e.getMessage(), e);
activitylogger.error(() -> "error initializing activity '" + activity.getAlias() + "': " + exception); activitylogger.error(() -> "error initializing activity '" + activity.getAlias() + "': " + exception);
throw new RuntimeException(exception); throw new RuntimeException(exception);
} }
adjustMotorCountToThreadParam(activity.getActivityDef()); adjustMotorCountToThreadParam(activity.getConfig().getThreads());
tally.awaitAny(RunState.Running, RunState.Finished, RunState.Stopped); tally.awaitAny(RunState.Running, RunState.Finished, RunState.Stopped);
activity.setRunState(RunState.Running); activity.setRunState(RunState.Running);
activitylogger.debug("START/after alias=(" + activity.getAlias() + ")"); activitylogger.debug("START/after alias=(" + activity.getAlias() + ")");
@ -592,7 +550,7 @@ public class ActivityExecutor implements NBLabeledElement, ParameterMap.Listener
.interval(startedAt, stoppedAt) .interval(startedAt, stoppedAt)
.layer(Layer.Activity) .layer(Layer.Activity)
.addDetail("event", "stop-activity") .addDetail("event", "stop-activity")
.addDetail("params", activityDef.toString()) .addDetail("params", config.toString())
.build()); .build());
} }
@ -605,6 +563,39 @@ public class ActivityExecutor implements NBLabeledElement, ParameterMap.Listener
return image.isNoneOther(RunState.Running); return image.isNoneOther(RunState.Running);
} }
@Override
public void applyReconfig(NBConfiguration recfg) {
// An activity must be initialized before the motors and other components are
// considered ready to handle parameter map changes. This is signaled in an activity
// by the RunState.
if (activity.getRunState() != RunState.Uninitialized) {
if (activity.getRunState() == RunState.Running) {
adjustMotorCountToThreadParam(activity.getConfig().getThreads());
}
motors.stream()
.filter(m -> (m instanceof NBReconfigurable reconf))
.forEach(r -> ((NBReconfigurable) r).applyReconfig(recfg));
}
}
@Override
public NBConfigModel getReconfigModel() {
return null;
}
@Override
public void applyConfig(NBConfiguration cfg) {
}
@Override
public NBConfigModel getConfigModel() {
return null;
}
private class ThreadsGauge implements Gauge<Double> { private class ThreadsGauge implements Gauge<Double> {
public ThreadsGauge(ActivityExecutor activityExecutor) { public ThreadsGauge(ActivityExecutor activityExecutor) {
ActivityExecutor ae = activityExecutor; ActivityExecutor ae = activityExecutor;

View File

@ -17,7 +17,7 @@
package io.nosqlbench.engine.core.lifecycle.activity; package io.nosqlbench.engine.core.lifecycle.activity;
import io.nosqlbench.engine.api.activityimpl.uniform.Activity; import io.nosqlbench.engine.api.activityimpl.uniform.Activity;
import io.nosqlbench.nb.api.engine.activityimpl.ActivityDef; import io.nosqlbench.nb.api.engine.activityimpl.ActivityConfig;
import io.nosqlbench.nb.api.components.core.NBComponent; import io.nosqlbench.nb.api.components.core.NBComponent;
import io.nosqlbench.engine.api.activityimpl.uniform.StandardActivityType; import io.nosqlbench.engine.api.activityimpl.uniform.StandardActivityType;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
@ -27,10 +27,9 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
/** /**
* Consolidates the activity type and activity instantiation logic into one place Consolidates the activity type and activity instantiation logic into one place
* per scope. Within the lifetime of this ActivityLoader, all activities may per scope. Within the lifetime of this ActivityLoader, all activities may
* see each other by name. see each other by name. */
*/
public class ActivityLoader { public class ActivityLoader {
private static final Logger logger = LogManager.getLogger("ACTIVITIES"); private static final Logger logger = LogManager.getLogger("ACTIVITIES");
private final Map<String, Activity> activityMap = new ConcurrentHashMap<>(); private final Map<String, Activity> activityMap = new ConcurrentHashMap<>();
@ -38,10 +37,14 @@ public class ActivityLoader {
public ActivityLoader() { public ActivityLoader() {
} }
public synchronized Activity loadActivity(ActivityDef activityDef, final NBComponent parent) { public synchronized Activity loadActivity(
activityDef= activityDef.deprecate("yaml","workload").deprecate("type","driver"); ActivityConfig activityDef,
final Activity activity = final NBComponent parent
new StandardActivityType<>(activityDef, parent).getAssembledActivity(parent, activityDef, this.activityMap);this.activityMap.put(activity.getAlias(),activity); )
{
final Activity activity = new StandardActivityType<>(
activityDef, parent).getAssembledActivity(parent, activityDef, this.activityMap);
this.activityMap.put(activity.getAlias(), activity);
ActivityLoader.logger.debug("Resolved activity for alias '{}'", activityDef.getAlias()); ActivityLoader.logger.debug("Resolved activity for alias '{}'", activityDef.getAlias());
return activity; return activity;
} }

View File

@ -19,9 +19,9 @@ package io.nosqlbench.engine.core.lifecycle.activity;
import io.nosqlbench.adapter.diag.DriverAdapterLoader; import io.nosqlbench.adapter.diag.DriverAdapterLoader;
import io.nosqlbench.adapters.api.activityimpl.uniform.DriverAdapter; import io.nosqlbench.adapters.api.activityimpl.uniform.DriverAdapter;
import io.nosqlbench.nb.api.components.core.NBComponent; import io.nosqlbench.nb.api.components.core.NBComponent;
import io.nosqlbench.nb.api.engine.activityimpl.ActivityConfig;
import io.nosqlbench.nb.api.nbio.Content; import io.nosqlbench.nb.api.nbio.Content;
import io.nosqlbench.nb.api.nbio.NBIO; import io.nosqlbench.nb.api.nbio.NBIO;
import io.nosqlbench.nb.api.engine.activityimpl.ActivityDef;
import io.nosqlbench.nb.api.errors.BasicError; import io.nosqlbench.nb.api.errors.BasicError;
import io.nosqlbench.nb.api.spi.SimpleServiceLoader; import io.nosqlbench.nb.api.spi.SimpleServiceLoader;
import io.nosqlbench.nb.api.system.NBEnvironment; import io.nosqlbench.nb.api.system.NBEnvironment;
@ -118,29 +118,33 @@ public class ActivityTypeLoader {
return urlsToAdd; return urlsToAdd;
} }
public Optional<StandardActivityType> load(final ActivityDef activityDef, final NBComponent parent) { public Optional<StandardActivityType> load(
final ActivityConfig activityDef,
final NBComponent parent
)
{
String driverName = activityDef.getParams() String driverName = activityDef.getDriver()
.getOptionalString("driver", "type")
.orElseThrow(() -> new BasicError("The parameter 'driver=' is required.")); .orElseThrow(() -> new BasicError("The parameter 'driver=' is required."));
activityDef.getParams() activityDef.getOptional("jar").map(jar -> {
.getOptionalString("jar") final Set<URL> urls = NBIO.local().search(jar).list().stream().map(Content::getURL)
.map(jar -> { .collect(Collectors.toSet());
final Set<URL> urls = NBIO.local().search(jar) return urls;
.list() }).ifPresent(this::extendClassLoader);
.stream().map(Content::getURL)
.collect(Collectors.toSet());
return urls;
})
.ifPresent(this::extendClassLoader);
return getDriverAdapter(driverName,activityDef,parent); return getDriverAdapter(driverName,activityDef,parent);
} }
private Optional<StandardActivityType> getDriverAdapter(final String activityTypeName, final ActivityDef activityDef, final NBComponent parent) { private Optional<StandardActivityType> getDriverAdapter(
final Optional<DriverAdapter> oda = this.DRIVERADAPTER_SPI_FINDER.getOptionally(activityTypeName); final String activityTypeName,
final ActivityConfig activityDef,
final NBComponent parent
)
{
final Optional<DriverAdapter> oda = this.DRIVERADAPTER_SPI_FINDER.getOptionally(
activityTypeName);
if (oda.isPresent()) { if (oda.isPresent()) {
final DriverAdapter<?, ?> driverAdapter = oda.get(); final DriverAdapter<?, ?> driverAdapter = oda.get();

View File

@ -44,7 +44,7 @@ public class CMD_stop extends NBBaseCommand {
= params.maybeGet("activity").orElseThrow( = params.maybeGet("activity").orElseThrow(
() -> new RuntimeException("The stop command requires an 'activity' parameter") () -> new RuntimeException("The stop command requires an 'activity' parameter")
); );
Optional<Activity> activity = controller.getActivity(activityName); Optional<Activity> activity = controller.getOptionalActivity(activityName);
if (activity.isEmpty()) { if (activity.isEmpty()) {
BasicError error = new BasicError("Activity '" + activityName + "' was not found for stop command."); BasicError error = new BasicError("Activity '" + activityName + "' was not found for stop command.");
logger.warn(error); logger.warn(error);

View File

@ -16,7 +16,8 @@
package io.nosqlbench.engine.core.lifecycle.scenario.container; package io.nosqlbench.engine.core.lifecycle.scenario.container;
import io.nosqlbench.engine.api.activityimpl.uniform.Activity; import io.nosqlbench.engine.api.activityimpl.uniform.Activity;
import io.nosqlbench.nb.api.engine.activityimpl.ActivityDef; import io.nosqlbench.nb.api.config.standard.NBConfigModel;
import io.nosqlbench.nb.api.engine.activityimpl.ActivityConfig;
import io.nosqlbench.nb.api.engine.activityimpl.ParameterMap; import io.nosqlbench.nb.api.engine.activityimpl.ParameterMap;
import io.nosqlbench.nb.api.components.core.NBComponent; import io.nosqlbench.nb.api.components.core.NBComponent;
import io.nosqlbench.nb.api.components.core.NBBaseComponent; import io.nosqlbench.nb.api.components.core.NBBaseComponent;
@ -46,9 +47,7 @@ public class ContainerActivitiesController extends NBBaseComponent {
private static final Logger scenariologger = LogManager.getLogger("SCENARIO"); private static final Logger scenariologger = LogManager.getLogger("SCENARIO");
private final ActivityLoader activityLoader; private final ActivityLoader activityLoader;
private final Map<String, ActivityRuntimeInfo> activityInfoMap = new ConcurrentHashMap<>(); private final Map<String, ActivityRuntimeInfo> activityInfoMap = new ConcurrentHashMap<>();
private final ExecutorService executorService; private final ExecutorService executorService;
public ContainerActivitiesController(NBComponent parent) { public ContainerActivitiesController(NBComponent parent) {
@ -63,17 +62,17 @@ public class ContainerActivitiesController extends NBBaseComponent {
* Start an activity, given the activity definition for it. The activity will be known in the scenario * Start an activity, given the activity definition for it. The activity will be known in the scenario
* by the alias parameter. * by the alias parameter.
* *
* @param activityDef string in alias=value1;driver=value2;... format * @param ActivityConfig string in alias=value1;driver=value2;... format
*/ */
public Activity start(ActivityDef activityDef) { public Activity start(ActivityConfig ActivityConfig) {
ActivityRuntimeInfo ari = doStartActivity(activityDef); ActivityRuntimeInfo ari = doStartActivity(ActivityConfig);
return ari.getActivity(); return ari.getActivity();
} }
private ActivityRuntimeInfo doStartActivity(ActivityDef activityDef) { private ActivityRuntimeInfo doStartActivity(ActivityConfig ActivityConfig) {
if (!this.activityInfoMap.containsKey(activityDef.getAlias())) { if (!this.activityInfoMap.containsKey(ActivityConfig.getAlias())) {
Activity activity = this.activityLoader.loadActivity(activityDef, this); Activity activity = this.activityLoader.loadActivity(ActivityConfig, this);
activity.initActivity(); activity.initActivity();
ActivityExecutor executor = new ActivityExecutor(activity); ActivityExecutor executor = new ActivityExecutor(activity);
Future<ExecutionResult> startedActivity = executorService.submit(executor); Future<ExecutionResult> startedActivity = executorService.submit(executor);
@ -82,17 +81,17 @@ public class ContainerActivitiesController extends NBBaseComponent {
this.activityInfoMap.put(activity.getAlias(), activityRuntimeInfo); this.activityInfoMap.put(activity.getAlias(), activityRuntimeInfo);
} }
return this.activityInfoMap.get(activityDef.getAlias()); return this.activityInfoMap.get(ActivityConfig.getAlias());
} }
/** /**
* Start an activity, given a map which holds the activity definition for it. The activity will be known in * Start an activity, given a map which holds the activity definition for it. The activity will be known in
* the scenario by the alias parameter. * the scenario by the alias parameter.
* *
* @param activityDefMap A map containing the activity definition * @param activityParams A map containing the activity definition
*/ */
public Activity start(Map<String, String> activityDefMap) { public Activity start(Map<String, String> activityParams) {
ActivityDef ad = new ActivityDef(new ParameterMap(activityDefMap)); ActivityConfig ad = Activity.configFor(activityParams);
Activity started = start(ad); Activity started = start(ad);
awaitAllThreadsOnline(started,30000L); awaitAllThreadsOnline(started,30000L);
return started; return started;
@ -105,11 +104,11 @@ public class ContainerActivitiesController extends NBBaseComponent {
* @param alias the alias of an activity that is already known to the scenario * @param alias the alias of an activity that is already known to the scenario
*/ */
public Activity start(String alias) { public Activity start(String alias) {
return start(ActivityDef.parseActivityDef(alias)); return start(Activity.configFor(Map.of("alias",alias)));
} }
public synchronized void run(int timeout, Map<String, String> activityDefMap) { public synchronized void run(int timeout, Map<String, String> activityParams) {
ActivityDef ad = new ActivityDef(new ParameterMap(activityDefMap)); ActivityConfig ad = Activity.configFor(activityParams);
run(ad, timeout); run(ad, timeout);
} }
@ -117,30 +116,32 @@ public class ContainerActivitiesController extends NBBaseComponent {
* Synchronously run the defined activity with a timeout in seconds. * Synchronously run the defined activity with a timeout in seconds.
* *
* @param timeoutMs seconds to await completion of the activity. * @param timeoutMs seconds to await completion of the activity.
* @param activityDef A definition for an activity to run * @param ActivityConfig A definition for an activity to run
*/ */
public synchronized void run(ActivityDef activityDef, long timeoutMs) { public synchronized void run(ActivityConfig ActivityConfig, long timeoutMs) {
doStartActivity(activityDef); doStartActivity(ActivityConfig);
awaitActivity(activityDef, timeoutMs); awaitActivity(ActivityConfig, timeoutMs);
} }
public synchronized void run(int timeout, String activityDefString) { public synchronized void run(int timeout, String ActivityConfigString) {
ActivityDef activityDef = ActivityDef.parseActivityDef(activityDefString); Map<String, String> stringStringMap = ParameterMap.parseParams(ActivityConfigString)
run(activityDef, timeout); .map(p -> p.getStringStringMap()).orElseThrow();
ActivityConfig activityConfig = Activity.configFor(stringStringMap);
run(activityConfig, timeout);
} }
public synchronized void run(Map<String, String> activityDefMap) { public synchronized void run(Map<String, String> ActivityConfigMap) {
run(Integer.MAX_VALUE, activityDefMap); run(Integer.MAX_VALUE, ActivityConfigMap);
} }
public synchronized void run(String activityDefString) { public synchronized void run(String ActivityConfigString) {
run(Integer.MAX_VALUE, activityDefString); run(Integer.MAX_VALUE, ActivityConfigString);
} }
public synchronized void run(ActivityDef activityDef) { public synchronized void run(ActivityConfig ActivityConfig) {
run(activityDef, Long.MAX_VALUE); run(ActivityConfig, Long.MAX_VALUE);
} }
@ -148,13 +149,13 @@ public class ContainerActivitiesController extends NBBaseComponent {
return isRunningActivity(aliasToDef(alias)); return isRunningActivity(aliasToDef(alias));
} }
public boolean isRunningActivity(ActivityDef activityDef) { public boolean isRunningActivity(ActivityConfig ActivityConfig) {
ActivityRuntimeInfo runtimeInfo = this.activityInfoMap.get(activityDef.getAlias()); ActivityRuntimeInfo runtimeInfo = this.activityInfoMap.get(ActivityConfig.getAlias());
return (null != runtimeInfo) && runtimeInfo.isRunning(); return (null != runtimeInfo) && runtimeInfo.isRunning();
} }
public boolean isRunningActivity(Map<String, String> activityDefMap) { public boolean isRunningActivity(Map<String, String> activityParams) {
ActivityDef ad = new ActivityDef(new ParameterMap(activityDefMap)); ActivityConfig ad = Activity.configFor(activityParams);
return isRunningActivity(ad); return isRunningActivity(ad);
} }
@ -163,36 +164,36 @@ public class ContainerActivitiesController extends NBBaseComponent {
* alias parameter. This method retains the activity def signature to provide convenience for scripting.</p> * alias parameter. This method retains the activity def signature to provide convenience for scripting.</p>
* <p>For example, sc.stop("alias=foo")</p> * <p>For example, sc.stop("alias=foo")</p>
* *
* @param activityDef An activity def, including at least the alias parameter. * @param ActivityConfig An activity def, including at least the alias parameter.
*/ */
public synchronized void stop(ActivityDef activityDef) { public synchronized void stop(ActivityConfig ActivityConfig) {
ActivityRuntimeInfo runtimeInfo = this.activityInfoMap.get(activityDef.getAlias()); ActivityRuntimeInfo runtimeInfo = this.activityInfoMap.get(ActivityConfig.getAlias());
if (null == runtimeInfo) { if (null == runtimeInfo) {
throw new RuntimeException("could not stop missing activity:" + activityDef); throw new RuntimeException("could not stop missing activity:" + ActivityConfig);
} }
scenariologger.debug("STOP {}", activityDef.getAlias()); scenariologger.debug("STOP {}", ActivityConfig.getAlias());
runtimeInfo.stopActivity(); runtimeInfo.stopActivity();
} }
public boolean awaitAllThreadsOnline(ActivityDef activityDef, long timeoutMs) { public boolean awaitAllThreadsOnline(ActivityConfig ActivityConfig, long timeoutMs) {
ActivityRuntimeInfo runtimeInfo = this.activityInfoMap.get(activityDef.getAlias()); ActivityRuntimeInfo runtimeInfo = this.activityInfoMap.get(ActivityConfig.getAlias());
if (null == runtimeInfo) { if (null == runtimeInfo) {
throw new RuntimeException("could not stop missing activity:" + activityDef); throw new RuntimeException("could not stop missing activity:" + ActivityConfig);
} }
scenariologger.debug("STOP {}", activityDef.getAlias()); scenariologger.debug("STOP {}", ActivityConfig.getAlias());
return runtimeInfo.awaitAllThreadsOnline(timeoutMs); return runtimeInfo.awaitAllThreadsOnline(timeoutMs);
} }
public synchronized void stop(Activity activity) { public synchronized void stop(Activity activity) {
stop(activity.getActivityDef()); stop(activity.getConfig());
} }
public boolean awaitAllThreadsOnline(Activity activity, long timeoutMs) { public boolean awaitAllThreadsOnline(Activity activity, long timeoutMs) {
return awaitAllThreadsOnline(activity.getActivityDef(), timeoutMs); return awaitAllThreadsOnline(activity.getConfig(), timeoutMs);
} }
@ -201,10 +202,10 @@ public class ContainerActivitiesController extends NBBaseComponent {
* <p>Stop an activity, given an activity def map. The only part of the map that is important is the * <p>Stop an activity, given an activity def map. The only part of the map that is important is the
* alias parameter. This method retains the map signature to provide convenience for scripting.</p> * alias parameter. This method retains the map signature to provide convenience for scripting.</p>
* *
* @param activityDefMap A map, containing at least the alias parameter * @param paramsMap A map, containing at least the alias parameter
*/ */
public synchronized void stop(Map<String, String> activityDefMap) { public synchronized void stop(Map<String, String> paramsMap) {
ActivityDef ad = new ActivityDef(new ParameterMap(activityDefMap)); ActivityConfig ad = Activity.configFor(paramsMap);
stop(ad); stop(ad);
} }
@ -225,7 +226,7 @@ public class ContainerActivitiesController extends NBBaseComponent {
.filter(s -> !s.isEmpty()) .filter(s -> !s.isEmpty())
.flatMap(aspec -> getMatchingAliases(aspec).stream()).collect(Collectors.toList()); .flatMap(aspec -> getMatchingAliases(aspec).stream()).collect(Collectors.toList());
for (String alias : matched) { for (String alias : matched) {
ActivityDef adef = aliasToDef(alias); ActivityConfig adef = aliasToDef(alias);
scenariologger.debug("STOP {}", adef.getAlias()); scenariologger.debug("STOP {}", adef.getAlias());
stop(adef); stop(adef);
} }
@ -236,16 +237,16 @@ public class ContainerActivitiesController extends NBBaseComponent {
* alias parameter. This method retains the activity def signature to provide convenience for scripting.</p> * alias parameter. This method retains the activity def signature to provide convenience for scripting.</p>
* <p>For example, sc.forceStop("alias=foo")</p> * <p>For example, sc.forceStop("alias=foo")</p>
* *
* @param activityDef An activity def, including at least the alias parameter. * @param ActivityConfig An activity def, including at least the alias parameter.
*/ */
public synchronized void forceStop(ActivityDef activityDef) { public synchronized void forceStop(ActivityConfig ActivityConfig) {
ActivityRuntimeInfo runtimeInfo = this.activityInfoMap.get(activityDef.getAlias()); ActivityRuntimeInfo runtimeInfo = this.activityInfoMap.get(ActivityConfig.getAlias());
if (null == runtimeInfo) { if (null == runtimeInfo) {
throw new RuntimeException("could not force stop missing activity:" + activityDef); throw new RuntimeException("could not force stop missing activity:" + ActivityConfig);
} }
scenariologger.debug("FORCE STOP {}", activityDef.getAlias()); scenariologger.debug("FORCE STOP {}", ActivityConfig.getAlias());
runtimeInfo.forceStopActivity(); runtimeInfo.forceStopActivity();
} }
@ -254,10 +255,10 @@ public class ContainerActivitiesController extends NBBaseComponent {
* <p>Stop an activity, given an activity def map. The only part of the map that is important is the * <p>Stop an activity, given an activity def map. The only part of the map that is important is the
* alias parameter. This method retains the map signature to provide convenience for scripting.</p> * alias parameter. This method retains the map signature to provide convenience for scripting.</p>
* *
* @param activityDefMap A map, containing at least the alias parameter * @param activityParams A map, containing at least the alias parameter
*/ */
public synchronized void forceStop(Map<String, String> activityDefMap) { public synchronized void forceStop(Map<String, String> activityParams) {
ActivityDef ad = new ActivityDef(new ParameterMap(activityDefMap)); ActivityConfig ad = Activity.configFor(activityParams);
forceStop(ad); forceStop(ad);
} }
@ -278,7 +279,7 @@ public class ContainerActivitiesController extends NBBaseComponent {
.filter(s -> !s.isEmpty()) .filter(s -> !s.isEmpty())
.flatMap(aspec -> getMatchingAliases(aspec).stream()).collect(Collectors.toList()); .flatMap(aspec -> getMatchingAliases(aspec).stream()).collect(Collectors.toList());
for (String alias : matched) { for (String alias : matched) {
ActivityDef adef = aliasToDef(alias); ActivityConfig adef = aliasToDef(alias);
scenariologger.debug("STOP {}", adef.getAlias()); scenariologger.debug("STOP {}", adef.getAlias());
forceStop(adef); forceStop(adef);
} }
@ -376,19 +377,17 @@ public class ContainerActivitiesController extends NBBaseComponent {
return completed; return completed;
} }
private ActivityDef aliasToDef(String alias) { private ActivityConfig aliasToDef(String alias) {
if (alias.contains("=")) { String cfg = alias.contains("=") ? alias : "alias=" + alias;
return ActivityDef.parseActivityDef(alias); return Activity.configFor(ParameterMap.parseOrException(cfg).getStringStringMap());
}
return ActivityDef.parseActivityDef("alias=" + alias + ';');
} }
public void await(Map<String, String> activityDefMap) { public void await(Map<String, String> ActivityConfigMap) {
this.awaitActivity(activityDefMap); this.awaitActivity(ActivityConfigMap);
} }
public boolean awaitActivity(Map<String, String> activityDefMap) { public boolean awaitActivity(Map<String, String> activityParams) {
ActivityDef ad = new ActivityDef(new ParameterMap(activityDefMap)); ActivityConfig ad = Activity.configFor(activityParams);
return awaitActivity(ad, Long.MAX_VALUE); return awaitActivity(ad, Long.MAX_VALUE);
} }
@ -397,21 +396,21 @@ public class ContainerActivitiesController extends NBBaseComponent {
} }
public boolean awaitActivity(String alias, long timeoutMs) { public boolean awaitActivity(String alias, long timeoutMs) {
ActivityDef toAwait = aliasToDef(alias); ActivityConfig toAwait = aliasToDef(alias);
return awaitActivity(toAwait, Long.MAX_VALUE); return awaitActivity(toAwait, Long.MAX_VALUE);
} }
public void await(ActivityDef activityDef, long timeoutMs) { public void await(ActivityConfig ActivityConfig, long timeoutMs) {
this.awaitActivity(activityDef, timeoutMs); this.awaitActivity(ActivityConfig, timeoutMs);
} }
public boolean awaitActivity(ActivityDef activityDef, long timeoutMs) { public boolean awaitActivity(ActivityConfig ActivityConfig, long timeoutMs) {
ActivityRuntimeInfo ari = this.activityInfoMap.get(activityDef.getAlias()); ActivityRuntimeInfo ari = this.activityInfoMap.get(ActivityConfig.getAlias());
if (null == ari) { if (null == ari) {
throw new RuntimeException("Could not await missing activity: " + activityDef.getAlias()); throw new RuntimeException("Could not await missing activity: " + ActivityConfig.getAlias());
} }
scenariologger.debug("AWAIT/before alias={}", activityDef.getAlias()); scenariologger.debug("AWAIT/before alias={}", ActivityConfig.getAlias());
ExecutionResult result = null; ExecutionResult result = null;
Future<ExecutionResult> future=null; Future<ExecutionResult> future=null;
try { try {
@ -434,8 +433,8 @@ public class ContainerActivitiesController extends NBBaseComponent {
return Collections.unmodifiableMap(activityInfoMap); return Collections.unmodifiableMap(activityInfoMap);
} }
public List<ActivityDef> getActivityDefs() { public List<ActivityConfig> getActivityConfigs() {
return activityInfoMap.values().stream().map(ari -> ari.getActivity().getActivityDef()).toList(); return activityInfoMap.values().stream().map(ari -> ari.getActivity().getConfig()).toList();
} }
public void reportMetrics() { public void reportMetrics() {
@ -448,7 +447,11 @@ public class ContainerActivitiesController extends NBBaseComponent {
} }
return Optional.empty(); return Optional.empty();
} }
public Optional<Activity> getActivity(String activityName) { public Activity getActivity(String activityName) {
return getOptionalActivity(activityName).orElseThrow(() -> new RuntimeException("Unable " +
"to find required activity by name: '" + activityName + "'"));
}
public Optional<Activity> getOptionalActivity(String activityName) {
return Optional.ofNullable(this.activityInfoMap.get(activityName)).map(ActivityRuntimeInfo::getActivity); return Optional.ofNullable(this.activityInfoMap.get(activityName)).map(ActivityRuntimeInfo::getActivity);
} }
@ -469,8 +472,8 @@ public class ContainerActivitiesController extends NBBaseComponent {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
public ActivityDef getActivityDef(String alias) { public ActivityConfig getActivityConfig(String alias) {
return activityInfoMap.get(alias).getActivity().getActivityDef(); return activityInfoMap.get(alias).getActivity().getConfig();
} }
public void shutdown() { public void shutdown() {

View File

@ -17,7 +17,7 @@
package io.nosqlbench.engine.core.lifecycle.scenario.script.bindings; package io.nosqlbench.engine.core.lifecycle.scenario.script.bindings;
import io.nosqlbench.engine.core.lifecycle.scenario.container.ContainerActivitiesController; import io.nosqlbench.engine.core.lifecycle.scenario.container.ContainerActivitiesController;
import io.nosqlbench.nb.api.engine.activityimpl.ActivityDef; import io.nosqlbench.nb.api.engine.activityimpl.ActivityConfig;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.graalvm.polyglot.Value; import org.graalvm.polyglot.Value;
@ -88,8 +88,8 @@ public class PolyglotScenarioController {
controller.run(timeout, spec.as(Map.class)); controller.run(timeout, spec.as(Map.class));
} else if (spec.isHostObject()) { } else if (spec.isHostObject()) {
Object o = spec.asHostObject(); Object o = spec.asHostObject();
if (o instanceof ActivityDef) { if (o instanceof ActivityConfig) {
controller.run((ActivityDef) o, timeout); controller.run((ActivityConfig) o, timeout);
} else { } else {
throw new RuntimeException("unrecognized polyglot host object type for run: " + spec); throw new RuntimeException("unrecognized polyglot host object type for run: " + spec);
} }
@ -113,7 +113,7 @@ public class PolyglotScenarioController {
private synchronized void startValue(Value spec) { private synchronized void startValue(Value spec) {
if (spec.isHostObject()) { if (spec.isHostObject()) {
controller.start((ActivityDef) spec.asHostObject()); controller.start((ActivityConfig) spec.asHostObject());
} else if (spec.isString()) { } else if (spec.isString()) {
controller.start(spec.asString()); controller.start(spec.asString());
} else if (spec.hasMembers()) { } else if (spec.hasMembers()) {
@ -137,7 +137,7 @@ public class PolyglotScenarioController {
private synchronized void stopValue(Value spec) { private synchronized void stopValue(Value spec) {
if (spec.isHostObject()) { if (spec.isHostObject()) {
controller.stop((ActivityDef) spec.asHostObject()); controller.stop((ActivityConfig) spec.asHostObject());
} else if (spec.isString()) { } else if (spec.isString()) {
controller.stop(spec.asString()); controller.stop(spec.asString());
} else if (spec.hasMembers()) { } else if (spec.hasMembers()) {
@ -162,7 +162,7 @@ public class PolyglotScenarioController {
private synchronized void forceStopValue(Value spec) { private synchronized void forceStopValue(Value spec) {
if (spec.isHostObject()) { if (spec.isHostObject()) {
controller.forceStop((ActivityDef) spec.asHostObject()); controller.forceStop((ActivityConfig) spec.asHostObject());
} else if (spec.isString()) { } else if (spec.isString()) {
controller.forceStop(spec.asString()); controller.forceStop(spec.asString());
} else if (spec.hasMembers()) { } else if (spec.hasMembers()) {
@ -239,7 +239,7 @@ public class PolyglotScenarioController {
private synchronized boolean isRunningActivityValue(Value spec) { private synchronized boolean isRunningActivityValue(Value spec) {
if (spec.isHostObject()) { if (spec.isHostObject()) {
return controller.isRunningActivity((ActivityDef) spec.asHostObject()); return controller.isRunningActivity((ActivityConfig) spec.asHostObject());
} else if (spec.isString()) { } else if (spec.isString()) {
return controller.isRunningActivity(spec.asString()); return controller.isRunningActivity(spec.asString());
} else if (spec.hasMembers()) { } else if (spec.hasMembers()) {

View File

@ -25,7 +25,7 @@ import io.nosqlbench.engine.core.lifecycle.scenario.execution.NBCommandResult;
import io.nosqlbench.engine.core.lifecycle.scenario.execution.NBInvokableCommand; import io.nosqlbench.engine.core.lifecycle.scenario.execution.NBInvokableCommand;
import io.nosqlbench.nb.api.components.decorators.NBTokenWords; import io.nosqlbench.nb.api.components.decorators.NBTokenWords;
import io.nosqlbench.nb.api.components.status.NBHeartbeatComponent; import io.nosqlbench.nb.api.components.status.NBHeartbeatComponent;
import io.nosqlbench.nb.api.engine.activityimpl.ActivityDef; import io.nosqlbench.nb.api.engine.activityimpl.ActivityConfig;
import io.nosqlbench.nb.api.engine.metrics.instruments.MetricCategory; import io.nosqlbench.nb.api.engine.metrics.instruments.MetricCategory;
import io.nosqlbench.nb.api.labels.NBLabeledElement; import io.nosqlbench.nb.api.labels.NBLabeledElement;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
@ -165,7 +165,7 @@ public class NBSession extends NBHeartbeatComponent implements Function<List<Cmd
for (String containerName : containers.keySet()) { for (String containerName : containers.keySet()) {
NBBufferedContainer ctx = containers.get(containerName); NBBufferedContainer ctx = containers.get(containerName);
logger.debug("awaiting end of activities in container '" + containerName + "':" + logger.debug("awaiting end of activities in container '" + containerName + "':" +
ctx.controller().getActivityDefs().stream().map(ActivityDef::getAlias).toList()); ctx.controller().getActivityConfigs().stream().map(ActivityConfig::getAlias).toList());
ctx.controller().shutdown(); ctx.controller().shutdown();
ctx.controller().awaitCompletion(Long.MAX_VALUE); ctx.controller().awaitCompletion(Long.MAX_VALUE);
logger.debug("completed"); logger.debug("completed");

View File

@ -23,7 +23,6 @@ import io.nosqlbench.nb.api.config.standard.TestComponent;
import io.nosqlbench.nb.api.labels.NBLabels; import io.nosqlbench.nb.api.labels.NBLabels;
import io.nosqlbench.nb.api.nbio.Content; import io.nosqlbench.nb.api.nbio.Content;
import io.nosqlbench.nb.api.nbio.NBIO; import io.nosqlbench.nb.api.nbio.NBIO;
import io.nosqlbench.nb.api.engine.activityimpl.ActivityDef;
import io.nosqlbench.nb.api.errors.BasicError; import io.nosqlbench.nb.api.errors.BasicError;
import io.nosqlbench.nb.annotations.Service; import io.nosqlbench.nb.annotations.Service;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;

View File

@ -16,26 +16,26 @@
package io.nosqlbench.engine.api.activityimpl; package io.nosqlbench.engine.api.activityimpl;
import io.nosqlbench.nb.api.engine.activityimpl.ActivityDef; import io.nosqlbench.engine.api.activityimpl.uniform.Activity;
import io.nosqlbench.nb.api.engine.activityimpl.ActivityConfig;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
public class ActivityDefTest { public class ActivityConfigTest {
@Test @Test
public void testSimpleCycleCount() { public void testSimpleCycleCount() {
ActivityDef d = ActivityDef.parseActivityDef("cycles=1M"); ActivityConfig config = Activity.configFor("cycles=1M");
assertThat(d.getStartCycle()).isEqualTo(0); assertThat(config.getCyclesSpec().firstSpec()).isEqualTo(0L);
assertThat(d.getEndCycle()).isEqualTo(1000000); assertThat(config.getCyclesSpec().last_exclusive()).isEqualTo(1000000L);
} }
@Test @Test
public void testCycleRange() { public void testCycleRange() {
ActivityDef d = ActivityDef.parseActivityDef("cycles=1M..5M"); ActivityConfig config = Activity.configFor("cycles=1M..5M");
assertThat(d.getStartCycle()).isEqualTo(1000000); assertThat(config.getCyclesSpec().firstSpec()).isEqualTo(1000000L);
assertThat(d.getEndCycle()).isEqualTo(5000000); assertThat(config.getCyclesSpec().last_exclusive()).isEqualTo(5000000L);
assertThat(d.getCycleCount()).isEqualTo(4000000);
} }
} }

View File

@ -16,8 +16,8 @@
package io.nosqlbench.engine.api.activityimpl.input; package io.nosqlbench.engine.api.activityimpl.input;
import io.nosqlbench.engine.api.activityimpl.uniform.Activity;
import io.nosqlbench.nb.api.config.standard.TestComponent; import io.nosqlbench.nb.api.config.standard.TestComponent;
import io.nosqlbench.nb.api.engine.activityimpl.ActivityDef;
import io.nosqlbench.engine.api.activityapi.cyclelog.buffers.results.CycleSegment; import io.nosqlbench.engine.api.activityapi.cyclelog.buffers.results.CycleSegment;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -25,16 +25,20 @@ import static org.assertj.core.api.Assertions.assertThat;
public class AtomicInputTest { public class AtomicInputTest {
private Activity activity(String cfg) {
return new Activity(new TestComponent("testing","atomicinput"),
Activity.configFor(cfg));
}
@Test @Test
public void testThatNoCyclesAndNoRecyclesMeansZero() { public void testThatNoCyclesAndNoRecyclesMeansZero() {
AtomicInput input = new AtomicInput(new TestComponent("testing","atomicinput"), ActivityDef.parseActivityDef("alias=foo;cycles=0;recycles=0")); AtomicInput input = new AtomicInput(activity("alias=foo;cycles=0;recycles=0"));
CycleSegment inputSegment = input.getInputSegment(1); CycleSegment inputSegment = input.getInputSegment(1);
assertThat(inputSegment).isNull(); assertThat(inputSegment).isNull();
} }
@Test @Test
public void testThatNoCyclesAndDefaultRecyclesMeans1xCycles() { public void testThatNoCyclesAndDefaultRecyclesMeans1xCycles() {
AtomicInput input = new AtomicInput(new TestComponent("testing","atomicinput"), ActivityDef.parseActivityDef("alias=foo;cycles=10")); AtomicInput input = new AtomicInput(activity("alias=foo;cycles=10"));
CycleSegment inputSegment =null; CycleSegment inputSegment =null;
inputSegment= input.getInputSegment(10); inputSegment= input.getInputSegment(10);
@ -51,7 +55,7 @@ public class AtomicInputTest {
int intendedRecycles=4; int intendedRecycles=4;
int stride=10; int stride=10;
AtomicInput input = new AtomicInput(new TestComponent("testing","atomicinput"), ActivityDef.parseActivityDef("alias=foo;cycles="+intendedCycles+";recycles="+intendedRecycles)); AtomicInput input = new AtomicInput(activity("alias=foo;cycles="+intendedCycles+";recycles="+intendedRecycles));
CycleSegment segment =null; CycleSegment segment =null;
for (int nextRecycle = 0; nextRecycle < intendedRecycles; nextRecycle++) { for (int nextRecycle = 0; nextRecycle < intendedRecycles; nextRecycle++) {
for (int nextCycle = 0; nextCycle < intendedCycles; nextCycle+=stride) { for (int nextCycle = 0; nextCycle < intendedCycles; nextCycle+=stride) {
@ -66,14 +70,14 @@ public class AtomicInputTest {
@Test @Test
public void testThatOneCycleAndOneRecycleYieldsOneTotal() { public void testThatOneCycleAndOneRecycleYieldsOneTotal() {
AtomicInput input = new AtomicInput(new TestComponent("testing","atomicinput"), ActivityDef.parseActivityDef("alias=foo;cycles=1;recycles=1")); AtomicInput input = new AtomicInput(activity("alias=foo;cycles=1;recycles=1"));
CycleSegment segment = input.getInputSegment(1); CycleSegment segment = input.getInputSegment(1);
assertThat(segment).isNotNull(); assertThat(segment).isNotNull();
assertThat(segment.nextCycle()).isEqualTo(0L); assertThat(segment.nextCycle()).isEqualTo(0L);
} }
@Test @Test
public void testThatCycleAndRecycleOffsetsWork() { public void testThatCycleAndRecycleOffsetsWork() {
AtomicInput input = new AtomicInput(new TestComponent("testing","atomicinput"), ActivityDef.parseActivityDef("alias=foo;cycles=310..330;recycles=37..39")); AtomicInput input = new AtomicInput(activity("alias=foo;cycles=310..330;recycles=37..39"));
CycleSegment segment = null; CycleSegment segment = null;
int stride=10; int stride=10;
segment = input.getInputSegment(stride); segment = input.getInputSegment(stride);
@ -95,8 +99,8 @@ public class AtomicInputTest {
@Test @Test
public void testEmptyIntervalShouldNotProvideValues() { public void testEmptyIntervalShouldNotProvideValues() {
AtomicInput i = new AtomicInput(new TestComponent("testing","atomicinput"),ActivityDef.parseActivityDef("alias=foo;cycles=23..23")); AtomicInput input = new AtomicInput(activity("alias=foo;cycles=23..23"));
CycleSegment inputSegment = i.getInputSegment(1); CycleSegment inputSegment = input.getInputSegment(1);
assertThat(inputSegment).isNull(); assertThat(inputSegment).isNull();
} }
} }

View File

@ -21,8 +21,8 @@ public class LinkedInputTest {
// TODO: Reintegrate these tests as follow the leader tests via output and input // TODO: Reintegrate these tests as follow the leader tests via output and input
// @Test // @Test
// public void shouldStayAtOrBehindLinkedInput() { // public void shouldStayAtOrBehindLinkedInput() {
// Input goes2Kfast = new TargetRateInput(ActivityDef.parseActivityDef("alias=goes2k;targetrate=2000")); // Input goes2Kfast = new TargetRateInput(Activity.configFor("alias=goes2k;targetrate=2000"));
// LinkedInput goesAsFast = new LinkedInput(ActivityDef.parseActivityDef("alias=asfast"),goes2Kfast); // LinkedInput goesAsFast = new LinkedInput(Activity.configFor("alias=asfast"),goes2Kfast);
// //
// long last2kFast = 0L; // long last2kFast = 0L;
// long lastAsFast = 0L; // long lastAsFast = 0L;
@ -37,8 +37,8 @@ public class LinkedInputTest {
// //
// @Test // @Test
// public void shouldBlockUntilLinkedAdvances() { // public void shouldBlockUntilLinkedAdvances() {
// ContiguousInput goes2Kfast = new TargetRateInput(ActivityDef.parseActivityDef("targetrate=2000")); // ContiguousInput goes2Kfast = new TargetRateInput(Activity.configFor("targetrate=2000"));
// LinkedInput goesAsFast = new LinkedInput(ActivityDef.parseActivityDef("alias=asfast"),goes2Kfast); // LinkedInput goesAsFast = new LinkedInput(Activity.configFor("alias=asfast"),goes2Kfast);
// //
// AtomicLong asFastValue = new AtomicLong(0L); // AtomicLong asFastValue = new AtomicLong(0L);
// Runnable linked = new Runnable() { // Runnable linked = new Runnable() {
@ -68,8 +68,8 @@ public class LinkedInputTest {
// //
// @Test(enabled=false) // @Test(enabled=false)
// public void microBenchDiffRate() { // public void microBenchDiffRate() {
// TargetRateInput fastInput = new TargetRateInput(ActivityDef.parseActivityDef("targetrate=10000000")); // TargetRateInput fastInput = new TargetRateInput(Activity.configFor("targetrate=10000000"));
// LinkedInput slowInput = new LinkedInput(ActivityDef.parseActivityDef("alias=asfast"),fastInput); // LinkedInput slowInput = new LinkedInput(Activity.configFor("alias=asfast"),fastInput);
// Timer fastInputTimer = new NicerTimer("fastinput", new DeltaHdrHistogramReservoir("fastinput",4)); // Timer fastInputTimer = new NicerTimer("fastinput", new DeltaHdrHistogramReservoir("fastinput",4));
// Timer slowInputTimer = new NicerTimer("slowinput", new DeltaHdrHistogramReservoir("slowinput",4)); // Timer slowInputTimer = new NicerTimer("slowinput", new DeltaHdrHistogramReservoir("slowinput",4));
// //

View File

@ -16,7 +16,7 @@
package io.nosqlbench.engine.api.util; package io.nosqlbench.engine.api.util;
import io.nosqlbench.nb.api.engine.activityimpl.ActivityDef; import io.nosqlbench.engine.api.activityimpl.uniform.Activity;
import io.nosqlbench.nb.api.engine.util.SSLKsFactory; import io.nosqlbench.nb.api.engine.util.SSLKsFactory;
import io.nosqlbench.nb.api.config.standard.NBConfiguration; import io.nosqlbench.nb.api.config.standard.NBConfiguration;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -29,197 +29,163 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
public class SSLKsFactoryTest { public class SSLKsFactoryTest {
@Test @Test
public void testJdkGetContext() { public void testJdkGetContext() {
String[] params = { NBConfiguration sslCfg = sslCfg("ssl=jdk", "tlsversion=TLSv1.2");
"ssl=jdk",
"tlsversion=TLSv1.2",
};
ActivityDef activityDef = ActivityDef.parseActivityDef(String.join(";", params));
NBConfiguration sslCfg = SSLKsFactory.get().getConfigModel().extractConfig(activityDef.getParams());
assertThat(SSLKsFactory.get().getContext(sslCfg)).isNotNull(); assertThat(SSLKsFactory.get().getContext(sslCfg)).isNotNull();
} }
private NBConfiguration sslCfg(String... params) {
return SSLKsFactory.get().getConfigModel()
.extractConfig(Activity.configFor(String.join(";",params)));
}
@Test @Test
public void testJdkGetContextWithTruststoreAndKeystore() { public void testJdkGetContextWithTruststoreAndKeystore() {
String[] params = { NBConfiguration sslCfg = sslCfg(
"ssl=jdk", "ssl=jdk",
"truststore=src/test/resources/ssl/server_truststore.p12", "truststore=src/test/resources/ssl/server_truststore.p12",
"tspass=nosqlbench_server", "tspass=nosqlbench_server",
"keystore=src/test/resources/ssl/client.p12", "keystore=src/test/resources/ssl/client.p12",
"kspass=nosqlbench_client" "kspass=nosqlbench_client"
}; );
ActivityDef activityDef = ActivityDef.parseActivityDef(String.join(";", params));
NBConfiguration sslCfg = SSLKsFactory.get().getConfigModel().extractConfig(activityDef.getParams());
assertThat(SSLKsFactory.get().getContext(sslCfg)).isNotNull(); assertThat(SSLKsFactory.get().getContext(sslCfg)).isNotNull();
} }
@Test @Test
public void testJdkGetContextWithTruststoreAndKeystoreAndDifferentKeyPassword() { public void testJdkGetContextWithTruststoreAndKeystoreAndDifferentKeyPassword() {
String[] params = { NBConfiguration sslCfg = sslCfg(
"ssl=jdk", "ssl=jdk",
"truststore=src/test/resources/ssl/server_truststore.p12", "truststore=src/test/resources/ssl/server_truststore.p12",
"tspass=nosqlbench_server", "tspass=nosqlbench_server",
"keystore=src/test/resources/ssl/client_diff_password.p12", "keystore=src/test/resources/ssl/client_diff_password.p12",
"kspass=nosqlbench_client", "kspass=nosqlbench_client",
"keyPassword=nosqlbench" "keyPassword=nosqlbench"
}; );
ActivityDef activityDef = ActivityDef.parseActivityDef(String.join(";", params));
NBConfiguration sslCfg = SSLKsFactory.get().getConfigModel().extractConfig(activityDef.getParams());
assertThat(SSLKsFactory.get().getContext(sslCfg)).isNotNull(); assertThat(SSLKsFactory.get().getContext(sslCfg)).isNotNull();
} }
@Test @Test
public void testJdkGetContextWithTruststore() { public void testJdkGetContextWithTruststore() {
String[] params = { NBConfiguration sslCfg = sslCfg(
"ssl=jdk", "ssl=jdk",
"truststore=src/test/resources/ssl/server_truststore.p12", "truststore=src/test/resources/ssl/server_truststore.p12",
"tspass=nosqlbench_server" "tspass=nosqlbench_server"
}; );
ActivityDef activityDef = ActivityDef.parseActivityDef(String.join(";", params));
NBConfiguration sslCfg = SSLKsFactory.get().getConfigModel().extractConfig(activityDef.getParams());
assertThat(SSLKsFactory.get().getContext(sslCfg)).isNotNull(); assertThat(SSLKsFactory.get().getContext(sslCfg)).isNotNull();
} }
@Test @Test
public void testJdkGetContextWithKeystore() { public void testJdkGetContextWithKeystore() {
String[] params = { NBConfiguration sslCfg = sslCfg(
"ssl=jdk", "ssl=jdk", "keystore=src/test/resources/ssl/client.p12", "kspass=nosqlbench_client"
"keystore=src/test/resources/ssl/client.p12", );
"kspass=nosqlbench_client"
};
ActivityDef activityDef = ActivityDef.parseActivityDef(String.join(";", params));
NBConfiguration sslCfg = SSLKsFactory.get().getConfigModel().extractConfig(activityDef.getParams());
assertThat(SSLKsFactory.get().getContext(sslCfg)).isNotNull(); assertThat(SSLKsFactory.get().getContext(sslCfg)).isNotNull();
} }
@Test @Test
public void testJdkGetContextWithKeystoreAndDifferentKeyPassword() { public void testJdkGetContextWithKeystoreAndDifferentKeyPassword() {
String[] params = { NBConfiguration sslCfg = sslCfg(
"ssl=jdk", "ssl=jdk",
"keystore=src/test/resources/ssl/client_diff_password.p12", "keystore=src/test/resources/ssl/client_diff_password.p12",
"kspass=nosqlbench_client", "kspass=nosqlbench_client",
"keyPassword=nosqlbench" "keyPassword=nosqlbench"
}; );
ActivityDef activityDef = ActivityDef.parseActivityDef(String.join(";", params));
NBConfiguration sslCfg = SSLKsFactory.get().getConfigModel().extractConfig(activityDef.getParams());
assertThat(SSLKsFactory.get().getContext(sslCfg)).isNotNull(); assertThat(SSLKsFactory.get().getContext(sslCfg)).isNotNull();
} }
@Test @Test
public void testOpenSSLGetContext() { public void testOpenSSLGetContext() {
String[] params = { NBConfiguration sslCfg = sslCfg("ssl=openssl", "tlsversion=TLSv1.2");
"ssl=openssl",
"tlsversion=TLSv1.2",
};
ActivityDef activityDef = ActivityDef.parseActivityDef(String.join(";", params));
NBConfiguration sslCfg = SSLKsFactory.get().getConfigModel().extractConfig(activityDef.getParams());
assertThat(SSLKsFactory.get().getContext(sslCfg)).isNotNull(); assertThat(SSLKsFactory.get().getContext(sslCfg)).isNotNull();
} }
@Test @Test
public void testOpenSSLGetContextWithCaCertAndCertAndKey() { public void testOpenSSLGetContextWithCaCertAndCertAndKey() {
String[] params = { NBConfiguration sslCfg = sslCfg(
"ssl=openssl", "ssl=openssl",
"caCertFilePath=src/test/resources/ssl/cacert.crt", "caCertFilePath=src/test/resources/ssl/cacert.crt",
"certFilePath=src/test/resources/ssl/client_cert.pem", "certFilePath=src/test/resources/ssl/client_cert.pem",
"keyFilePath=src/test/resources/ssl/client.key" "keyFilePath=src/test/resources/ssl/client.key"
}; );
ActivityDef activityDef = ActivityDef.parseActivityDef(String.join(";", params));
NBConfiguration sslCfg = SSLKsFactory.get().getConfigModel().extractConfig(activityDef.getParams());
assertThat(SSLKsFactory.get().getContext(sslCfg)).isNotNull(); assertThat(SSLKsFactory.get().getContext(sslCfg)).isNotNull();
} }
@Test @Test
public void testOpenSSLGetContextWithCaCert() { public void testOpenSSLGetContextWithCaCert() {
String[] params = { NBConfiguration sslCfg = sslCfg(
"ssl=openssl", "ssl=openssl", "caCertFilePath=src/test/resources/ssl/cacert.crt"
"caCertFilePath=src/test/resources/ssl/cacert.crt" );
};
ActivityDef activityDef = ActivityDef.parseActivityDef(String.join(";", params));
NBConfiguration sslCfg = SSLKsFactory.get().getConfigModel().extractConfig(activityDef.getParams());
assertThat(SSLKsFactory.get().getContext(sslCfg)).isNotNull(); assertThat(SSLKsFactory.get().getContext(sslCfg)).isNotNull();
} }
@Test @Test
public void testOpenSSLGetContextWithCertAndKey() { public void testOpenSSLGetContextWithCertAndKey() {
String[] params = { NBConfiguration sslCfg = sslCfg(
"ssl=openssl",
"certFilePath=src/test/resources/ssl/client_cert.pem", "ssl=openssl",
"keyFilePath=src/test/resources/ssl/client.key" "certFilePath=src/test/resources/ssl/client_cert.pem",
}; "keyFilePath=src/test/resources/ssl/client.key"
ActivityDef activityDef = ActivityDef.parseActivityDef(String.join(";", params)); );
NBConfiguration sslCfg = SSLKsFactory.get().getConfigModel().extractConfig(activityDef.getParams());
assertThat(SSLKsFactory.get().getContext(sslCfg)).isNotNull(); assertThat(SSLKsFactory.get().getContext(sslCfg)).isNotNull();
} }
@Test @Test
public void testLoadKeystoreError() { public void testLoadKeystoreError() {
String[] params = { NBConfiguration sslCfg = sslCfg(
"ssl=jdk",
"keystore=src/test/resources/ssl/non_existing.p12", "ssl=jdk",
"kspass=nosqlbench_client", "keystore=src/test/resources/ssl/non_existing.p12",
"keyPassword=nosqlbench_client" "kspass=nosqlbench_client",
}; "keyPassword=nosqlbench_client"
ActivityDef activityDef = ActivityDef.parseActivityDef(String.join(";", params)); );
NBConfiguration sslCfg = SSLKsFactory.get().getConfigModel().extractConfig(activityDef.getParams()); assertThatExceptionOfType(RuntimeException.class).isThrownBy(
assertThatExceptionOfType(RuntimeException.class) () -> SSLKsFactory.get().getContext(sslCfg))
.isThrownBy(() -> SSLKsFactory.get().getContext(sslCfg)) .withMessageMatching("Unable to load the keystore: .*");
.withMessageMatching("Unable to load the keystore: .*");
} }
@Test @Test
public void testInitKeyManagerFactoryError() { public void testInitKeyManagerFactoryError() {
String[] params = { NBConfiguration sslCfg = sslCfg(
"ssl=jdk", "ssl=jdk",
"keystore=src/test/resources/ssl/client.p12", "keystore=src/test/resources/ssl/client.p12",
"kspass=nosqlbench_client", "kspass=nosqlbench_client",
"keyPassword=incorrect_password" "keyPassword=incorrect_password"
}; );
ActivityDef activityDef = ActivityDef.parseActivityDef(String.join(";", params)); assertThatExceptionOfType(RuntimeException.class).isThrownBy(
NBConfiguration sslCfg = SSLKsFactory.get().getConfigModel().extractConfig(activityDef.getParams()); () -> SSLKsFactory.get().getContext(sslCfg))
.withMessageMatching("Unable to init KeyManagerFactory. Please check.*");
assertThatExceptionOfType(RuntimeException.class)
.isThrownBy(() -> SSLKsFactory.get().getContext(sslCfg))
.withMessageMatching("Unable to init KeyManagerFactory. Please check.*");
} }
@Test @Test
public void testLoadTruststoreError() { public void testLoadTruststoreError() {
String[] params = { NBConfiguration sslCfg = sslCfg(
"ssl=jdk", "ssl=jdk",
"truststore=src/test/resources/ssl/non_existing.p12", "truststore=src/test/resources/ssl/non_existing.p12",
"tspass=nosqlbench_server" "tspass=nosqlbench_server"
}; );
ActivityDef activityDef = ActivityDef.parseActivityDef(String.join(";", params)); assertThatExceptionOfType(RuntimeException.class).isThrownBy(
NBConfiguration sslCfg = SSLKsFactory.get().getConfigModel().extractConfig(activityDef.getParams()); () -> SSLKsFactory.get().getContext(sslCfg))
assertThatExceptionOfType(RuntimeException.class) .withMessageMatching("Unable to load the truststore: .*");
.isThrownBy(() -> SSLKsFactory.get().getContext(sslCfg))
.withMessageMatching("Unable to load the truststore: .*");
} }
@Test @Test
void testSSLValidationActive() { void testSSLValidationActive() {
{ {
final String[] params1 = { NBConfiguration sslCfg1 = sslCfg(
"ssl=openssl", "ssl=openssl",
"certFilePath=src/test/resources/ssl/client_cert.pem", "certFilePath=src/test/resources/ssl/client_cert.pem",
"keyFilePath=src/test/resources/ssl/client.key", "keyFilePath=src/test/resources/ssl/client.key",
"sslValidation=true" "sslValidation=true"
}; );
ActivityDef activityDef = ActivityDef.parseActivityDef(String.join(";", params1));
NBConfiguration sslCfg1 = SSLKsFactory.get().getConfigModel().extractConfig(activityDef.getParams());
assertThat(SSLKsFactory.get().getContext(sslCfg1)).isNotNull(); assertThat(SSLKsFactory.get().getContext(sslCfg1)).isNotNull();
} }
{ {
final String[] params2 = { NBConfiguration sslCfg2 = sslCfg( "ssl=jdk",
"ssl=jdk", "keystore=src/test/resources/ssl/client_diff_password.p12",
"keystore=src/test/resources/ssl/client_diff_password.p12", "kspass=nosqlbench_client",
"kspass=nosqlbench_client", "keyPassword=nosqlbench",
"keyPassword=nosqlbench", "sslValidation=true"
"sslValidation=true" );
};
ActivityDef activityDef2 = ActivityDef.parseActivityDef(String.join(";", params2));
NBConfiguration sslCfg2 = SSLKsFactory.get().getConfigModel().extractConfig(activityDef2.getParams());
assertThat(SSLKsFactory.get().getContext(sslCfg2)).isNotNull(); assertThat(SSLKsFactory.get().getContext(sslCfg2)).isNotNull();
} }
} }
@ -227,86 +193,72 @@ public class SSLKsFactoryTest {
@Test @Test
void testSSLValidationNotActive() { void testSSLValidationNotActive() {
{ {
final String[] params1 = { NBConfiguration sslCfg1 = sslCfg(
"ssl=openssl", "ssl=openssl",
"certFilePath=src/test/resources/ssl/client_cert.pem", "certFilePath=src/test/resources/ssl/client_cert.pem",
"keyFilePath=src/test/resources/ssl/client.key", "keyFilePath=src/test/resources/ssl/client.key",
"sslValidation=false" "sslValidation=false"
}; );
ActivityDef activityDef = ActivityDef.parseActivityDef(String.join(";", params1));
NBConfiguration sslCfg1 = SSLKsFactory.get().getConfigModel().extractConfig(activityDef.getParams());
assertThat(SSLKsFactory.get().getContext(sslCfg1)).isNotNull(); assertThat(SSLKsFactory.get().getContext(sslCfg1)).isNotNull();
} }
{ {
final String[] params2 = { NBConfiguration sslCfg2 = sslCfg( "ssl=jdk",
"ssl=jdk", "keystore=src/test/resources/ssl/client_diff_password.p12",
"keystore=src/test/resources/ssl/client_diff_password.p12", "kspass=nosqlbench_client",
"kspass=nosqlbench_client", "keyPassword=nosqlbench",
"keyPassword=nosqlbench", "sslValidation=false"
"sslValidation=false" );
};
ActivityDef activityDef2 = ActivityDef.parseActivityDef(String.join(";", params2));
NBConfiguration sslCfg2 = SSLKsFactory.get().getConfigModel().extractConfig(activityDef2.getParams());
assertThat(SSLKsFactory.get().getContext(sslCfg2)).isNotNull(); assertThat(SSLKsFactory.get().getContext(sslCfg2)).isNotNull();
} }
} }
@Test @Test
public void testOpenSSLGetContextWithCaCertError() { public void testOpenSSLGetContextWithCaCertError() {
String[] params = { NBConfiguration sslCfg = sslCfg(
"ssl=openssl", "ssl=openssl", "caCertFilePath=src/test/resources/ssl/non_existing.pem"
"caCertFilePath=src/test/resources/ssl/non_existing.pem" );
}; assertThatExceptionOfType(RuntimeException.class).isThrownBy(
ActivityDef activityDef = ActivityDef.parseActivityDef(String.join(";", params)); () -> SSLKsFactory.get().getContext(sslCfg))
NBConfiguration sslCfg = SSLKsFactory.get().getConfigModel().extractConfig(activityDef.getParams()); .withMessageContaining("Unable to load caCert from")
assertThatExceptionOfType(RuntimeException.class) .withCauseInstanceOf(FileNotFoundException.class);
.isThrownBy(() -> SSLKsFactory.get().getContext(sslCfg))
.withMessageContaining("Unable to load caCert from")
.withCauseInstanceOf(FileNotFoundException.class);
} }
@Test @Test
public void testOpenSSLGetContextWithCertError() { public void testOpenSSLGetContextWithCertError() {
String[] params = { NBConfiguration sslCfg = sslCfg(
"ssl=openssl", "ssl=openssl", "certFilePath=src/test/resources/ssl/non_existing.pem"
"certFilePath=src/test/resources/ssl/non_existing.pem" );
}; assertThatExceptionOfType(RuntimeException.class).isThrownBy(
ActivityDef activityDef = ActivityDef.parseActivityDef(String.join(";", params)); () -> SSLKsFactory.get().getContext(sslCfg))
NBConfiguration sslCfg = SSLKsFactory.get().getConfigModel().extractConfig(activityDef.getParams()); .withMessageContaining("Unable to load cert from")
assertThatExceptionOfType(RuntimeException.class) .withCauseInstanceOf(FileNotFoundException.class);
.isThrownBy(() -> SSLKsFactory.get().getContext(sslCfg))
.withMessageContaining("Unable to load cert from")
.withCauseInstanceOf(FileNotFoundException.class);
} }
@Test @Test
public void testOpenSSLGetContextWithKeyError() { public void testOpenSSLGetContextWithKeyError() {
String[] params = { NBConfiguration sslCfg = sslCfg(
"ssl=openssl",
"keyFilePath=src/test/resources/ssl/non_existing.pem" "ssl=openssl", "keyFilePath=src/test/resources/ssl/non_existing.pem"
}; );
ActivityDef activityDef = ActivityDef.parseActivityDef(String.join(";", params)); assertThatExceptionOfType(RuntimeException.class).isThrownBy(
NBConfiguration sslCfg = SSLKsFactory.get().getConfigModel().extractConfig(activityDef.getParams()); () -> SSLKsFactory.get().getContext(sslCfg))
assertThatExceptionOfType(RuntimeException.class) .withMessageContaining("Unable to load key from")
.isThrownBy(() -> SSLKsFactory.get().getContext(sslCfg)) .withCauseInstanceOf(FileNotFoundException.class);
.withMessageContaining("Unable to load key from")
.withCauseInstanceOf(FileNotFoundException.class);
} }
@Test @Test
public void testOpenSSLGetContextWithMissingCertError() { public void testOpenSSLGetContextWithMissingCertError() {
String[] params = { NBConfiguration sslCfg = sslCfg(
"ssl=openssl",
"caCertFilePath=src/test/resources/ssl/cacert.crt", "ssl=openssl",
"keyFilePath=src/test/resources/ssl/client.key" "caCertFilePath=src/test/resources/ssl/cacert.crt",
}; "keyFilePath=src/test/resources/ssl/client.key"
ActivityDef activityDef = ActivityDef.parseActivityDef(String.join(";", params)); );
NBConfiguration sslCfg = SSLKsFactory.get().getConfigModel().extractConfig(activityDef.getParams()); assertThatExceptionOfType(RuntimeException.class).isThrownBy(
assertThatExceptionOfType(RuntimeException.class) () -> SSLKsFactory.get().getContext(sslCfg))
.isThrownBy(() -> SSLKsFactory.get().getContext(sslCfg)) .withMessageContaining("Unable to load key from")
.withMessageContaining("Unable to load key from") .withCauseInstanceOf(IllegalArgumentException.class);
.withCauseInstanceOf(IllegalArgumentException.class);
} }
} }

View File

@ -19,8 +19,9 @@ package io.nosqlbench.engine.core;
import io.nosqlbench.engine.api.activityimpl.uniform.Activity; import io.nosqlbench.engine.api.activityimpl.uniform.Activity;
import io.nosqlbench.engine.api.activityimpl.uniform.ActivityWiring; import io.nosqlbench.engine.api.activityimpl.uniform.ActivityWiring;
import io.nosqlbench.engine.api.activityimpl.uniform.StandardActivityType; import io.nosqlbench.engine.api.activityimpl.uniform.StandardActivityType;
import io.nosqlbench.nb.api.config.standard.NBConfiguration;
import io.nosqlbench.nb.api.config.standard.TestComponent; import io.nosqlbench.nb.api.config.standard.TestComponent;
import io.nosqlbench.nb.api.engine.activityimpl.ActivityDef; import io.nosqlbench.nb.api.engine.activityimpl.ActivityConfig;
import io.nosqlbench.nb.api.advisor.NBAdvisorException; import io.nosqlbench.nb.api.advisor.NBAdvisorException;
import io.nosqlbench.engine.api.activityapi.core.*; import io.nosqlbench.engine.api.activityapi.core.*;
import io.nosqlbench.engine.api.activityapi.input.Input; import io.nosqlbench.engine.api.activityapi.input.Input;
@ -50,7 +51,7 @@ class ActivityExecutorTest {
// TODO: Design review of this mechanism // TODO: Design review of this mechanism
// @Test // @Test
// synchronized void testRestart() { // synchronized void testRestart() {
// ActivityDef activityDef = ActivityDef.parseActivityDef("driver=diag;alias=test-restart;cycles=1000;cyclerate=10;op=initdelay:initdelay=5000;"); // ActivityConfig activityDef = Activity.configFor("driver=diag;alias=test-restart;cycles=1000;cyclerate=10;op=initdelay:initdelay=5000;");
// new ActivityTypeLoader().load(activityDef); // new ActivityTypeLoader().load(activityDef);
// //
// final StandardActivity activity = new DelayedInitActivity(activityDef); // final StandardActivity activity = new DelayedInitActivity(activityDef);
@ -89,7 +90,7 @@ class ActivityExecutorTest {
synchronized void testAdvisorError() { synchronized void testAdvisorError() {
try { try {
ActivityDef activityDef = ActivityDef.parseActivityDef( ActivityConfig activityDef = Activity.configFor(
"driver=diag;alias=test-delayed-start;cycles=1000;initdelay=2000;"); "driver=diag;alias=test-delayed-start;cycles=1000;initdelay=2000;");
new ActivityTypeLoader().load(activityDef, TestComponent.INSTANCE); new ActivityTypeLoader().load(activityDef, TestComponent.INSTANCE);
Activity activity = new DelayedInitActivity(activityDef); Activity activity = new DelayedInitActivity(activityDef);
@ -103,7 +104,7 @@ class ActivityExecutorTest {
@Test @Test
synchronized void testDelayedStartSanity() { synchronized void testDelayedStartSanity() {
ActivityDef activityDef = ActivityDef.parseActivityDef( ActivityConfig activityDef = Activity.configFor(
"driver=diag;alias=test_delayed_start;cycles=1000;initdelay=2000;"); "driver=diag;alias=test_delayed_start;cycles=1000;initdelay=2000;");
Optional<StandardActivityType> standardActivityType = new ActivityTypeLoader().load( Optional<StandardActivityType> standardActivityType = new ActivityTypeLoader().load(
activityDef, TestComponent.INSTANCE); activityDef, TestComponent.INSTANCE);
@ -146,7 +147,7 @@ class ActivityExecutorTest {
@Test @Test
synchronized void testNewActivityExecutor() { synchronized void testNewActivityExecutor() {
final ActivityDef activityDef = ActivityDef.parseActivityDef( final ActivityConfig activityDef = Activity.configFor(
"driver=diag;alias=test_dynamic_params;cycles=1000;initdelay=5000;"); "driver=diag;alias=test_dynamic_params;cycles=1000;initdelay=5000;");
new ActivityTypeLoader().load(activityDef, TestComponent.INSTANCE); new ActivityTypeLoader().load(activityDef, TestComponent.INSTANCE);
ActivityWiring wiring = new ActivityWiring(activityDef); ActivityWiring wiring = new ActivityWiring(activityDef);
@ -202,8 +203,9 @@ class ActivityExecutorTest {
private MotorDispenser<?> getActivityMotorFactory(final SyncAction lc, Input ls) { private MotorDispenser<?> getActivityMotorFactory(final SyncAction lc, Input ls) {
return new MotorDispenser<>() { return new MotorDispenser<>() {
@Override @Override
public Motor getMotor(final ActivityDef activityDef, final int slotId) { public Motor getMotor(final ActivityConfig activityConfig, final int slotId) {
final Activity activity = new Activity(TestComponent.INSTANCE, activityDef); final Activity activity = new Activity(TestComponent.INSTANCE,
new ActivityConfig(activityConfig));
final Motor<?> cm = new CoreMotor<>(activity, slotId, ls, lc, null); final Motor<?> cm = new CoreMotor<>(activity, slotId, ls, lc, null);
return cm; return cm;
} }
@ -229,14 +231,14 @@ class ActivityExecutorTest {
private static class DelayedInitActivity extends Activity { private static class DelayedInitActivity extends Activity {
private static final Logger logger = LogManager.getLogger(DelayedInitActivity.class); private static final Logger logger = LogManager.getLogger(DelayedInitActivity.class);
public DelayedInitActivity(final ActivityDef activityDef) { public DelayedInitActivity(final ActivityConfig activityDef) {
super(TestComponent.INSTANCE, activityDef); super(TestComponent.INSTANCE, activityDef);
} }
@Override @Override
public void initActivity() { public void initActivity() {
final Integer initDelay = this.activityDef.getParams().getOptionalInteger( final Integer initDelay =
"initdelay").orElse(0); this.getConfig().getOptional(Integer.class,"initdelay").orElse(0);
DelayedInitActivity.logger.info(() -> "delaying for " + initDelay); DelayedInitActivity.logger.info(() -> "delaying for " + initDelay);
try { try {
Thread.sleep(initDelay); Thread.sleep(initDelay);

View File

@ -18,11 +18,11 @@ package io.nosqlbench.engine.core;
import io.nosqlbench.engine.api.activityimpl.uniform.Activity; import io.nosqlbench.engine.api.activityimpl.uniform.Activity;
import io.nosqlbench.nb.api.config.standard.TestComponent; import io.nosqlbench.nb.api.config.standard.TestComponent;
import io.nosqlbench.nb.api.engine.activityimpl.ActivityDef;
import io.nosqlbench.engine.api.activityapi.core.Motor; import io.nosqlbench.engine.api.activityapi.core.Motor;
import io.nosqlbench.engine.api.activityapi.core.SyncAction; import io.nosqlbench.engine.api.activityapi.core.SyncAction;
import io.nosqlbench.engine.api.activityimpl.motor.CoreMotor; import io.nosqlbench.engine.api.activityimpl.motor.CoreMotor;
import io.nosqlbench.engine.core.fortesting.BlockingSegmentInput; import io.nosqlbench.engine.core.fortesting.BlockingSegmentInput;
import io.nosqlbench.nb.api.engine.activityimpl.ActivityConfig;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
@ -35,9 +35,9 @@ public class CoreMotorTest {
@Test @Test
public void testBasicActivityMotor() { public void testBasicActivityMotor() {
ActivityDef activityDef = ActivityDef.parseActivityDef("alias=foo"); ActivityConfig config = Activity.configFor("alias=foo");
final Activity activity = new Activity<>( final Activity activity = new Activity<>(
new TestComponent("testing", "coremotor"), activityDef); new TestComponent("testing", "coremotor"), config);
final BlockingSegmentInput lockstepper = new BlockingSegmentInput(); final BlockingSegmentInput lockstepper = new BlockingSegmentInput();
final AtomicLong observableAction = new AtomicLong(-3L); final AtomicLong observableAction = new AtomicLong(-3L);
SyncAction action = this.getTestConsumer(observableAction); SyncAction action = this.getTestConsumer(observableAction);
@ -58,7 +58,7 @@ public class CoreMotorTest {
@Test @Test
public void testIteratorStride() { public void testIteratorStride() {
ActivityDef activityDef = ActivityDef.parseActivityDef("stride=3"); ActivityConfig activityDef = Activity.configFor("stride=3");
Activity activity = new Activity( Activity activity = new Activity(
TestComponent.INSTANCE, activityDef); TestComponent.INSTANCE, activityDef);
final BlockingSegmentInput lockstepper = new BlockingSegmentInput(); final BlockingSegmentInput lockstepper = new BlockingSegmentInput();

View File

@ -61,7 +61,8 @@ public class NB_activity_error extends NBBaseCommand {
stdout.write("starting activity activity_error"); stdout.write("starting activity activity_error");
controller.start(activitydef1); controller.start(activitydef1);
controller.waitMillis(500); controller.waitMillis(500);
controller.getActivityDef("activity_error").getParams().set("threads","unparsable"); // forced error controller.getActivity("activity_error").getConfig().update("threads","unparsable"); //
// forced error
controller.awaitActivity("activity_error", Long.MAX_VALUE); controller.awaitActivity("activity_error", Long.MAX_VALUE);
return null; return null;
} }

View File

@ -16,6 +16,7 @@
package io.nosqlbench.nbr.examples.injava; package io.nosqlbench.nbr.examples.injava;
import io.nosqlbench.engine.api.activityimpl.uniform.Activity;
import io.nosqlbench.engine.core.lifecycle.scenario.container.NBBufferedContainer; import io.nosqlbench.engine.core.lifecycle.scenario.container.NBBufferedContainer;
import io.nosqlbench.engine.core.lifecycle.scenario.execution.NBBaseCommand; import io.nosqlbench.engine.core.lifecycle.scenario.execution.NBBaseCommand;
import io.nosqlbench.nb.api.engine.metrics.instruments.NBMetricCounter; import io.nosqlbench.nb.api.engine.metrics.instruments.NBMetricCounter;
@ -35,71 +36,81 @@ public class NB_cocycledelay_bursty_backup extends NBBaseCommand {
} }
/** /**
* <pre>{@code <pre>{@code
* co_cycle_delay_bursty = { co_cycle_delay_bursty = {
* "alias": "co_cycle_delay_bursty", "alias": "co_cycle_delay_bursty",
* "driver": "diag", "driver": "diag",
* "cycles": "0..1000000", "cycles": "0..1000000",
* "threads": "10", "threads": "10",
* "cyclerate": "1000,1.5", "cyclerate": "1000,1.5",
* "op" : "diagrate: diagrate=500" "op" : "diagrate: diagrate=500"
* }; };
*
* print('starting activity co_cycle_delay_bursty'); print('starting activity co_cycle_delay_bursty');
* scenario.start(co_cycle_delay_bursty); scenario.start(co_cycle_delay_bursty);
* for (i = 0; i < 5; i++) { for (i = 0; i < 5; i++) {
* scenario.waitMillis(1000); scenario.waitMillis(1000);
* if (!scenario.isRunningActivity('co_cycle_delay_bursty')) { if (!scenario.isRunningActivity('co_cycle_delay_bursty')) {
* print("scenario exited prematurely, aborting."); print("scenario exited prematurely, aborting.");
* break; break;
* } }
* print("backlogging, cycles=" + metrics.co_cycle_delay_bursty.cycles_servicetime.count + print("backlogging, cycles=" + metrics.co_cycle_delay_bursty.cycles_servicetime.count +
* " waittime=" + metrics.co_cycle_delay_bursty.cycles_waittime.value + " waittime=" + metrics.co_cycle_delay_bursty.cycles_waittime.value +
* " diagrate=" + activities.co_cycle_delay_bursty.diagrate + " diagrate=" + activities.co_cycle_delay_bursty.diagrate +
* " cyclerate=" + activities.co_cycle_delay_bursty.cyclerate " cyclerate=" + activities.co_cycle_delay_bursty.cyclerate
* ); );
* } }
* print('step1 metrics.waittime=' + metrics.co_cycle_delay_bursty.cycles_waittime.value); print('step1 metrics.waittime=' + metrics.co_cycle_delay_bursty.cycles_waittime.value);
* activities.co_cycle_delay_bursty.diagrate = "10000"; activities.co_cycle_delay_bursty.diagrate = "10000";
*
* for (i = 0; i < 10; i++) { for (i = 0; i < 10; i++) {
* if (!scenario.isRunningActivity('co_cycle_delay_bursty')) { if (!scenario.isRunningActivity('co_cycle_delay_bursty')) {
* print("scenario exited prematurely, aborting."); print("scenario exited prematurely, aborting.");
* break; break;
* } }
* print("recovering, cycles=" + metrics.co_cycle_delay_bursty.cycles_servicetime.count + print("recovering, cycles=" + metrics.co_cycle_delay_bursty.cycles_servicetime.count +
* " waittime=" + metrics.co_cycle_delay_bursty.cycles_waittime.value + " waittime=" + metrics.co_cycle_delay_bursty.cycles_waittime.value +
* " diagrate=" + activities.co_cycle_delay_bursty.diagrate + " diagrate=" + activities.co_cycle_delay_bursty.diagrate +
* " cyclerate=" + activities.co_cycle_delay_bursty.cyclerate " cyclerate=" + activities.co_cycle_delay_bursty.cyclerate
* ); );
*
* scenario.waitMillis(1000); scenario.waitMillis(1000);
* if (metrics.co_cycle_delay_bursty.cycles_waittime.value < 50000000) { if (metrics.co_cycle_delay_bursty.cycles_waittime.value < 50000000) {
* print("waittime trended back down as expected, exiting on iteration " + i); print("waittime trended back down as expected, exiting on iteration " + i);
* break; break;
* } }
* } }
* //scenario.awaitActivity("co_cycle_delay"); //scenario.awaitActivity("co_cycle_delay");
* print('step2 metrics.waittime=' + metrics.co_cycle_delay_bursty.cycles_waittime.value); print('step2 metrics.waittime=' + metrics.co_cycle_delay_bursty.cycles_waittime.value);
* scenario.stop(co_cycle_delay_bursty); scenario.stop(co_cycle_delay_bursty);
* print("stopped activity co_cycle_delay_bursty"); print("stopped activity co_cycle_delay_bursty");
* }</pre> }</pre>
*/ */
@Override @Override
public Object invoke(NBCommandParams params, PrintWriter stdout, PrintWriter stderr, Reader stdin, ContainerActivitiesController controller) { public Object invoke(
NBCommandParams params,
PrintWriter stdout,
PrintWriter stderr,
Reader stdin,
ContainerActivitiesController controller
)
{
Map<String, String> co_cycle_delay_bursty = Map.of( Map<String, String> co_cycle_delay_bursty = Map.of(
"alias", "co_cycle_delay_bursty", "driver", "diag", "cycles", "0..1000000", "threads", "alias", "co_cycle_delay_bursty", "driver", "diag", "cycles", "0..1000000", "threads",
"1", "cyclerate", "1000,1.5", "op", "diagrate: diagrate=500" "1", "cyclerate", "1000,1.5", "op", "diagrate: diagrate=500");
);
stdout.println("starting activity co_cycle_delay_bursty"); stdout.println("starting activity co_cycle_delay_bursty");
controller.start(co_cycle_delay_bursty); controller.start(co_cycle_delay_bursty);
NBMetricCounter service_time_counter = find().counter("activity=co_cycle_delay_bursty,name=cycles_servicetime"); NBMetricCounter service_time_counter = find().counter(
NBMetricGauge wait_time_gauge = find().gauge("activity=co_cycle_delay_bursty,name=cycles_waittime"); "activity=co_cycle_delay_bursty,name=cycles_servicetime");
String diagrate = controller.getActivityDef("co_cycle_delay_bursty").getParams().get("diagrate").toString(); NBMetricGauge wait_time_gauge = find().gauge(
String cyclerate = controller.getActivityDef("co_cycle_delay_bursty").getParams().get("cyclerate").toString(); "activity=co_cycle_delay_bursty,name=cycles_waittime");
String diagrate = controller.getActivity("co_cycle_delay_bursty").getConfig()
.get("diagrate");
String cyclerate = controller.getActivity("co_cycle_delay_bursty").getConfig()
.get("cyclerate").toString();
for (int i = 0; i < 5; i++) { for (int i = 0; i < 5; i++) {
controller.waitMillis(1000); controller.waitMillis(1000);
@ -107,33 +118,41 @@ public class NB_cocycledelay_bursty_backup extends NBBaseCommand {
stdout.println("scenario exited prematurely, aborting."); stdout.println("scenario exited prematurely, aborting.");
break; break;
} }
diagrate = controller.getActivityDef("co_cycle_delay_bursty").getParams().get("diagrate").toString(); diagrate = controller.getActivity("co_cycle_delay_bursty").getConfig()
cyclerate = controller.getActivityDef("co_cycle_delay_bursty").getParams().get("cyclerate").toString(); .get("diagrate").toString();
stdout.println( cyclerate = controller.getActivity("co_cycle_delay_bursty").getConfig()
"backlogging, cycles=" + service_time_counter.getCount() + .get("cyclerate").toString();
" waittime=" + wait_time_gauge.getValue() + stdout.println("backlogging, cycles=" +
" diagrate=" + diagrate + service_time_counter.getCount() +
" cyclerate=" + cyclerate " waittime=" +
); wait_time_gauge.getValue() +
" diagrate=" +
diagrate +
" cyclerate=" +
cyclerate);
} }
stdout.println("step1 metrics.waittime=" + wait_time_gauge.getValue()); stdout.println("step1 metrics.waittime=" + wait_time_gauge.getValue());
controller.getActivityDef("co_cycle_delay_bursty").getParams().put("diagrate", "10000"); controller.getActivity("co_cycle_delay_bursty").getConfig().update("diagrate", "10000");
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
if (!controller.isRunningActivity("co_cycle_delay_bursty")) { if (!controller.isRunningActivity("co_cycle_delay_bursty")) {
stdout.println("scenario exited prematurely, aborting."); stdout.println("scenario exited prematurely, aborting.");
break; break;
} }
diagrate = controller.getActivityDef("co_cycle_delay_bursty").getParams().get("diagrate").toString(); diagrate = controller.getActivity("co_cycle_delay_bursty").getConfig()
cyclerate = controller.getActivityDef("co_cycle_delay_bursty").getParams().get("cyclerate").toString(); .get("diagrate").toString();
cyclerate = controller.getActivity("co_cycle_delay_bursty").getConfig()
.get("cyclerate").toString();
stdout.println( stdout.println("recovering, cycles=" +
"recovering, cycles=" + service_time_counter.getCount() + service_time_counter.getCount() +
" waittime=" + wait_time_gauge.getValue() + " waittime=" +
" diagrate=" + diagrate + wait_time_gauge.getValue() +
" cyclerate=" + cyclerate " diagrate=" +
); diagrate +
" cyclerate=" +
cyclerate);
controller.waitMillis(1000); controller.waitMillis(1000);
if (wait_time_gauge.getValue() < 50000000) { if (wait_time_gauge.getValue() < 50000000) {

View File

@ -49,13 +49,13 @@ public class NB_threadchange extends NBBaseCommand {
Activity activity = controller.start( Activity activity = controller.start(
"driver=diag;alias=threadchange;cycles=0..60000;threads=1;interval=2000;op='noop';rate=1000"); "driver=diag;alias=threadchange;cycles=0..60000;threads=1;interval=2000;op='noop';rate=1000");
activity.getActivityDef().setThreads(1); activity.getConfig().setThreads(1);
stdout.println("threads now " + activity.getActivityDef().getThreads()); stdout.println("threads now " + activity.getConfig().getThreads());
stdout.println("waiting 500 ms"); stdout.println("waiting 500 ms");
controller.waitMillis(500); controller.waitMillis(500);
activity.getActivityDef().setThreads(5); activity.getConfig().setThreads(5);
stdout.println("threads now " + activity.getActivityDef().getThreads()); stdout.println("threads now " + activity.getConfig().getThreads());
controller.stop("threadchange"); controller.stop("threadchange");
return null; return null;
} }

View File

@ -45,7 +45,8 @@ public class SimFrameUtils {
} }
public static Activity findFlywheelActivity(ContainerActivitiesController controller, String providedActivityName) { public static Activity findFlywheelActivity(ContainerActivitiesController controller, String providedActivityName) {
Optional<Activity> optionalActivity = Optional.ofNullable(providedActivityName).flatMap(controller::getActivity); Optional<Activity> optionalActivity =
Optional.ofNullable(providedActivityName).flatMap(controller::getOptionalActivity);
if (providedActivityName!=null && optionalActivity.isEmpty()) { if (providedActivityName!=null && optionalActivity.isEmpty()) {
throw new RuntimeException("you specified activity '" + providedActivityName + "' but it was not found."); throw new RuntimeException("you specified activity '" + providedActivityName + "' but it was not found.");
} }
@ -54,8 +55,8 @@ public class SimFrameUtils {
// Start the flywheel at an "idle" speed, even if the user hasn't set it // Start the flywheel at an "idle" speed, even if the user hasn't set it
flywheel.onEvent(new ParamChange<>(new CycleRateSpec(100.0d, 1.1d, SimRateSpec.Verb.restart))); flywheel.onEvent(new ParamChange<>(new CycleRateSpec(100.0d, 1.1d, SimRateSpec.Verb.restart)));
flywheel.getActivityDef().setEndCycle(Long.MAX_VALUE); flywheel.getConfig().updateLastCycle(Long.MAX_VALUE);
flywheel.getActivityDef().getParams().set(SIM_CYCLES, Long.MAX_VALUE); flywheel.getConfig().update(SIM_CYCLES, Long.MAX_VALUE);
return flywheel; return flywheel;
} }

View File

@ -61,7 +61,7 @@ public class CMD_reset extends NBBaseCommand {
@Override @Override
public Object invoke(NBCommandParams params, PrintWriter stdout, PrintWriter stderr, Reader stdin, ContainerActivitiesController controller) { public Object invoke(NBCommandParams params, PrintWriter stdout, PrintWriter stderr, Reader stdin, ContainerActivitiesController controller) {
Optional<Activity> optionalActivity = Optional<Activity> optionalActivity =
Optional.ofNullable(params.get("activity")).flatMap(controller::getActivity); Optional.ofNullable(params.get("activity")).flatMap(controller::getOptionalActivity);
if (params.get("activity")!=null && optionalActivity.isEmpty()) { if (params.get("activity")!=null && optionalActivity.isEmpty()) {
throw new RuntimeException("you specified activity '" + params.get("activity") + "' but it was not found."); throw new RuntimeException("you specified activity '" + params.get("activity") + "' but it was not found.");
} }
@ -81,21 +81,23 @@ public class CMD_reset extends NBBaseCommand {
default -> { default -> {
if (!IGNORABLE.contains(key)) { if (!IGNORABLE.contains(key)) {
logger.debug("Resetting parameter: " + key + " to " + value); logger.debug("Resetting parameter: " + key + " to " + value);
flywheel.getActivityDef().getParams().put(key, value); flywheel.getConfig().update(key, value);
} }
} }
} }
}); });
// Get the original cycle count and re-apply it // Get the original cycle count and re-apply it
long cycles = Long.parseLong((String) flywheel.getActivityDef().getParams().get("cycles")); long last_exclusive = flywheel.getConfig().getCyclesSpec().last_exclusive();
logger.debug("Resetting cycle count to " + cycles + " cycles"); logger.debug("Resetting last cycle to " + last_exclusive + " cycles");
flywheel.getActivityDef().setEndCycle(cycles); flywheel.getConfig().updateLastCycle(last_exclusive);
//TODO: This needs to be reworked, but simply calling controller.start on the flywheel results in 2 //TODO: This needs to be reworked, but simply calling controller.start on the flywheel results in 2
// copies of the activity running simultaneously. This is a temporary workaround. // copies of the activity running simultaneously. This is a temporary workaround.
SimFrameUtils.awaitActivity(flywheel); SimFrameUtils.awaitActivity(flywheel);
// flywheel.getWiring().getMotorDispenserDelegate().getMotor(flywheel.getActivityDef(), 0).run();
// flywheel.getWiring().getMotorDispenserDelegate().getMotor(flywheel.getConfig(), 0)
// .run();
// TODO Implement this correctly around new API // TODO Implement this correctly around new API
} }