formalize space type in generics

formalize space
This commit is contained in:
Jonathan Shook 2024-10-23 13:39:37 -05:00
parent 22ff75aa98
commit 7b8e9145d7
11 changed files with 141 additions and 48 deletions

View File

@ -19,10 +19,11 @@ package io.nosqlbench.adapter.diag;
import io.nosqlbench.adapters.api.activityimpl.uniform.DriverAdapter;
import io.nosqlbench.adapters.api.activityimpl.uniform.Space;
import io.nosqlbench.adapters.api.activityimpl.uniform.flowtypes.Op;
import io.nosqlbench.nb.api.labels.NBLabels;
import io.nosqlbench.nb.api.components.core.NBComponent;
public interface DriverAdapterLoader {
public <A extends Op,B> DriverAdapter<A,B> load(NBComponent parent, NBLabels childLabels);
public <A extends Op,B extends Space> DriverAdapter<A,B> load(NBComponent parent, NBLabels childLabels);
}

View File

@ -19,6 +19,7 @@ package io.nosqlbench.adapters.api.activityimpl;
import com.codahale.metrics.Timer;
import groovy.lang.Binding;
import io.nosqlbench.adapters.api.activityimpl.uniform.DriverAdapter;
import io.nosqlbench.adapters.api.activityimpl.uniform.Space;
import io.nosqlbench.adapters.api.activityimpl.uniform.flowtypes.Op;
import io.nosqlbench.adapters.api.evalctx.*;
import io.nosqlbench.adapters.api.metrics.ThreadLocalNamedTimers;
@ -42,10 +43,10 @@ import java.util.concurrent.TimeUnit;
* Some details are tracked per op template, which aligns to the life-cycle of the op dispenser.
* Thus, each op dispenser is where the stats for all related operations are kept.
*
* @param <T>
* @param <OP>
* The type of operation
*/
public abstract class BaseOpDispenser<T extends Op, S> extends NBBaseComponent implements OpDispenser<T>{
public abstract class BaseOpDispenser<OP extends Op,SPACE extends Space> extends NBBaseComponent implements OpDispenser<OP>{
protected final static Logger logger = LogManager.getLogger(BaseOpDispenser.class);
public static final String VERIFIER = "verifier";
public static final String VERIFIER_INIT = "verifier-init";
@ -55,7 +56,7 @@ public abstract class BaseOpDispenser<T extends Op, S> extends NBBaseComponent i
public static final String STOP_TIMERS = "stop-timers";
private final String opName;
protected final DriverAdapter<? extends T, ? extends S> adapter;
protected final DriverAdapter<? extends OP, ? extends SPACE> adapter;
private final NBLabels labels;
public final Timer verifierTimer;
private boolean instrument;
@ -77,7 +78,7 @@ public abstract class BaseOpDispenser<T extends Op, S> extends NBBaseComponent i
private final CycleFunction<Boolean> _verifier;
private final ThreadLocal<CycleFunction<Boolean>> tlVerifier;
protected BaseOpDispenser(final DriverAdapter<? extends T, ? extends S> adapter, final ParsedOp op) {
protected BaseOpDispenser(final DriverAdapter<? extends OP, ? extends SPACE> adapter, final ParsedOp op) {
super(adapter);
opName = op.getName();
this.adapter = adapter;
@ -177,7 +178,7 @@ public abstract class BaseOpDispenser<T extends Op, S> extends NBBaseComponent i
return this.opName;
}
public DriverAdapter<? extends T, ? extends S> getAdapter() {
public DriverAdapter<? extends OP, ? extends SPACE> getAdapter() {
return this.adapter;
}
@ -227,8 +228,8 @@ public abstract class BaseOpDispenser<T extends Op, S> extends NBBaseComponent i
}
@Override
public final T apply(long value) {
T op = getOp(value);
public final OP apply(long value) {
OP op = getOp(value);
return op;
}
}

View File

@ -16,6 +16,7 @@
package io.nosqlbench.adapters.api.activityimpl;
import io.nosqlbench.adapters.api.activityimpl.uniform.flowtypes.Op;
import io.nosqlbench.adapters.api.evalctx.CycleFunction;
import java.util.function.LongFunction;
@ -64,11 +65,11 @@ import java.util.function.LongFunction;
* are easy to understand at the mapping level ({@link OpMapper}),
* and streamlined for fast execution at the synthesis level ({@link OpDispenser}).
*
* @param <T> The parameter type of the actual operation which will be used
* @param <OP> The parameter type of the actual operation which will be used
* to hold all the details for executing an operation,
* something that implements {@link Runnable}.
* something that implements {@link Op}.
*/
public interface OpDispenser<T> extends LongFunction<T>, OpResultTracker {
public interface OpDispenser<OP extends Op> extends LongFunction<OP>, OpResultTracker {
/**
* The apply method in an op dispenser should do all the work of
@ -82,7 +83,7 @@ public interface OpDispenser<T> extends LongFunction<T>, OpResultTracker {
* @return an executable operation
*/
T getOp(long value);
OP getOp(long value);
CycleFunction<Boolean> getVerifier();

View File

@ -17,17 +17,21 @@
package io.nosqlbench.adapters.api.activityimpl;
import io.nosqlbench.adapters.api.activityimpl.uniform.DriverAdapter;
import io.nosqlbench.adapters.api.activityimpl.uniform.Space;
import io.nosqlbench.adapters.api.activityimpl.uniform.flowtypes.Op;
import io.nosqlbench.adapters.api.templating.ParsedOp;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.function.LongFunction;
/**
* <p>
* <h2>Synopsis</h2>
* An OpMapper is responsible for converting parsed op templates
* into dispensers of operations based on the intention of the user.
*
* <p>
* Op Templates as expressed as a set of field values, some literal, and
* some dynamic, to be generated based on a specific cycle value.
* </p>
@ -79,16 +83,19 @@ import java.util.function.Function;
* to hold all the details for executing an operation,
* generally something that implements {@link Runnable}.
*/
public interface OpMapper<OPTYPE extends Op> extends Function<ParsedOp, OpDispenser<? extends OPTYPE>> {
public interface OpMapper<OPTYPE extends Op, SPACETYPE extends Space>
extends BiFunction<ParsedOp, LongFunction<SPACETYPE>, OpDispenser<OPTYPE>> {
/**
* Interrogate the parsed command, and provide a new
*
* @param op The {@link ParsedOp} which is the parsed version of the user-provided op template.
* This contains all the fields provided by the user, as well as explicit knowledge of
* which ones are static and dynamic.
* @param op
* The {@link ParsedOp} which is the parsed version of the user-provided op template.
* This contains all the fields provided by the user, as well as explicit knowledge of
* which ones are static and dynamic.
* @param spaceInitF
* @return An OpDispenser which can be used to synthesize real operations.
*/
@Override
OpDispenser<? extends OPTYPE> apply(ParsedOp op);
OpDispenser<OPTYPE> apply(ParsedOp op, LongFunction<SPACETYPE> spaceInitF);
}

View File

@ -18,6 +18,7 @@ package io.nosqlbench.adapters.api.activityimpl.docs;
import io.nosqlbench.adapter.diag.DriverAdapterLoader;
import io.nosqlbench.adapters.api.activityimpl.uniform.DriverAdapter;
import io.nosqlbench.adapters.api.activityimpl.uniform.Space;
import io.nosqlbench.adapters.api.activityimpl.uniform.flowtypes.Op;
import io.nosqlbench.nb.api.docsapi.BundledMarkdownManifest;
import io.nosqlbench.nb.api.docsapi.Docs;
@ -40,7 +41,10 @@ public class BundledDriverAdapterDocs implements BundledMarkdownManifest {
List<SimpleServiceLoader.Component<? extends DriverAdapterLoader>> namedProviders = loader.getNamedProviders();
for (SimpleServiceLoader.Component<? extends DriverAdapterLoader> namedProvider : namedProviders) {
DriverAdapterLoader driverAdapterLoader = namedProvider.provider.get();
DriverAdapter<Op, Object> driverAdapter = driverAdapterLoader.load(NBComponent.EMPTY_COMPONENT, NBLabels.forKV());
DriverAdapter<Op, Space> driverAdapter = driverAdapterLoader.load(
NBComponent.EMPTY_COMPONENT,
NBLabels.forKV()
);
DocsBinder bundledDocs = driverAdapter.getBundledDocs();
docs = docs.merge(bundledDocs);
}

View File

@ -32,12 +32,13 @@ import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.LongFunction;
import java.util.function.LongToIntFunction;
import java.util.stream.Collectors;
public abstract class BaseDriverAdapter<R extends Op, S> extends NBBaseComponent implements DriverAdapter<R, S>, NBConfigurable, NBReconfigurable {
public abstract class BaseDriverAdapter<R extends Op, S extends Space> extends NBBaseComponent implements DriverAdapter<R, S>, NBConfigurable, NBReconfigurable {
private final static Logger logger = LogManager.getLogger("ADAPTER");
private StringDriverSpaceCache<? extends S> spaceCache;
private ConcurrentSpaceCache<S> spaceCache;
private NBConfiguration cfg;
private LongFunction<S> spaceF;
@ -62,7 +63,7 @@ public abstract class BaseDriverAdapter<R extends Op, S> extends NBBaseComponent
mappers.addAll(stmtRemappers);
mappers.addAll(getOpFieldRemappers());
if (mappers.size() == 0) {
if (mappers.isEmpty()) {
return (i) -> i;
}
@ -121,7 +122,7 @@ public abstract class BaseDriverAdapter<R extends Op, S> extends NBBaseComponent
* <p>Provide a list of field remappers which operate on arbitrary fields.
* Each function is applied to the op template fields. </p>
*
* @return
* @return op field remappers, an empty list by default
*/
@Override
public List<Function<Map<String, Object>, Map<String, Object>>> getOpFieldRemappers() {
@ -129,9 +130,9 @@ public abstract class BaseDriverAdapter<R extends Op, S> extends NBBaseComponent
}
@Override
public final synchronized StringDriverSpaceCache<? extends S> getSpaceCache() {
public final synchronized ConcurrentSpaceCache<S> getSpaceCache() {
if (spaceCache == null) {
spaceCache = new StringDriverSpaceCache<>(this, getSpaceInitializer(getConfiguration()));
spaceCache = new ConcurrentSpaceCache<S>(getSpaceInitializer(getConfiguration()));
}
return spaceCache;
}
@ -192,8 +193,8 @@ public abstract class BaseDriverAdapter<R extends Op, S> extends NBBaseComponent
@Override
public LongFunction<S> getSpaceFunc(ParsedOp pop) {
LongFunction<String> spaceNameF = pop.getAsFunctionOr("space", "default");
StringDriverSpaceCache<? extends S> cache = getSpaceCache();
return l -> getSpaceCache().get(spaceNameF.apply(l));
LongToIntFunction spaceIdxF = pop.getAsFunctionOrInt("space", 0);
ConcurrentSpaceCache<? extends S> cache = getSpaceCache();
return l -> getSpaceCache().get(spaceIdxF.applyAsInt(l));
}
}

View File

@ -0,0 +1,36 @@
package io.nosqlbench.adapters.api.activityimpl.uniform;
/*
* Copyright (c) 2022 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 java.util.function.IntFunction;
import java.util.function.LongFunction;
public class BaseSpace implements Space {
private final String spaceName;
public BaseSpace(long idx) {
this.spaceName = String.valueOf(idx);
}
@Override
public String getName() {
return spaceName;
}
}

View File

@ -33,6 +33,7 @@ import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.function.LongFunction;
/**
@ -55,7 +56,7 @@ import java.util.function.LongFunction;
* during construction of R type operations, or even for individual
* operations.
*/
public interface DriverAdapter<OPTYPE extends Op, SPACETYPE> extends NBComponent {
public interface DriverAdapter<OPTYPE extends Op, SPACETYPE extends Space> extends NBComponent {
/**
* <p>
@ -101,7 +102,7 @@ public interface DriverAdapter<OPTYPE extends Op, SPACETYPE> extends NBComponent
*
* @return a synthesizer function for {@link OPTYPE} op generation
*/
OpMapper<OPTYPE> getOpMapper();
OpMapper<OPTYPE, SPACETYPE> getOpMapper();
/**
* The preprocessor function allows the driver adapter to remap
@ -159,7 +160,7 @@ public interface DriverAdapter<OPTYPE extends Op, SPACETYPE> extends NBComponent
* @return A function which can initialize a new Space, which is a place to hold
* object state related to retained objects for the lifetime of a native driver.
*/
default Function<String, ? extends SPACETYPE> getSpaceInitializer(NBConfiguration cfg) {
default LongFunction<SPACETYPE> getSpaceInitializer(NBConfiguration cfg) {
return n -> null;
}

View File

@ -0,0 +1,37 @@
package io.nosqlbench.adapters.api.activityimpl.uniform;
/*
* Copyright (c) 2022 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.components.core.NBNamedElement;
/**
* <P>A space is simply a separate namespace associated with an instance of a
* native client or driver. This allows for the emulation of many clients
* in testing scenarios. Within the operations for an adapter, the space
* may be needed, for example, to construct prepared statements, or other
* 'session-attached' objects. Put any state that you would normally
* associate with an instance of a native driver into a space, and use
* the {@link DriverAdapter#getSpaceCache()} to access it when needed.</P>
*/
public interface Space extends NBNamedElement, AutoCloseable {
@Override
default void close() throws Exception {
}
}

View File

@ -23,6 +23,7 @@ import io.nosqlbench.adapters.api.activityconfig.yaml.OpsDocList;
import io.nosqlbench.adapters.api.activityimpl.OpDispenser;
import io.nosqlbench.adapters.api.activityimpl.OpMapper;
import io.nosqlbench.adapters.api.activityimpl.uniform.DriverAdapter;
import io.nosqlbench.adapters.api.activityimpl.uniform.Space;
import io.nosqlbench.adapters.api.activityimpl.uniform.decorators.SyntheticOpTemplateProvider;
import io.nosqlbench.adapters.api.activityimpl.uniform.flowtypes.CycleOp;
import io.nosqlbench.adapters.api.activityimpl.uniform.flowtypes.Op;
@ -58,6 +59,7 @@ import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.function.Function;
import java.util.function.LongFunction;
/**
* A default implementation of an Activity, suitable for building upon.
@ -395,7 +397,7 @@ public class SimpleActivity extends NBStatusComponent implements Activity, Invok
protected <O extends Op> OpSequence<OpDispenser<? extends O>> createOpSourceFromParsedOps(
// Map<String, DriverAdapter<?,?>> adapterCache,
// Map<String, OpMapper<? extends Op>> mapperCache,
List<DriverAdapter<?, ?>> adapters,
List<DriverAdapter<Op, Space>> adapters,
List<ParsedOp> pops
) {
try {
@ -424,10 +426,10 @@ public class SimpleActivity extends NBStatusComponent implements Activity, Invok
continue;
}
DriverAdapter<?, ?> adapter = adapters.get(i);
OpMapper<? extends Op> opMapper = adapter.getOpMapper();
OpDispenser<? extends Op> dispenser = opMapper.apply(pop);
DriverAdapter<Op, Space> adapter = adapters.get(i);
OpMapper<Op, Space> opMapper = adapter.getOpMapper();
LongFunction<Space> spaceFunc = adapter.getSpaceFunc(pop);
OpDispenser<Op> dispenser = opMapper.apply(pop, spaceFunc);
String dryrunSpec = pop.takeStaticConfigOr("dryrun", "none");
if ("op".equalsIgnoreCase(dryrunSpec)) {
dispenser = new DryRunOpDispenserWrapper((DriverAdapter<Op, Object>) adapter, pop, dispenser);

View File

@ -23,6 +23,7 @@ import io.nosqlbench.adapters.api.activityconfig.yaml.OpsDocList;
import io.nosqlbench.adapters.api.activityimpl.OpDispenser;
import io.nosqlbench.adapters.api.activityimpl.OpMapper;
import io.nosqlbench.adapters.api.activityimpl.uniform.DriverAdapter;
import io.nosqlbench.adapters.api.activityimpl.uniform.Space;
import io.nosqlbench.adapters.api.activityimpl.uniform.decorators.SyntheticOpTemplateProvider;
import io.nosqlbench.adapters.api.activityimpl.uniform.flowtypes.Op;
import io.nosqlbench.adapters.api.templating.ParsedOp;
@ -62,7 +63,7 @@ import java.util.concurrent.ConcurrentHashMap;
public class StandardActivity<R extends Op, S> extends SimpleActivity implements SyntheticOpTemplateProvider, ActivityDefObserver {
private static final Logger logger = LogManager.getLogger("ACTIVITY");
private final OpSequence<OpDispenser<? extends Op>> sequence;
private final ConcurrentHashMap<String, DriverAdapter<?, ?>> adapters = new ConcurrentHashMap<>();
private final ConcurrentHashMap<String, DriverAdapter<Op,Space>> adapters = new ConcurrentHashMap<>();
public StandardActivity(NBComponent parent, ActivityDef activityDef) {
super(parent, activityDef);
@ -92,11 +93,11 @@ public class StandardActivity<R extends Op, S> extends SimpleActivity implements
List<ParsedOp> pops = new ArrayList<>();
List<DriverAdapter<?, ?>> adapterlist = new ArrayList<>();
List<DriverAdapter<Op, Space>> adapterlist = new ArrayList<>();
NBConfigModel supersetConfig = ConfigModel.of(StandardActivity.class).add(yamlmodel);
Optional<String> defaultDriverOption = defaultDriverName;
ConcurrentHashMap<String, OpMapper<? extends Op>> mappers = new ConcurrentHashMap<>();
ConcurrentHashMap<String, OpMapper<? extends Op, ? extends Space>> mappers = new ConcurrentHashMap<>();
for (OpTemplate ot : opTemplates) {
// ParsedOp incompleteOpDef = new ParsedOp(ot, NBConfiguration.empty(), List.of(), this);
String driverName = ot.getOptionalStringParam("driver", String.class)
@ -112,7 +113,7 @@ public class StandardActivity<R extends Op, S> extends SimpleActivity implements
// HERE
if (!adapters.containsKey(driverName)) {
DriverAdapter<?, ?> adapter = Optional.of(driverName)
DriverAdapter<Op,Space> adapter = Optional.of(driverName)
.flatMap(
name -> ServiceSelector.of(
name,
@ -144,7 +145,7 @@ public class StandardActivity<R extends Op, S> extends SimpleActivity implements
supersetConfig.assertValidConfig(activityDef.getParams().getStringStringMap());
DriverAdapter<?, ?> adapter = adapters.get(driverName);
DriverAdapter<Op, Space> adapter = adapters.get(driverName);
adapterlist.add(adapter);
ParsedOp pop = new ParsedOp(ot, adapter.getConfiguration(), List.of(adapter.getPreprocessor()), this);
Optional<String> discard = pop.takeOptionalStaticValue("driver", String.class);
@ -261,19 +262,20 @@ public class StandardActivity<R extends Op, S> extends SimpleActivity implements
*/
@Override
public void shutdownActivity() {
for (Map.Entry<String, DriverAdapter<?, ?>> entry : adapters.entrySet()) {
for (Map.Entry<String, DriverAdapter<Op,Space>> entry : adapters.entrySet()) {
String adapterName = entry.getKey();
DriverAdapter<?, ?> adapter = entry.getValue();
adapter.getSpaceCache().getElements().forEach((spaceName, space) -> {
if (space instanceof AutoCloseable autocloseable) {
for (Space space : adapter.getSpaceCache()) {
if (space instanceof AutoCloseable autoCloseable) {
try {
autocloseable.close();
// TODO This should be invariant now, remove conditional?
autoCloseable.close();
} catch (Exception e) {
throw new RuntimeException("Error while shutting down state space for " +
"adapter=" + adapterName + ", space=" + spaceName + ": " + e, e);
"adapter=" + adapterName + ", space=" + space.getName() + ": " + e, e);
}
}
});
}
}
}