import nosqlbench

This commit is contained in:
Jonathan Shook 2020-02-20 15:37:57 -06:00
parent 62d53ecec6
commit fdc3d79856
464 changed files with 42623 additions and 0 deletions

169
nb-api/pom.xml Normal file
View File

@ -0,0 +1,169 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>nb-defaults</artifactId>
<groupId>io.nosqlbench</groupId>
<version>2.12.66-SNAPSHOT</version>
<relativePath>../nb-defaults</relativePath>
</parent>
<artifactId>nb-api</artifactId>
<packaging>jar</packaging>
<name>${project.artifactId}</name>
<description>
The driver API for nosqlbench;
Provides the interfaces needed to build drivers that can be loaded by nosqlbench core
</description>
<dependencies>
<dependency>
<groupId>io.nosqlbench</groupId>
<artifactId>virtdata-userlibs</artifactId>
<version>2.12.16-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>io.dropwizard.metrics</groupId>
<artifactId>metrics-core</artifactId>
<version>${metrics-version}</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>1.22</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>1.22</version>
</dependency>
<!--<dependency>-->
<!--<groupId>io.dropwizard.metrics</groupId>-->
<!--<artifactId>metrics-jmx</artifactId>-->
<!--<version>${metrics-version}</version>-->
<!--</dependency>-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.7</version>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.23</version>
</dependency>
<dependency>
<groupId>com.mitchtalmadge</groupId>
<artifactId>ascii-data</artifactId>
<version>1.2.0</version>
</dependency>
<!-- test scope only -->
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.13.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core-java8</artifactId>
<version>1.0.0m1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hdrhistogram</groupId>
<artifactId>HdrHistogram</artifactId>
<version>2.1.10</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-handler</artifactId>
<version>4.1.44.Final</version>
</dependency>
<dependency>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.1</version>
</dependency>
</dependencies>
<profiles>
<profile>
<id>perftests</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M3</version>
<configuration>
<groups>perf</groups>
</configuration>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>shade</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.1</version>
<configuration>
<relocations>
<relocation>
<pattern>com.google.common</pattern>
<shadedPattern>com.google.shaded.common</shadedPattern>
</relocation>
</relocations>
<minimizeJar>true</minimizeJar>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@ -0,0 +1,129 @@
/*
*
* Copyright 2016 jshook
* 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 activityconfig;
import java.util.*;
import java.util.stream.Collectors;
public class MultiMapLookup implements Map<String, String> {
private final List<Map<String, String>> maps = new ArrayList<>();
public MultiMapLookup() {
}
public MultiMapLookup(Map<String,String> map1, Map<String,String> map2) {
add(map1);
add(map2);
}
public MultiMapLookup add(Map<String,String> map) {
maps.add(map);
return this;
}
@Override
public int size() {
long count = maps.stream().map(Map::keySet).flatMap(Set::stream).distinct().count();
return (int) count;
}
@Override
public boolean isEmpty() {
return maps.stream().allMatch(Map::isEmpty);
}
@Override
public boolean containsKey(Object key) {
return maps.stream().anyMatch(m -> m.containsKey(key));
}
@Override
public boolean containsValue(Object value) {
return maps.stream().anyMatch(m -> m.containsValue(value));
}
@Override
public String get(Object key) {
return maps.stream()
.filter(m -> m.containsKey(String.valueOf(key)))
.findFirst()
.map(m -> String.valueOf(m.get(key)))
.orElse(null);
}
@Override
public String put(String key, String value) {
throw immutable();
}
@Override
public String remove(Object key) {
throw immutable();
}
@Override
public void putAll(Map<? extends String, ? extends String> m) {
throw immutable();
}
@Override
public void clear() {
throw immutable();
}
@Override
public Set<String> keySet() {
Set<String> keys = new HashSet<>();
maps.stream().map(Map::keySet).flatMap(Set::stream)
.forEach(keys::add);
return keys;
}
@Override
public Collection<String> values() {
return entrySet().stream()
.map(Entry::getValue)
.collect(Collectors.toList());
}
@Override
public Set<Entry<String, String>> entrySet() {
Map<String, String> compositeMap = new HashMap<>();
for (Map<String, String> map : maps) {
for (Entry<String, String> entry : map.entrySet()) {
if (!compositeMap.containsKey(entry.getKey())) {
compositeMap.put(entry.getKey(), entry.getValue());
}
}
}
return compositeMap.entrySet();
}
private RuntimeException immutable() {
return new RuntimeException("This map is not meant to be mutable.");
}
@Override
public String toString() {
return entrySet().stream().map(e -> (e.getKey() + ":" + e.getValue()))
.collect(Collectors.joining(","));
}
}

View File

@ -0,0 +1,163 @@
/*
*
* Copyright 2016 jshook
* 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 activityconfig;
import activityconfig.yaml.StmtDef;
import io.virtdata.templates.BindPoint;
import io.virtdata.templates.ParsedTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.regex.Pattern;
/**
* Allow for uniform statement anchor parsing, using the <pre>?anchor</pre>
* and <pre>{anchor}</pre> anchoring conventions. This type also includes
* all of the properties from the enclosed StmtDef, in addition to a couple of
* helpers. It should allow programmers to project this type directly from an
* existing {@link StmtDef} as a substitute.
*/
public class ParsedStmt {
private final static Pattern stmtToken = Pattern.compile("\\?(\\w+[-_\\d\\w]*)|\\{(\\w+[-_\\d\\w.]*)}");
private final static Logger logger = LoggerFactory.getLogger(ParsedStmt.class);
private ParsedTemplate template;
private final StmtDef stmtDef;
private final ParsedTemplate parsed;
/**
* Construct a new ParsedStatement from the provided stmtDef and anchor token.
*
* @param stmtDef An existing statement def as read from the YAML API.
*/
public ParsedStmt(StmtDef stmtDef) {
this.stmtDef = stmtDef;
parsed = new ParsedTemplate(stmtDef.getStmt(), stmtDef.getBindings());
}
public ParsedStmt orError() {
if (hasError()) {
throw new RuntimeException("Unable to parse statement: " + this.toString());
}
return this;
}
public String toString() {
return parsed.toString();
}
/**
* @return true if the parsed statement is not usable.
*/
public boolean hasError() {
return parsed.hasError();
}
/**
* The list of binding names returned by this method does not
* constitute an error. They may be used for
* for informational purposes in error handlers, for example.
*
* @return a set of bindings names which were provided to
* this parsed statement, but which were not referenced
* in either <pre>{anchor}</pre> or <pre>?anchor</pre> form.
*/
public Set<String> getExtraBindings() {
return parsed.getExtraBindings();
}
/**
* Returns a list of binding names which were referenced
* in either <pre>{anchor}</pre> or <pre>?anchor</pre> form,
* but which were not present in the provided bindings map.
* If any binding names are present in the returned set, then
* this binding will not be usable.
*
* @return A list of binding names which were referenced but not defined*
*/
public Set<String> getMissingBindings() {
return parsed.getMissingBindings();
}
/**
* Return a map of bindings which were referenced in the statement.
* This is an easy way to get the list of effective bindings for
* a statement for diagnostic purposes without including a potentially
* long list of library bindings.
* @return a bindings map of referenced bindings in the statement
*/
public Map<String, String> getSpecificBindings() {
return parsed.getSpecificBindings();
}
/**
* Return the statement that can be used as-is by any driver specific version.
* This uses the anchor token as provided to yield a version of the statement
* which contains positional anchors, but no named bindings.
* @param tokenMapper A function which maps the anchor name to the needed form
* in the callers driver context
* @return A driver or usage-specific format of the statement, with anchors
*/
public String getPositionalStatement(Function<String,String> tokenMapper) {
return parsed.getPositionalStatement(tokenMapper);
}
/**
* @return the statement name from the enclosed {@link StmtDef}
*/
public String getName() {
return stmtDef.getName();
}
/**
* @return the raw statement from the enclosed {@link StmtDef}
*/
public String getStmt() {
return stmtDef.getStmt();
}
/**
* @return the tags from the enclosed {@link StmtDef}
*/
public Map<String, String> getTags() {
return stmtDef.getTags();
}
/**
* @return the bindings from the enclosed {@link StmtDef}
*/
public Map<String, String> getBindings() {
return stmtDef.getBindings();
}
/**
* @return the params from the enclosed {@link StmtDef}
*/
public Map<String, String> getParams() {
return stmtDef.getParams();
}
public List<BindPoint> getBindPoints() {
return parsed.getBindPoints();
}
}

View File

@ -0,0 +1,43 @@
/*
*
* Copyright 2016 jshook
* 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 activityconfig;
import activityconfig.rawyaml.RawStmtsDocList;
import activityconfig.rawyaml.RawYamlStatementLoader;
import activityconfig.yaml.StmtsDocList;
import org.slf4j.Logger;
import java.util.function.Function;
public class StatementsLoader {
public static StmtsDocList load(Logger logger, String path, String... searchPaths) {
RawYamlStatementLoader loader = new RawYamlStatementLoader();
RawStmtsDocList rawDocList = loader.load(logger, path, searchPaths);
StmtsDocList layered = new StmtsDocList(rawDocList);
return layered;
}
public static StmtsDocList load(Logger logger, String path, Function<String, String> transformer, String... searchPaths) {
RawYamlStatementLoader loader = new RawYamlStatementLoader(transformer);
RawStmtsDocList rawDocList = loader.load(logger, path, searchPaths);
StmtsDocList layered = new StmtsDocList(rawDocList);
return layered;
}
}

View File

@ -0,0 +1,64 @@
/*
*
* Copyright 2016 jshook
* 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 activityconfig.rawyaml;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
public class BlockParams extends Tags {
private String name = "";
private Map<String, String> bindings = new LinkedHashMap<>();
private Map<String, String> params = new LinkedHashMap<>();
public BlockParams() {}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Map<String, String> getBindings() {
return Collections.unmodifiableMap(bindings);
}
public void setBindings(Map<String, String> bindings) {
this.bindings.clear();
this.bindings.putAll(bindings);
}
public Map<String, String> getParams() {
return params;
}
public void setParams(Map<String, String> config) {
this.params.clear();
this.params.putAll(config);
}
public void applyBlockParams(BlockParams other) {
setName(other.getName());
setBindings(other.getBindings());
setTags(other.getTags());
setParams(other.getParams());
}
}

View File

@ -0,0 +1,86 @@
/*
*
* Copyright 2016 jshook
* 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 activityconfig.rawyaml;
import java.util.Iterator;
import java.util.Map;
import java.util.Optional;
public class RawStmtDef extends BlockParams {
private String statement;
public RawStmtDef() {
}
public RawStmtDef(String name, String statement) {
setName(name);
this.statement = statement;
}
@SuppressWarnings("unchecked")
public RawStmtDef(String defaultName, Map<String, Object> map) {
Optional.ofNullable((String) map.remove("stmt")).ifPresent(this::setStmt);
Optional.ofNullable((String) map.remove("statement")).ifPresent(this::setStmt);
Optional.ofNullable((String) map.remove("name")).ifPresent(this::setName);
Optional.ofNullable((Map<String, String>) map.remove("tags")).ifPresent(this::setTags);
Optional.ofNullable((Map<String, String>) map.remove("bindings")).ifPresent(this::setBindings);
Optional.ofNullable((Map<String, String>) map.remove("params")).ifPresent(this::setParams);
// Depends on order stability, relying on LinkedHashMap -- Needs stability unit tests
if (this.statement == null) {
Iterator<Map.Entry<String, Object>> iterator = map.entrySet().iterator();
if (!iterator.hasNext()) {
throw new RuntimeException("undefined-name-statement-tuple:" +
" The statement is not set, and no statements remain to pull 'name: statement' values from." +
" For more details on this error see " +
"the troubleshooting section of the YAML format" +
" docs for undefined-name-statement-tuple");
}
Map.Entry<String, Object> firstEntry = iterator.next();
setStmt((String) firstEntry.getValue());
map.remove(firstEntry.getKey());
if (getName().isEmpty()) {
setName(firstEntry.getKey());
} else {
throw new RuntimeException("redefined-name-in-statement-tuple: Statement name has already been set by name parameter. Remove the name parameter for a statement definition map." +
" For more details on this error see " +
"the troubleshooting section in the " +
"YAML format docs for redefined-name-statement-tuple");
}
}
if (getName().isEmpty()) {
setName(defaultName);
}
map.forEach((key, value) -> getParams().put(key, String.valueOf(value)));
}
public String getStmt() {
return statement;
}
private void setStmt(String statement) {
this.statement = statement;
}
public String getName() {
return getParams().getOrDefault("name", super.getName());
}
}

View File

@ -0,0 +1,27 @@
/*
*
* Copyright 2016 jshook
* 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 activityconfig.rawyaml;
/**
* A StmtsDef contains a list of rawStmts, as well as all of the optional
* block parameters that can be assigned to {@link BlockParams}, which includes
* a name, config values, data bindings, and filtering tags.
*/
public class RawStmtsBlock extends StatementsOwner {
}

View File

@ -0,0 +1,60 @@
/*
*
* Copyright 2016 jshook
* 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 activityconfig.rawyaml;
import java.util.ArrayList;
import java.util.List;
/**
* A statements doc can have both a list of statement blocks and/or a
* list of statements. It can also have all the block parameters
* assignable to {@link BlockParams}.
* <p>
* The reason for having support both statements or statement blocks
* is merely convenience. If you do not need or want to deal with the
* full blocks format, the extra structure gets in the way.
*/
public class RawStmtsDoc extends StatementsOwner {
private List<RawStmtsBlock> blocks = new ArrayList<>();
/**
* Return the list of statement blocks in this RawStmtsDoc.
* If raw statements are defined on this RawStmtsDoc, then a single
* StmtBlock containing those statements is prepended to the block list.
* Otherwise, the list of StmtBlocks is returned as-is.
*
* @return all logical statement blocks containing statements
*/
public List<RawStmtsBlock> getBlocks() {
List<RawStmtsBlock> stmtBlocks = new ArrayList<>();
if (!getRawStmtDefs().isEmpty()) {
RawStmtsBlock rawStmtsBlock = new RawStmtsBlock();
rawStmtsBlock.setName("block0");
rawStmtsBlock.setRawStmtDefs(getRawStmtDefs());
stmtBlocks.add(rawStmtsBlock);
}
stmtBlocks.addAll(this.blocks);
return stmtBlocks;
}
public void setBlocks(List<RawStmtsBlock> blocks) {
this.blocks.clear();
this.blocks.addAll(blocks);
}
}

View File

@ -0,0 +1,33 @@
/*
*
* Copyright 2016 jshook
* 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 activityconfig.rawyaml;
import java.util.List;
public class RawStmtsDocList {
private List<RawStmtsDoc> rawStmtsDocList;
public RawStmtsDocList(List<RawStmtsDoc> rawStmtsDocList) {
this.rawStmtsDocList = rawStmtsDocList;
}
public List<RawStmtsDoc> getStmtsDocs() {
return rawStmtsDocList;
}
}

View File

@ -0,0 +1,132 @@
/*
*
* Copyright 2016 jshook
* 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 activityconfig.rawyaml;
import activityconfig.snakecharmer.SnakeYamlCharmer;
import io.nosqlbench.activityimpl.ActivityInitializationError;
import io.nosqlbench.util.NosqlBenchFiles;
import org.slf4j.Logger;
import org.yaml.snakeyaml.TypeDescription;
import org.yaml.snakeyaml.Yaml;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
public class RawYamlStatementLoader {
List<Function<String, String>> stringTransformers = new ArrayList<>();
public RawYamlStatementLoader() {
}
public RawYamlStatementLoader(Function<String, String> stringTransformer) {
this.addTransformer(stringTransformer);
}
public RawStmtsDocList load(Logger logger, String fromPath, String... searchPaths) {
String data = loadRawFile(logger, fromPath, searchPaths);
data = applyTransforms(logger, data);
return parseYaml(logger, data);
}
public void addTransformer(Function<String, String> transformer) {
stringTransformers.add(transformer);
}
protected String loadRawFile(Logger logger, String fromPath, String... searchPaths) {
InputStream stream = NosqlBenchFiles.findRequiredStreamOrFile(fromPath, "yaml", searchPaths);
try (BufferedReader buffer = new BufferedReader(new InputStreamReader(stream))) {
return buffer.lines().collect(Collectors.joining("\n"));
} catch (Exception e) {
throw new RuntimeException(
"Error while reading YAML from search paths:" + Arrays.toString(searchPaths) + ":" + e.getMessage(), e
);
}
}
protected String applyTransforms(Logger logger, String data) {
for (Function<String, String> xform : stringTransformers) {
try {
if (logger != null) logger.debug("Applying string transformer to yaml data:" + xform);
data = xform.apply(data);
} catch (Exception e) {
RuntimeException t = new ActivityInitializationError("Error applying string applyTransforms to input", e);
if (logger != null) logger.error(t.getMessage(), t);
throw t;
}
}
return data;
}
protected RawStmtsDocList parseYaml(Logger logger, String data) {
Yaml yaml = getCustomYaml();
try {
Iterable<Object> objects = yaml.loadAll(data);
List<RawStmtsDoc> stmtListList = new ArrayList<>();
for (Object object : objects) {
RawStmtsDoc tgsd = (RawStmtsDoc) object;
stmtListList.add(tgsd);
}
return new RawStmtsDocList(stmtListList);
} catch (Exception e) {
if (logger != null) logger.error("yaml-construction-error: Error building configuration:"
+ e.getMessage() + "" +
" For more details on this error see the " +
"troubleshooting section of the YAML format docs " +
"for yaml-construction-error.", e);
throw e;
}
}
protected Yaml getCustomYaml() {
SnakeYamlCharmer charmer = new SnakeYamlCharmer(RawStmtsDoc.class);
charmer.addHandler(StatementsOwner.class, "statements", new StatementsReader());
charmer.addHandler(StatementsOwner.class, "statement", new StatementsReader());
TypeDescription tds = new TypeDescription(RawStmtsDoc.class);
tds.addPropertyParameters("blocks", RawStmtsBlock.class);
charmer.addTypeDescription(tds);
return new Yaml(charmer);
}
protected RawStmtsDocList loadString(Logger logger, String rawYaml) {
String data = applyTransforms(logger, rawYaml);
return parseYaml(logger, data);
}
private class StatementsReader implements SnakeYamlCharmer.FieldHandler {
@Override
public void handleMapping(Object object, Object nodeTuple) {
//System.out.println("Handling mapping for" + object +", nodes:" + nodeTuple);
if (object instanceof StatementsOwner) {
((StatementsOwner) object).setByObject(nodeTuple);
}
}
}
}

View File

@ -0,0 +1,81 @@
/*
*
* Copyright 2016 jshook
* 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 activityconfig.rawyaml;
import java.util.*;
public class StatementsOwner extends BlockParams {
private List<RawStmtDef> rawStmtDefs = new ArrayList<>();
public StatementsOwner() {
}
public List<RawStmtDef> getRawStmtDefs() {
return rawStmtDefs;
}
public void setRawStmtDefs(List<RawStmtDef> rawStmtDefs) {
this.rawStmtDefs = rawStmtDefs;
}
@SuppressWarnings("unchecked")
public void setByObject(Object object) {
if (object instanceof List) {
List<Object> stmtList = (List<Object>) object;
List<RawStmtDef> defs = new ArrayList<>(stmtList.size());
for (int i = 0; i < stmtList.size(); i++) {
String defaultName = "stmt"+(i+1);
Object o = stmtList.get(i);
if (o instanceof String) {
defs.add(new RawStmtDef(defaultName,(String)o));
} else if (o instanceof Map) {
defs.add(new RawStmtDef(defaultName,(Map<String,Object>)o));
} else {
throw new RuntimeException("Can not construct stmt def from object type:" + o.getClass());
}
}
this.setRawStmtDefs(defs);
} else if (object instanceof Map) {
Map<String,Object> map = (Map<String,Object>) object;
List<Map<String,Object>> itemizedMaps = new ArrayList<>();
for (Map.Entry<String, Object> entries : map.entrySet()) {
Object value = entries.getValue();
if (value instanceof Map) {
Map<String,Object> valueMap = ((Map<String,Object>)value);
valueMap.put("name", entries.getKey());
itemizedMaps.add(valueMap);
} else if (value instanceof String) {
Map<String,Object> stmtDetails = new HashMap<String,Object>() {{
put("name", entries.getKey());
put("stmt", entries.getValue());
}};
itemizedMaps.add(stmtDetails);
} else {
throw new RuntimeException("Unknown inner value type on map-based statement definition.");
}
}
setByObject(itemizedMaps);
} else if (object instanceof String) {
List<RawStmtDef> defs = new ArrayList<>();
defs.add(new RawStmtDef(null,(String)object));
} else {
throw new RuntimeException("Unknown object type: " + object.getClass());
}
}
}

View File

@ -0,0 +1,40 @@
/*
*
* Copyright 2016 jshook
* 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 activityconfig.rawyaml;
import io.nosqlbench.util.Tagged;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
public class Tags implements Tagged {
private Map<String, String> tags = new LinkedHashMap<>();
@Override
public Map<String, String> getTags() {
return Collections.unmodifiableMap(tags);
}
public void setTags(Map<String, String> tags) {
this.tags.clear();
this.tags.putAll(tags);
}
}

View File

@ -0,0 +1,110 @@
/*
*
* Copyright 2016 jshook
* 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 activityconfig.snakecharmer;
import org.yaml.snakeyaml.constructor.Constructor;
import org.yaml.snakeyaml.constructor.SafeConstructor;
import org.yaml.snakeyaml.nodes.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* This is as arcane and strange looking as it sounds. SnakeYaml has a design that does not
* make it easy to mix and match bean-style constructions with generic collections or variant
* YAML structure (as allowed by the YAML spec), so this is a set of surgical APIs that
* help to do such.
*
* It would be a nice improvement to be able to drop these classes and rely instead directly on
* SnakeYaml APIs of similar flavor if/when it can do so, or if/when the documentation explains
* more cleanly how to do so.
*/
public class SnakeYamlCharmer extends Constructor {
private final Map<String,HandlerDef> handlerDefs = new HashMap<>();
private final ReSafeConstructor ctor = new ReSafeConstructor();
public SnakeYamlCharmer(Class<?> targetClass) {
super(targetClass);
this.yamlClassConstructors.put(NodeId.mapping, new DelegatorConstructor());
}
public <T> void addHandler(Class<T> typeName, String fieldName, FieldHandler fieldHandler) {
this.handlerDefs.put(fieldName, new HandlerDef(fieldName, typeName, fieldHandler));
}
public interface FieldHandler {
void handleMapping(Object object, Object subObject);
}
private static class HandlerDef {
final String fieldName;
final Class<?> handlerClass;
final FieldHandler handler;
HandlerDef(String fieldName, Class<?> handlerClass, FieldHandler handler) {
this.fieldName = fieldName;
this.handlerClass = handlerClass;
this.handler = handler;
}
}
private class DelegatorConstructor extends Constructor.ConstructMapping {
@Override
protected Object constructJavaBean2ndStep(MappingNode node, Object object) {
if (node.getNodeId()==NodeId.mapping) {
List<NodeTuple> toExtract = new ArrayList<>();
// Find all matching field names and remember them
for (NodeTuple nodeTuple : node.getValue()) {
Node prospectNode = nodeTuple.getKeyNode();
if (nodeTuple.getKeyNode() instanceof ScalarNode) {
ScalarNode nameNode = (ScalarNode) prospectNode;
if (SnakeYamlCharmer.this.handlerDefs.keySet().contains(nameNode.getValue())) {
toExtract.add(nodeTuple);
}
}
}
/**
* Remove each matching field name by node and owning object
* Construct a safe collection-based Java object
* Call the delegated handler for the owning object and the sub-object
*/
for (NodeTuple nodeTuple : toExtract) {
node.getValue().remove(nodeTuple);
String nodeName = ((ScalarNode) nodeTuple.getKeyNode()).getValue();
Object subObject = ctor.constructObject(nodeTuple.getValueNode());
HandlerDef handlerDef = SnakeYamlCharmer.this.handlerDefs.get(nodeName);
handlerDef.handler.handleMapping(object,subObject);
}
}
return super.constructJavaBean2ndStep(node,object);
}
}
public static class ReSafeConstructor extends SafeConstructor {
@Override
public Object constructObject(Node node) {
return super.constructObject(node);
}
}
}

View File

@ -0,0 +1,70 @@
/*
*
* Copyright 2016 jshook
* 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 activityconfig.yaml;
import activityconfig.MultiMapLookup;
import activityconfig.ParsedStmt;
import activityconfig.rawyaml.RawStmtDef;
import io.nosqlbench.util.Tagged;
import java.util.Map;
public class StmtDef implements Tagged {
private final RawStmtDef rawStmtDef;
private StmtsBlock block;
public StmtDef(StmtsBlock block, RawStmtDef rawStmtDef) {
this.block = block;
this.rawStmtDef = rawStmtDef;
}
public String getName() {
return block.getName() + "--" + rawStmtDef.getName();
}
public String getStmt() {
return rawStmtDef.getStmt();
}
public Map<String,String> getBindings() {
return new MultiMapLookup(rawStmtDef.getBindings(), block.getBindings());
}
public Map<String, String> getParams() {
return new MultiMapLookup(rawStmtDef.getParams(), block.getParams());
}
public Map<String,String> getTags() {
return new MultiMapLookup(rawStmtDef.getTags(), block.getTags());
}
@Override
public String toString() {
return "stmt(name:" + getName() + ", stmt:" + getStmt() + ", tags:(" + getTags() + "), params:(" + getParams() +"), bindings:(" + getBindings()+"))";
}
/**
* Parse the statement for anchors and return a richer view of the StmtDef which
* is simpler to use for most statement configuration needs.
* @return a new {@link ParsedStmt}
*/
public ParsedStmt getParsed() {
return new ParsedStmt(this);
}
}

View File

@ -0,0 +1,87 @@
/*
*
* Copyright 2016 jshook
* 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 activityconfig.yaml;
import activityconfig.MultiMapLookup;
import activityconfig.rawyaml.RawStmtDef;
import activityconfig.rawyaml.RawStmtsBlock;
import io.nosqlbench.util.Tagged;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
public class StmtsBlock implements Tagged, Iterable<StmtDef> {
private final static String NameToken = "name";
private final static String StmtToken = "stmt";
private final RawStmtsBlock rawStmtsBlock;
private StmtsDoc rawStmtsDoc;
private int blockIdx;
public StmtsBlock(RawStmtsBlock rawStmtsBlock, StmtsDoc rawStmtsDoc, int blockIdx) {
this.rawStmtsBlock = rawStmtsBlock;
this.rawStmtsDoc = rawStmtsDoc;
this.blockIdx = blockIdx;
}
public List<StmtDef> getStmts() {
List<StmtDef> rawStmtDefs = new ArrayList<>();
List<RawStmtDef> statements = rawStmtsBlock.getRawStmtDefs();
for (int i = 0; i < statements.size(); i++) {
rawStmtDefs.add(
new StmtDef(this,statements.get(i))
);
}
return rawStmtDefs;
}
public String getName() {
StringBuilder sb = new StringBuilder();
if (!rawStmtsDoc.getName().isEmpty()) {
sb.append(rawStmtsDoc.getName()).append("--");
}
if (!rawStmtsBlock.getName().isEmpty()) {
sb.append(rawStmtsBlock.getName());
} else {
sb.append("block").append(blockIdx);
}
return sb.toString();
}
public Map<String, String> getTags() {
return new MultiMapLookup(rawStmtsBlock.getTags(), rawStmtsDoc.getTags());
}
public Map<String, String> getParams() {
return new MultiMapLookup(rawStmtsBlock.getParams(), rawStmtsDoc.getParams());
}
public Map<String, String> getBindings() {
return new MultiMapLookup(rawStmtsBlock.getBindings(), rawStmtsDoc.getBindings());
}
@Override
public Iterator<StmtDef> iterator() {
return getStmts().iterator();
}
}

View File

@ -0,0 +1,107 @@
/*
*
* Copyright 2016 jshook
* 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 activityconfig.yaml;
import activityconfig.rawyaml.RawStmtsBlock;
import activityconfig.rawyaml.RawStmtsDoc;
import io.nosqlbench.util.Tagged;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* StmtsDoc creates a logical view of a statements doc that includes
* all inherited and overridden values for bindings, tags, and params.
*/
public class StmtsDoc implements Tagged, Iterable<StmtsBlock> {
private RawStmtsDoc rawStmtsDoc;
public StmtsDoc(RawStmtsDoc rawStmtsDoc) {
this.rawStmtsDoc = rawStmtsDoc;
}
/**
* @return a usable list of blocks, including inherited bindings, params, and tags
* from the parent doc
*/
public List<StmtsBlock> getBlocks() {
List<StmtsBlock> blocks = new ArrayList<>();
int blockIdx = 0;
for (RawStmtsBlock rawStmtsBlock : rawStmtsDoc.getBlocks()) {
String compositeName = rawStmtsDoc.getName() +
(rawStmtsBlock.getName().isEmpty() ? "" : "-" + rawStmtsBlock.getName());
StmtsBlock compositeBlock = new StmtsBlock(rawStmtsBlock, this, ++blockIdx);
blocks.add(compositeBlock);
}
return blocks;
}
/**
* @return a usable map of tags, including those inherited from the parent doc
*/
@Override
public Map<String, String> getTags() {
return rawStmtsDoc.getTags();
}
/**
* @return a usable map of parameters, including those inherited from the parent doc
*/
public Map<String, String> getParams() {
return rawStmtsDoc.getParams();
}
/**
* @return a usable map of bindings, including those inherited from the parent doc
*/
public Map<String, String> getBindings() {
return rawStmtsDoc.getBindings();
}
/**
* @return the name of this block
*/
public String getName() {
return rawStmtsDoc.getName();
}
/**
* @return The list of all included statements for all included block in this document,
* including the inherited and overridden values from the this doc and the parent block.
*/
public List<StmtDef> getStmts() {
return getBlocks().stream().flatMap(b -> b.getStmts().stream()).collect(Collectors.toList());
}
/**
* Allow StmtsDoc to be used in iterable loops.
* @return An iterator of {@link StmtsBlock}
*/
@Override
public Iterator<StmtsBlock> iterator() {
return getBlocks().iterator();
}
}

View File

@ -0,0 +1,85 @@
/*
*
* Copyright 2016 jshook
* 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 activityconfig.yaml;
import activityconfig.rawyaml.RawStmtsDocList;
import io.nosqlbench.util.TagFilter;
import java.util.*;
import java.util.stream.Collectors;
public class StmtsDocList implements Iterable<StmtsDoc> {
private RawStmtsDocList rawStmtsDocList;
public StmtsDocList(RawStmtsDocList rawStmtsDocList) {
this.rawStmtsDocList = rawStmtsDocList;
}
public List<StmtsDoc> getStmtDocs(String tagFilter) {
TagFilter tf = new TagFilter(tagFilter);
return getStmtDocs().stream()
.filter(tf::matchesTagged)
.collect(Collectors.toList());
}
public List<StmtsDoc> getStmtDocs() {
return rawStmtsDocList.getStmtsDocs().stream()
.map(StmtsDoc::new)
.collect(Collectors.toList());
}
public List<StmtDef> getStmts() {
return getStmts("");
}
/**
* @return The list of all included statements for all included blocks of in this document,
* including the inherited and overridden values from the this doc and the parent block.
* @param tagFilterSpec a comma-separated tag filter spec
*/
public List<StmtDef> getStmts(String tagFilterSpec) {
TagFilter ts = new TagFilter(tagFilterSpec);
List<StmtDef> stmts = getStmtDocs().stream()
.flatMap(d -> d.getStmts().stream())
.filter(ts::matchesTagged)
.collect(Collectors.toList());
return stmts;
}
@Override
public Iterator<StmtsDoc> iterator() {
return getStmtDocs().iterator();
}
/**
* Return the list of all bindings combined across all docs, not including
* the block or statement level bindings.
* @return A map of all bindings at the doc level.
*/
public Map<String,String> getDocBindings() {
LinkedHashMap<String,String> docBindings= new LinkedHashMap<>();
getStmtDocs().stream()
.map(StmtsDoc::getBindings)
.forEach(docBindings::putAll);
return docBindings;
}
}

View File

@ -0,0 +1,29 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.core;
/**
* An action is the core logic that occurs within an activity.
* Within a thread slot, a motor will continuously ask an action to process its input.
*
* To do anything useful in your action, you should implement {@link AsyncAction} or
* {@link SyncAction} directly.
*/
public interface Action {
default void init() {
}
}

View File

@ -0,0 +1,34 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.core;
/**
* An ActionDispenser is created for each Activity instance within a scenario.
* When a thread is created, the motor and its input and action instances are resolved.
* The ActionDispenser is responsible for choosing how the action is resolved,
* whether that is a shared thread-safe action or an action per slot.
*/
public interface ActionDispenser {
/**
* Resolve (find or create) an Action instance for the slot specified.
* The action is not required to be per-slot (per-thread), but any shared actions must be thread safe.
* @param slot The numbered slot within the activity instance for this action.
* @return A new or cached Action for the specified slot.
*/
Action getAction(int slot);
}

View File

@ -0,0 +1,28 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.core;
import java.util.Map;
/**
* Dispensers that implement this decorator interface might need to know about the other
* activities that are present in a configuration. Those dispensers will have th
*/
public interface ActivitiesAware {
void setActivitiesMap(Map<String,Activity> activities);
}

View File

@ -0,0 +1,184 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.core;
import com.codahale.metrics.Timer;
import io.nosqlbench.activityapi.cyclelog.filters.IntPredicateDispenser;
import io.nosqlbench.activityapi.input.InputDispenser;
import io.nosqlbench.activityapi.output.OutputDispenser;
import io.nosqlbench.activityapi.ratelimits.RateLimiter;
import io.nosqlbench.activityimpl.ActivityDef;
import io.nosqlbench.activityimpl.ParameterMap;
import io.nosqlbench.activityimpl.SimpleActivity;
import java.util.function.Supplier;
/**
* Provides the components needed to build and run an activity a runtime.
* The easiest way to build a useful Activity is to extend {@link SimpleActivity}.
*/
public interface Activity extends Comparable<Activity>, ActivityDefObserver {
/**
* Provide the activity with the controls needed to stop itself.
* @param activityController The dedicated control interface for this activity
*/
void setActivityController(ActivityController activityController);
ActivityController getActivityController();
/**
* Register an object which should be closed after this activity is shutdown.
*
* @param closeable An Autocloseable object
*/
void registerAutoCloseable(AutoCloseable closeable);
ActivityDef getActivityDef();
default String getAlias() {
return getActivityDef().getAlias();
}
default ParameterMap getParams() {
return getActivityDef().getParams();
}
default void initActivity() {
}
/**
* Close all autocloseables that have been registered with this Activity.
*/
void closeAutoCloseables();
MotorDispenser getMotorDispenserDelegate();
void setMotorDispenserDelegate(MotorDispenser motorDispenser);
InputDispenser getInputDispenserDelegate();
void setInputDispenserDelegate(InputDispenser inputDispenser);
ActionDispenser getActionDispenserDelegate();
void setActionDispenserDelegate(ActionDispenser actionDispenser);
IntPredicateDispenser getResultFilterDispenserDelegate();
void setResultFilterDispenserDelegate(IntPredicateDispenser resultFilterDispenser);
OutputDispenser getMarkerDispenserDelegate();
void setOutputDispenserDelegate(OutputDispenser outputDispenser);
RunState getRunState();
void setRunState(RunState runState);
default void shutdownActivity() {
}
default String getCycleSummary() {
return getActivityDef().getCycleSummary();
}
/**
* Get the current cycle rate limiter for this activity.
* The cycle rate limiter is used to throttle the rate at which
* cycles are dispatched across all threads in the activity
* @return the cycle {@link RateLimiter}
*/
RateLimiter getCycleLimiter();
/**
* Set the cycle rate limiter for this activity. This method should only
* be used in a non-concurrent context. Otherwise, the supplier version
* {@link #getCycleRateLimiter(Supplier)} should be used.
* @param rateLimiter The cycle {@link RateLimiter} for this activity
*/
void setCycleLimiter(RateLimiter rateLimiter);
/**
* Get or create the cycle rate limiter in a safe way. Implementations
* should ensure that this method is synchronized or that each requester
* gets the same cycle rate limiter for the activity.
* @param supplier A {@link RateLimiter} {@link Supplier}
* @return An extant or newly created cycle {@link RateLimiter}
*/
RateLimiter getCycleRateLimiter(Supplier<? extends RateLimiter> supplier);
/**
* Get the current stride rate limiter for this activity.
* The stride rate limiter is used to throttle the rate at which
* new strides are dispatched across all threads in an activity.
* @return The stride {@link RateLimiter}
*/
RateLimiter getStrideLimiter();
/**
* Set the stride rate limiter for this activity. This method should only
* be used in a non-concurrent context. Otherwise, the supplier version
* {@link #getStrideRateLimiter(Supplier)}} should be used.
* @param rateLimiter The stride {@link RateLimiter} for this activity.
*/
void setStrideLimiter(RateLimiter rateLimiter);
/**
* Get or create the stride {@link RateLimiter} in a concurrent-safe
* way. Implementations should ensure that this method is synchronized or
* that each requester gets the same stride rate limiter for the activity.
* @param supplier A {@link RateLimiter} {@link Supplier}
* @return An extant or newly created stride {@link RateLimiter}
*/
RateLimiter getStrideRateLimiter(Supplier<? extends RateLimiter> supplier);
/**
* Get the current phase rate limiter for this activity.
* The phase rate limiter is used to throttle the rate at which
* new phases are dispatched across all threads in an activity.
* @return The stride {@link RateLimiter}
*/
RateLimiter getPhaseLimiter();
Timer getResultTimer();
/**
* Set the phase rate limiter for this activity. This method should only
* be used in a non-concurrent context. Otherwise, the supplier version
* {@link #getPhaseRateLimiter(Supplier)}} should be used.
* @param rateLimiter The phase {@link RateLimiter} for this activity.
*/
void setPhaseLimiter(RateLimiter rateLimiter);
/**
* Get or create the phase {@link RateLimiter} in a concurrent-safe
* way. Implementations should ensure that this method is synchronized or
* that each requester gets the same phase rate limiter for the activity.
* @param supplier A {@link RateLimiter} {@link Supplier}
* @return An extant or newly created phase {@link RateLimiter}
*/
RateLimiter getPhaseRateLimiter(Supplier<? extends RateLimiter> supplier);
/**
* Get or create the instrumentation needed for this activity. This provides
* a single place to find and manage, and document instrumentation that is
* uniform across all activities.
*
* @return A new or existing instrumentation object for this activity.
*/
ActivityInstrumentation getInstrumentation();
}

View File

@ -0,0 +1,23 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.core;
public interface ActivityController {
void stopActivityWithReasonAsync(String reason);
void stopActivityWithErrorAsync(Throwable throwable);
}

View File

@ -0,0 +1,21 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.core;
public interface ActivityControlsListener {
}

View File

@ -0,0 +1,29 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.core;
import io.nosqlbench.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);
}

View File

@ -0,0 +1,92 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.core;
import com.codahale.metrics.Counter;
import com.codahale.metrics.Timer;
/**
* All the accessors of the metrics that will be used for each activity instance.
* Implementors of this interface should ensure that the methods are synchronized
* to avoid race conditions during lazy init from callers.
*
*
*/
public interface ActivityInstrumentation {
/**
* The input timer measures how long it takes to get the cycle value to be used for
* an operation.
* @return A new or existing Timer
*/
Timer getOrCreateInputTimer();
/**
* The strides service timer measures how long it takes to complete a stride of work.
* @return A new or existing Timer
*/
Timer getOrCreateStridesServiceTimer();
/**
* The strides response timer measures the total response time from the scheduled
* time a stride should start to when it completed. Stride scheduling is only defined
* when it is implied by a stride rate limiter, so this method should return null if
* there is no strides rate limiter.
* @return A new or existing Timer if appropriate, else null
*/
Timer getStridesResponseTimerOrNull();
/**
* The cycles service timer measures how long it takes to complete a cycle of work.
* @return A new or existing Timer
*/
Timer getOrCreateCyclesServiceTimer();
/**
* The cycles response timer measures the total response time from the scheduled
* time an operation should start to when it is completed. Cycle scheduling is only defined
* when it is implied by a cycle rate limiter, so this method should return null if
* there is no cycles rate limiter.
* @return A new or existing Timer if appropriate, else null
*/
Timer getCyclesResponseTimerOrNull();
/**
* The phases service timer measures how long it takes to complete a phase of work.
* @return A new or existing Timer
*/
Timer getOrCreatePhasesServiceTimer();
/**
* The phases response timer measures the total response time from the scheduled
* time a phase should start to when it is completed. Phase scheduling is only defined
* when it is implied by a phase rate limiter, so this method should return null if
* there is no phases rate limiter.
* @return A new or existing Timer if appropriate, else null
*/
Timer getPhasesResponseTimerOrNull();
/**
* The pending ops counter keeps track of how many ops are submitted or in-flight, but
* which haven't been completed yet.
* @return A new or existing Counter
*/
Counter getOrCreatePendingOpCounter();
Counter getOrCreateOpTrackerBlockedCounter();
}

View File

@ -0,0 +1,142 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.core;
import io.nosqlbench.activityapi.input.InputDispenser;
import io.nosqlbench.activityapi.output.OutputDispenser;
import io.nosqlbench.activityimpl.ActivityDef;
import io.nosqlbench.activityimpl.CoreServices;
import io.nosqlbench.activityimpl.SimpleActivity;
import io.nosqlbench.activityimpl.action.CoreActionDispenser;
import io.nosqlbench.activityimpl.motor.CoreMotorDispenser;
import io.nosqlbench.util.Named;
import io.nosqlbench.util.SimpleServiceLoader;
import java.util.Map;
import java.util.Optional;
/**
* <p>An ActivityType is the central extension point in NB for new
* activity types drivers. It is responsible for naming the activity type, as well as providing
* the input, activity, and motor instances that will be assembled into an activity.</p>
* <p>At the very minimum, a useful implementation of an activity type should provide
* an action dispenser. Default implementations of input and motor dispensers are provided,
* and by extension, default inputs and motors.</p>
*/
public interface ActivityType<A extends Activity> extends Named {
public static SimpleServiceLoader<ActivityType> FINDER = new SimpleServiceLoader<>(ActivityType.class);
/**
* Return the short name of this activity type. The fully qualified name of an activity type is
* this value, prefixed by the package of the implementing class.
*
* @return An activity type name, like "diag"
*/
String getName();
/**
* Create an instance of an activity from the activity type.
*
* @param activityDef the definition that initializes and controls the activity.
* @return a distinct Activity instance for each call
*/
@SuppressWarnings("unchecked")
default A getActivity(ActivityDef activityDef) {
SimpleActivity activity = new SimpleActivity(activityDef);
return (A) activity;
}
/**
* Create an instance of an activity that ties together all the components into a usable
* activity instance. This is the method that should be called by executor classes.
*
* @param activityDef the definition that initializez and controlls the activity.
* @param activities a map of existing activities
* @return a distinct activity instance for each call
*/
default Activity getAssembledActivity(ActivityDef activityDef, Map<String, Activity> activities) {
A activity = getActivity(activityDef);
InputDispenser inputDispenser = getInputDispenser(activity);
if (inputDispenser instanceof ActivitiesAware) {
((ActivitiesAware) inputDispenser).setActivitiesMap(activities);
}
activity.setInputDispenserDelegate(inputDispenser);
ActionDispenser actionDispenser = getActionDispenser(activity);
if (actionDispenser instanceof ActivitiesAware) {
((ActivitiesAware) actionDispenser).setActivitiesMap(activities);
}
activity.setActionDispenserDelegate(actionDispenser);
OutputDispenser outputDispenser = getOutputDispenser(activity).orElse(null);
if (outputDispenser !=null && outputDispenser instanceof ActivitiesAware) {
((ActivitiesAware) outputDispenser).setActivitiesMap(activities);
}
activity.setOutputDispenserDelegate(outputDispenser);
MotorDispenser motorDispenser = getMotorDispenser(activity, inputDispenser, actionDispenser, outputDispenser);
if (motorDispenser instanceof ActivitiesAware) {
((ActivitiesAware) motorDispenser).setActivitiesMap(activities);
}
activity.setMotorDispenserDelegate(motorDispenser);
return activity;
}
/**
* This method will be called <em>once</em> per action instance.
*
* @param activity The activity instance that will parameterize the returned MarkerDispenser instance.
* @return an instance of MarkerDispenser
*/
default Optional<OutputDispenser> getOutputDispenser(A activity) {
return CoreServices.getOutputDispenser(activity);
}
/**
* This method will be called <em>once</em> per action instance.
*
* @param activity The activity instance that will parameterize the returned ActionDispenser instance.
* @return an instance of ActionDispenser
*/
default ActionDispenser getActionDispenser(A activity) {
return new CoreActionDispenser(activity);
}
/**
* Return the InputDispenser instance that will be used by the associated activity to create Input factories
* for each thread slot.
*
* @param activity the Activity instance which will parameterize this InputDispenser
* @return the InputDispenser for the associated activity
*/
default InputDispenser getInputDispenser(A activity) {
return CoreServices.getInputDispenser(activity);
}
default <T> MotorDispenser<T> getMotorDispenser(
A activity,
InputDispenser inputDispenser,
ActionDispenser actionDispenser,
OutputDispenser outputDispenser) {
return new CoreMotorDispenser<T> (activity, inputDispenser, actionDispenser, outputDispenser);
}
}

View File

@ -0,0 +1,96 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.core;
import io.nosqlbench.activityapi.core.ops.fluent.opfacets.TrackedOp;
import java.util.function.LongFunction;
/**
* <p>An AsyncAction allows an activity type to implement asynchronous
* operations within each thread.
* </p>
*
*/
public interface AsyncAction<D> extends Action {
LongFunction<D> getOpInitFunction();
/**
* THIS DOCUMENTATION IS LIKELY OUT OF DATE
*
* The responsibility for tracking async pending against concurrency limits,
* including signaling for thread state, has been moved into the async
* event loop of the core motor. If this experiment holds, then the docs
* here must be rewritten to be accurate for that approach.
**
*
* Enqueue a cycle to be executed by the action. This method should block unless
* or until the action accepts the cycle to be processed.
* This method is not allowed to reject a cycle. If it is unable to accept the
* cycle for any reason, it must throw an exception.
*
* Since the action implementation is presumed to be running some externally
* asynchronous process to support the action, it is up to the action itself
* to control when to block enqueueing. If the action is not actually asynchronous,
* then it may need to do downstream processing in order to open room in its
* concurrency limits for the new cycle.
*
* Each action implementation is responsible for tracking and controlling
* its own limits of concurrency. The {@link BaseAsyncAction} base class is a
* convenient starting point for such implementations.
*
* If the action is known to have additional open slots for an operations to
* be started (according to the configured concurrency limits),
* then it can signal such by returning true from this method.
*
* @param opc The op context that holds state for this operation
* @return true, if the action is ready immediately for another operation
*/
boolean enqueue(TrackedOp<D> opc);
// /**
// * Await completion of all pending operations for this thread.
// * If all tasks are already complete when this is called, then it
// * should return immediately.
// * @param timeout Timeout in milliseconds
// * @return true, if all tasks pending for this thread are completed.
// */
// boolean awaitCompletion(long timeout);
// /**
// * Once constructed, all async actions are expected to provide a tracker
// * object which can be used to register callback for operational events,
// * as well as to provide a diagnostic view of what is happening with
// * the number of pending operations per thread.
// * @return An async operations tracker
// */
// OpTracker<D> getTracker();
// /**
// * When the activity needs to create a new op context which tracks all
// * things interesting for the operation, it will call this method.
// * The payload type D determines any and all of what an async action
// * may know about an op.
// *
// * @return A new op state of parameterized type D
// */
// D allocateOpData(long cycle);
}

View File

@ -0,0 +1,72 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.core;
import io.nosqlbench.activityapi.core.ops.fluent.opfacets.TrackedOp;
import io.nosqlbench.activityimpl.ActivityDef;
import io.nosqlbench.activityimpl.ParameterMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @param <D> An type of state holder for an operation, holding everything unique to that cycle and operation
* @param <A> An type of of an Activity, a state holder for a runtime instance of an Activity
*/
public abstract class BaseAsyncAction<D, A extends Activity> implements AsyncAction<D>, Stoppable, ActivityDefObserver {
private final static Logger logger = LoggerFactory.getLogger("BaseAsyncAction");
protected final A activity;
protected int slot;
protected boolean running = true;
public BaseAsyncAction(A activity, int slot) {
this.activity = activity;
this.slot = slot;
onActivityDefUpdate(activity.getActivityDef());
}
@Override
public void onActivityDefUpdate(ActivityDef activityDef) {
ParameterMap params = activityDef.getParams();
params.getOptionalInteger("async").orElseThrow(
() -> new RuntimeException("the async parameter is required to activate async actions"));
}
public boolean enqueue(TrackedOp<D> opc) {
startOpCycle(opc);
return (running);
}
/**
* Implementations that extend this base class can call this method in order to put
* an operation in flight.
*
* @param opc A tracked operation with state of parameterized type D
*/
public abstract void startOpCycle(TrackedOp<D> opc);
@Override
public void requestStop() {
logger.info(this.toString() + " requested to stop.");
this.running = false;
}
}

View File

@ -0,0 +1,109 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.core;
import com.codahale.metrics.Counter;
import com.codahale.metrics.Timer;
import io.nosqlbench.activityimpl.ActivityDef;
import io.nosqlbench.activityimpl.ParameterMap;
import io.nosqlbench.metrics.ActivityMetrics;
public class CoreActivityInstrumentation implements ActivityInstrumentation {
private static final String STRICTMETRICNAMES = "strictmetricnames";
private static final String WAIT_TIME = ".waittime";
private static final String SERVICE_TIME = ".servicetime";
private static final String RESPONSE_TIME = ".responsetime";
private final Activity activity;
private final ActivityDef def;
private final ParameterMap params;
private final String svcTimeSuffix;
private final boolean strictNaming;
public CoreActivityInstrumentation(Activity activity) {
this.activity = activity;
this.def = activity.getActivityDef();
this.params = def.getParams();
this.strictNaming = params.getOptionalBoolean(STRICTMETRICNAMES).orElse(true);
svcTimeSuffix = strictNaming ? SERVICE_TIME : "";
}
@Override
public synchronized Timer getOrCreateInputTimer() {
String metricName = "read_input";
return ActivityMetrics.timer(def, metricName);
}
@Override
public synchronized Timer getOrCreateStridesServiceTimer() {
return ActivityMetrics.timer(def, "strides" + SERVICE_TIME);
}
@Override
public synchronized Timer getStridesResponseTimerOrNull() {
if (activity.getStrideLimiter()==null) {
return null;
}
return ActivityMetrics.timer(def, "strides" + RESPONSE_TIME);
}
@Override
public synchronized Timer getOrCreateCyclesServiceTimer() {
return ActivityMetrics.timer(def, "cycles" + svcTimeSuffix);
}
@Override
public synchronized Timer getCyclesResponseTimerOrNull() {
if (activity.getCycleLimiter()==null) {
return null;
}
String metricName = "cycles" + RESPONSE_TIME;
return ActivityMetrics.timer(def, metricName);
}
@Override
public synchronized Timer getOrCreatePhasesServiceTimer() {
return ActivityMetrics.timer(def, "phases" + SERVICE_TIME);
}
@Override
public synchronized Timer getPhasesResponseTimerOrNull() {
if (activity.getPhaseLimiter()==null) {
return null;
}
return ActivityMetrics.timer(def,"phases" + RESPONSE_TIME);
}
@Override
public synchronized Counter getOrCreatePendingOpCounter() {
String metricName = "pending_ops";
return ActivityMetrics.counter(def, metricName);
}
@Override
public synchronized Counter getOrCreateOpTrackerBlockedCounter() {
String metricName = "optracker_blocked";
return ActivityMetrics.counter(def, metricName);
}
}

View File

@ -0,0 +1,24 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.core;
import com.codahale.metrics.MetricRegistry;
public interface MetricRegistryService {
MetricRegistry getMetricRegistry();
}

View File

@ -0,0 +1,60 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.core;
import io.nosqlbench.activityapi.input.Input;
import io.nosqlbench.activityimpl.SlotStateTracker;
/**
* The core threading harness within an activity.
*/
public interface Motor<T> extends Runnable, Stoppable {
/**
* Set the input on this motor. It will be read from each cycle before applying the action.
*
* @param input an instance of ActivityInput
* @return this ActivityMotor, for method chaining
*/
Motor<T> setInput(Input input);
Input getInput();
/**
* Set the action on this motor. It will be applied to each input.
*
* @param action an instance of activityAction
* @return this ActivityMotor, for method chaining
*/
Motor<T> setAction(Action action);
Action getAction();
/**
* get the slotId which this motor is assigned to within the activity instance.
* @return long slot id
*/
long getSlotId();
/**
* Get a description of the current slot run status.
* @return - a value from the {@link RunState} enum
*/
SlotStateTracker getSlotStateTracker();
}

View File

@ -0,0 +1,38 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.core;
import io.nosqlbench.activityimpl.ActivityDef;
/**
* A MotorDispenser is created for each Activity instance within a scenario.
* When a thread is created, the motor and its input and action instances are resolved.
* The MotorDispenser is responsible for choosing how the motor is resolved,
* whether that is a shared thread-safe motor or, more conventionally, a separate motor per slot.
*/
public interface MotorDispenser<T> {
/**
* 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.
*
* @param activityDef the ActivityDef which will be used to parameterize the returned motor
* @param slot The numbered slot within the activity instance for this motor
* @return A new or cached Motor for the specified slot.
*/
Motor<T> getMotor(ActivityDef activityDef, int slot);
}

View File

@ -0,0 +1,55 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.core;
/**
* A continuing action can ask to be iterated within the cycle.
* <p>
* Motors must:
* <ul>
* <li>Detect when an action is a multi-phase action at initialization time, not in the inner loop</li>
* <li>Call accept(cycle) as normal.</li>
* <li>If the action is a multi-phase action, keep calling accept(cycle), with the same cycle number as above,
* until incomplete returns false.</li>
* </ul>
*/
public interface MultiPhaseAction extends Action {
/**
* Signal to the caller whether or not the current multi-phase is completed.
*
* @return true when the action is not yet complete.
*/
boolean incomplete();
/**
* <p>Apply a work function to an input value, producing an int status code.</p>
* <p>This iterative interface represents work that occurs within the scope
* of an existing action cycle. The last value returned by this phase loop will
* take the place of the value returned by {@link SyncAction#runCycle(long)}</p>
*
* <p>This will be called iteratively so long as {@link #incomplete()} returns true.</p>
*
* <p>The meaning of status codes is activity specific, however, negative values are reserved.</p>
*
* @param value a long input
* @return an int status
*/
int runPhase(long value);
}

View File

@ -0,0 +1,25 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.core;
public interface ProgressMeter {
double getProgress();
String getProgressName();
RunState getProgressState();
String getProgressDetails();
}

View File

@ -0,0 +1,102 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.core;
public enum RunState {
// Initial state after creation of this control
Uninitialized("i⌀"),
// This thread has been queued to run, but hasn't signaled yet that it is full started
// This must be set by the executor before executing the slot runnable
Starting("s⏫"),
// This thread is running. This should only be set by the controlled thread
Running("R\u23F5"),
// This thread has completed all of its activity, and will do no further work without new input
Finished("F⏯"),
// The thread has been requested to stop. This says nothing of the internal state.
Stopping("s⏬"),
// The thread has stopped. This should only be set by the controlled thread
Stopped("_\u23F9");
private String runcode;
RunState(String runcode) {
this.runcode = runcode;
}
public String getCode() {
return this.runcode;
}
public boolean canTransitionTo(RunState to) {
switch (this) {
default:
return false;
case Uninitialized: // A motor was just created. This is its initial state.
switch (to) {
case Starting: // a motor has been reserved for an execution command
return true;
default:
return false;
}
case Starting:
switch (to) {
case Running: // a motor has indicated that is in the run() method
case Finished: // a motor has exhausted its input, and has declined to go into started mode
return true;
default:
return false;
}
case Running:
switch (to) {
case Stopping: // A request was made to stop the motor before it finished
case Finished: // A motor has exhausted its input, and is finished with its work
return true;
default:
return false;
}
case Stopping:
switch (to) {
case Stopped: // A motor was stopped by request before exhausting input
return true;
default:
return false;
}
case Stopped:
switch (to) {
case Running: // A motor was restarted after being stopped
return true;
default:
return false;
}
case Finished:
switch (to) {
case Running: // A motor was restarted?
return true;
// not useful as of yet.
// Perhaps this will be allowed via explicit reset of input stream.
// If the input isn't reset, then trying to start a finished motor
// will cause it to short-circuit back to Finished state.
default:
return false;
}
}
}
}

View File

@ -0,0 +1,21 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.core;
public interface Shutdownable {
void shutdown();
}

View File

@ -0,0 +1,22 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.core;
public interface Startable {
void start();
}

View File

@ -0,0 +1,26 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.core;
public interface Stoppable {
/**
* Ask this component to stop cycling. This is an asynchronous request. Once the current active cycle
* completes, the request will cause the component to stop cooperatively.
*/
void requestStop();
}

View File

@ -0,0 +1,34 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.core;
public interface SyncAction extends Action {
/**
* <p>Apply a work function to an input value, producing an int status code.</p>
* The meaning of status codes is activity specific, however the values Integer.MIN_VALUE,
* and Integer.MAX_VALUE are reserved.
*
* @param value a long input
* @return an int status
*/
default int runCycle(long value) {
return (int) value % 100;
}
}

View File

@ -0,0 +1,29 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.core;
public interface longIntervalSupplier {
/**
* Get the next interval to be consumed by the caller, where the
* first value is the returned value, and the last value is
* one less than the first value plus the stride.
* @param stride How many values to request
* @return the base value of the interval to consume
*/
long getCycleInterval(int stride);
}

View File

@ -0,0 +1,5 @@
package io.nosqlbench.activityapi.core.ops.fluent;
public interface FluentOp {
}

View File

@ -0,0 +1,22 @@
package io.nosqlbench.activityapi.core.ops.fluent;
import io.nosqlbench.activityapi.core.ops.fluent.opfacets.OpEvents;
import io.nosqlbench.activityapi.core.ops.fluent.opfacets.TrackedOp;
import java.util.function.LongFunction;
public interface OpTracker<D> extends OpEvents<D> {
void setMaxPendingOps(int maxPendingOps);
int getMaxPendingOps();
boolean isFull();
int getPendingOps();
void setCycleOpFunction(LongFunction<D> newOpFunction);
// By making the op tracker the factory for ops, we allow it to hook their event streams
TrackedOp<D> newOp(long cycle, OpEvents<D> strideTracker);
boolean awaitCompletion(long timeout);
}

View File

@ -0,0 +1,166 @@
package io.nosqlbench.activityapi.core.ops.fluent;
import com.codahale.metrics.Counter;
import com.codahale.metrics.Timer;
import io.nosqlbench.activityapi.core.Activity;
import io.nosqlbench.activityapi.core.ActivityDefObserver;
import io.nosqlbench.activityapi.core.ops.fluent.opfacets.*;
import io.nosqlbench.activityimpl.ActivityDef;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.LongFunction;
/**
* This tracker keeps track of the state of operations associated with it.
*
* @param <D> The payload data type of the associated Op, based on OpImpl
*/
public class OpTrackerImpl<D> implements OpTracker<D>, ActivityDefObserver {
private final AtomicInteger pendingOps = new AtomicInteger(0);
private final String label;
private final long slot;
private final Timer cycleServiceTimer;
private final Timer cycleResponseTimer;
private final Counter pendingOpsCounter;
private int maxPendingOps =1;
private LongFunction<D> cycleOpFunction;
public OpTrackerImpl(Activity activity, long slot) {
this.slot = slot;
this.label = "tracker-" + slot + "_" + activity.getAlias();
this.pendingOpsCounter = activity.getInstrumentation().getOrCreatePendingOpCounter();
this.cycleServiceTimer = activity.getInstrumentation().getOrCreateCyclesServiceTimer();
this.cycleResponseTimer = activity.getInstrumentation().getCyclesResponseTimerOrNull();
}
// for testing
public OpTrackerImpl(String name, int slot, Timer cycleServiceTimer, Timer cycleResponseTimer, Counter pendingOpsCounter) {
this.label = name;
this.slot = slot;
this.cycleResponseTimer = cycleResponseTimer;
this.cycleServiceTimer = cycleServiceTimer;
this.pendingOpsCounter = pendingOpsCounter;
}
@Override
public void onOpStarted(StartedOp<D> op) {
pendingOps.incrementAndGet();
pendingOpsCounter.inc();
}
@Override
public void onOpSuccess(SucceededOp<D> op) {
pendingOpsCounter.dec();
int pending = this.pendingOps.decrementAndGet();
cycleServiceTimer.update(op.getServiceTimeNanos(), TimeUnit.NANOSECONDS);
if (cycleResponseTimer !=null) { cycleResponseTimer.update(op.getResponseTimeNanos(), TimeUnit.NANOSECONDS); }
if (pending< maxPendingOps) {
synchronized (this) {
notify();
}
}
}
@Override
public void onOpSkipped(SkippedOp<D> op) {
pendingOpsCounter.dec();
int pending = this.pendingOps.decrementAndGet();
if (pending< maxPendingOps) {
synchronized (this) {
notify();
}
}
}
@Override
public void onOpFailure(FailedOp<D> op) {
pendingOpsCounter.dec();
int pending = this.pendingOps.decrementAndGet();
cycleServiceTimer.update(op.getServiceTimeNanos(), TimeUnit.NANOSECONDS);
if (cycleResponseTimer !=null) { cycleResponseTimer.update(op.getResponseTimeNanos(), TimeUnit.NANOSECONDS); }
if (pending< maxPendingOps) {
synchronized (this) {
notify();
}
}
}
@Override
public void setMaxPendingOps(int maxPendingOps) {
this.maxPendingOps =maxPendingOps;
synchronized (this) {
notifyAll();
}
}
@Override
public boolean isFull() {
return this.pendingOps.intValue()>=maxPendingOps;
}
@Override
public int getPendingOps() {
return pendingOps.intValue();
}
@Override
public void setCycleOpFunction(LongFunction<D> newOpFunction) {
this.cycleOpFunction = newOpFunction;
}
@Override
public TrackedOp<D> newOp(long cycle, OpEvents<D> strideTracker) {
D opstate = cycleOpFunction.apply(cycle);
OpImpl<D> op = new EventedOpImpl<>(this,strideTracker);
op.setCycle(cycle);
op.setData(opstate);
return op;
}
public int getMaxPendingOps() {
return maxPendingOps;
}
@Override
public synchronized boolean awaitCompletion(long timeout) {
long endAt = System.currentTimeMillis() + timeout;
while (getPendingOps() > 0 && System.currentTimeMillis() < endAt) {
try {
long waitfor = Math.max(0, endAt - System.currentTimeMillis());
wait(waitfor);
} catch (InterruptedException ignored) {
}
}
return getPendingOps() == 0;
}
@Override
public String toString() {
return "OpTracker-" + label + ":" + this.slot + " " + this.pendingOps.get() + "/" + maxPendingOps + " ops ";
}
@Override
public void onActivityDefUpdate(ActivityDef activityDef) {
this.maxPendingOps=getMaxPendingOpsForThisThread(activityDef);
}
private int getMaxPendingOpsForThisThread(ActivityDef def) {
int maxTotalOpsInFlight = def.getParams().getOptionalInteger("async").orElse(1);
int threads = def.getThreads();
return (maxTotalOpsInFlight / threads) + (slot < (maxTotalOpsInFlight % threads) ? 1 : 0);
}
}

View File

@ -0,0 +1,40 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.core.ops.fluent.opfacets;
import io.nosqlbench.activityapi.cyclelog.buffers.results.CycleResult;
/**
* A CompletedOp can be any of
* <UL>
* <LI>{@link SucceededOp}</LI>
* <LI>{@link FailedOp}</LI>
* <LI>{@link SkippedOp}</LI>
* </UL>
*
* It may be necessary to downcast a completed Op in order to
* get more contextual details from it.
*
* @param <D> The type of delegate needed for the
* implementing protocol
*/
public interface CompletedOp<D> extends Payload<D>, CycleResult {
long getStartedAtNanos();
public long getServiceTimeNanos();
public long getResponseTimeNanos();
}

View File

@ -0,0 +1,78 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.core.ops.fluent.opfacets;
public class EventedOpImpl<D> extends OpImpl<D> {
private OpEvents<D> opTracker;
private OpEvents<D> strideTracker;
public EventedOpImpl(OpEvents<D> opTracker, OpEvents<D> strideTracker) {
this.opTracker = opTracker;
this.strideTracker = strideTracker;
}
public EventedOpImpl(OpEvents<D> opTracker) {
this.opTracker = opTracker;
this.strideTracker = new NullTracker<>();
}
@Override
public StartedOp<D> start() {
super.start();
opTracker.onOpStarted(this);
strideTracker.onOpStarted(this);
return this;
}
@Override
public SucceededOp<D> succeed(int status) {
super.succeed(status);
opTracker.onOpSuccess(this);
strideTracker.onOpSuccess(this);
return this;
}
@Override
public FailedOp<D> fail(int status) {
super.fail(status);
opTracker.onOpFailure(this);
strideTracker.onOpFailure(this);
return this;
}
private static class NullTracker<D> implements OpEvents<D> {
@Override
public void onOpStarted(StartedOp<D> op) {
}
@Override
public void onOpSuccess(SucceededOp<D> op) {
}
@Override
public void onOpSkipped(SkippedOp<D> op) {
}
@Override
public void onOpFailure(FailedOp<D> op) {
}
}
}

View File

@ -0,0 +1,29 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.core.ops.fluent.opfacets;
import io.nosqlbench.activityapi.cyclelog.buffers.results.CycleResult;
/**
* A failed op is any operation which has an error, according to the semantics
* of the implementing activity type.
* @param <D> The delegate type needed by the implementing activity type
*/
public interface FailedOp<D> extends Payload<D>, CycleResult, CompletedOp<D> {
public int getTries();
}

View File

@ -0,0 +1,25 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.core.ops.fluent.opfacets;
public interface OpEvents<D> {
void onOpStarted(StartedOp<D> op);
void onOpSuccess(SucceededOp<D> op);
void onOpSkipped(SkippedOp<D> op);
void onOpFailure(FailedOp<D> op);
}

View File

@ -0,0 +1,41 @@
/*
*
* Copyright 2018 jshook
* 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.activityapi.core.ops.fluent.opfacets;
/**
* This interface represents the union of interfaces needed for all of the
* behavioral facets of a useful Op implementation. By implementing
* these faceted interfaces by way of the OpFacets interface, an
* implementation can be a state carrier that exposes a contextual
* interface by declaration.
*
* While this not a secure method of
* enforcing type and interface over shared state, it does provide
* a high degree of simplification for developers who wish to constrain
* the operational view of an object according to an implied state machine.
*
* @param <D> The data carrier parameter type. Any OpFacets implementation can
* be used to carry any state which is needed to support a specific type of
* operation.
*/
public interface OpFacets<D> extends TrackedOp<D>, StartedOp<D>, SucceededOp<D>, FailedOp<D>, SkippedOp<D> {
default int compareTo(OpFacets<D> o) {
return Long.compare(getCycle(),o.getCycle());
}
}

View File

@ -0,0 +1,159 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.core.ops.fluent.opfacets;
public class OpImpl<D> implements OpFacets<D> {
// private OpTracker<D> tracker;
private D data;
private long cycle;
private int cycleResult;
private long waitTime;
private long endedAtNanos;
private long startedAtNanos;
// private long usages;
private int tries = 0;
private int skipreason;
public OpImpl() {
}
@Override
public StartedOp<D> start() {
this.endedAtNanos = Long.MIN_VALUE;
this.startedAtNanos = System.nanoTime();
tries = 1;
return this;
}
@Override
public OpImpl<D> setWaitTime(long waitTime) {
this.endedAtNanos = Long.MIN_VALUE;
this.waitTime = waitTime;
this.startedAtNanos = System.nanoTime();
// usages++;
return this;
}
@Override
public SucceededOp<D> succeed(int status) {
// TODO: Enable a debug version of OpImpl which can assert invariants (succeed is only called once after start, ...)
this.endedAtNanos = System.nanoTime();
this.cycleResult = status;
return this;
}
@Override
public FailedOp<D> fail(int status) {
this.endedAtNanos = System.nanoTime();
this.cycleResult = status;
return this;
}
@Override
public StartedOp<D> retry() {
this.startedAtNanos = System.nanoTime();
this.endedAtNanos = Long.MIN_VALUE;
tries++;
return this;
}
@Override
public SkippedOp<D> skip(int reason) {
this.skipreason=reason;
return this;
}
@Override
public long getCycle() {
return this.cycle;
}
@Override
public void setCycle(long cycle) {
this.cycle = cycle;
}
@Override
public long getStartedAtNanos() {
return startedAtNanos;
}
@Override
public D getData() {
return data;
}
@Override
public void setData(D data) {
this.data = data;
}
@Override
public int getTries() {
return tries;
}
@Override
public long getCurrentServiceTimeNanos() {
return System.nanoTime() - this.startedAtNanos;
}
@Override
public long getCurrentResponseTimeNanos() {
return waitTime + getCurrentServiceTimeNanos();
}
@Override
public long getServiceTimeNanos() {
return this.endedAtNanos - this.startedAtNanos;
}
@Override
public long getResponseTimeNanos() {
return waitTime + getServiceTimeNanos();
}
@Override
public int getResult() {
return this.cycleResult;
}
@Override
public String toString() {
return "Op{" +
"cycle=" + cycle +
", result=" + cycleResult +
", wait=" + waitTime +
", started=" + startedAtNanos +
", ended=" + endedAtNanos +
", tries=" + tries +
", data=" + (data == null ? "NULL" : data.toString()) +
'}';
}
@Override
public int getSkippedReason() {
return skipreason;
}
}

View File

@ -0,0 +1,28 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.core.ops.fluent.opfacets;
/**
* This op context carries with it a data element which a protocol-specific
* implementation can use to hold the state and logic for operations.
* @param <D> The type of delegate needed for the implementing protocol
*/
public interface Payload<D> {
D getData();
void setData(D data);
}

View File

@ -0,0 +1,24 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.core.ops.fluent.opfacets;
import io.nosqlbench.activityapi.cyclelog.buffers.results.CycleResult;
public interface SkippedOp<D> extends Payload<D>, CycleResult, CompletedOp<D> {
int getSkippedReason();
}

View File

@ -0,0 +1,82 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.core.ops.fluent.opfacets;
import io.nosqlbench.activityapi.cyclelog.buffers.results.CycleReadable;
/**
* A StartedOp is a type that represents that an operation has been sent to some
* specific type of protocol or logic.
*
* <H2>Correctness</H2>
* It is essential that developers close a StartedOp in one of the appropriate ways.
* Creating a StartedOp and not calling either {@link #succeed(int)}, or {@link #fail(int)}
* will cause deadlocks in concurrency management. This is because the logic which tracks
* operations relies on these signals to know when to close out an operation and allow
* another to be started according to concurrency controls.
*
* {@link #retry()} can be called as many times as an activity allows for, but this is
* not sufficient to retire the operation. After calling {@link #retry()}, one of the
* end states above must be set.
*
* @param <D> The delegate type that is need for the implementing activity type
*/
public interface StartedOp<D> extends Payload<D>, CycleReadable {
/**
* Reset the service timer on this op, and increment the tries counter
* @return A StartedOp
*/
StartedOp<D> retry();
/**
* Mark this op as successful as of the time it is called, and record the resulting status code.
* @param status The status for this op, determined by individual activity types
* @return a SucceededOp
*/
SucceededOp<D> succeed(int status);
/**
* Mark this op as failed as of the time it is called, and record the resulting status code.
* @param status The status for this op, determined by individual activity types
* @return A FailedOp
*/
FailedOp<D> fail(int status);
/**
* Get the nanosecond instant which was recorded for this operation to be started.
* Specifically, this is when the operation was known to enter a native protocol or
* activity type section of logic which is more than just preparatory work by the
* client before execution.
* @return nanoseconds started instant
*/
long getStartedAtNanos();
/**
* Return the nanos that have elapsed since the op was started at the time of this call.
* @return nanosecond service time duration
*/
public long getCurrentServiceTimeNanos();
/**
* Return the nanos that have elapsed since this op was started at the time of this call,
* plus any prior waittime.
* @return nanosecond response time duration
*/
public long getCurrentResponseTimeNanos();
}

View File

@ -0,0 +1,28 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.core.ops.fluent.opfacets;
import io.nosqlbench.activityapi.cyclelog.buffers.results.CycleResult;
/**
* An op should be deemed successful if it completes with no exception.
* @param <D> The type of delegate needed for the implementing protocol
*/
public interface SucceededOp<D> extends Payload<D>, CycleResult, CompletedOp<D> {
public int getTries();
}

View File

@ -0,0 +1,58 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.core.ops.fluent.opfacets;
import io.nosqlbench.activityapi.cyclelog.buffers.results.CycleMutable;
/**
* A tracked op is one that has been added to a tracker, and can
* then be started.
* @param <D> The payload type of this op.
*/
public interface TrackedOp<D> extends Payload<D>, CycleMutable {
/**
* Signify to NB that the associated operation is known to
* have started processing in some specific way according to the implementing activity type.
*
* This should be called after any operational setup work that would not occur
* in a typical application client scenario. The moment this is called, the
* start time for the operation is marked.
*
* @return a StartedOp of the appropriate generic delegate type
*/
StartedOp<D> start();
/**
* Mark that this operation is being skipped by the activity type for some reason.
*
* @param reason An integer code, activity type specific, to track why the operation was skipped
* @return a SkippedOp of the appropriate generic delegate type
*/
SkippedOp<D> skip(int reason);
/**
* Indicate to this op, how much wait time elapsed between the time it was expected
* to start and the time it actually started. This is used to calculate the response time
* once service time is known.
* @param cycleDelay nanosecond delay
* @return a TrackedOp for method chaining
*/
TrackedOp<D> setWaitTime(long cycleDelay);
}

View File

@ -0,0 +1,78 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.buffers;
import java.util.ArrayList;
import java.util.List;
/**
* This is a lightweight buffer implementation that allows for buffer
* flipping and callbacks when the buffer is full.
* @param <T> The type held in this buffer
*/
public abstract class Buffer<T extends Comparable> {
private int position;
private int limit;
protected ArrayList<T> data;
public Buffer(int size) {
data = new ArrayList<>(size);
this.limit=size;
}
protected void onFull() {
}
protected abstract int compare(T one, T other);
public int remaining() {
return limit-position;
}
public Buffer<T> put(T element) {
data.add(element);
if (data.size()==limit) {
onFull();
}
return this;
}
// @Override
// public int compareTo(Buffer<T> other) {
// int diff = Integer.compare(this.data.size(), other.data.size());
// if (diff!=0) return diff;
//
// for (int i = 0; i < data.size(); i++) {
// diff = data.get(i).compareTo(other.data.get(i));
// if (diff!=0) {
// return diff;
// }
// }
// return 0;
// }
public List<T> getFlippedData() {
return data;
}
@Override
public String toString() {
return "position=" + this.position + ", limit=" + this.limit + ", capacity=" + (data!=null ? data.size() : "NULLDATA");
}
}

View File

@ -0,0 +1,54 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.buffers;
import io.nosqlbench.activityapi.cyclelog.buffers.results.CycleResult;
import io.nosqlbench.activityapi.cyclelog.buffers.results.CycleResultsSegment;
import java.util.Iterator;
public interface CycleResultSegmentsReadable extends Iterable<CycleResultsSegment> {
default Iterable<CycleResult> getCycleResultIterable() {
return new Iterable<CycleResult>() {
@Override
public Iterator<CycleResult> iterator() {
return new Iterator<CycleResult>() {
Iterator<CycleResultsSegment> iterSegment = CycleResultSegmentsReadable.this.iterator();
Iterator<CycleResult> innerIter=iterSegment.next().iterator();
@Override
public boolean hasNext() {
while(!innerIter.hasNext()&&iterSegment.hasNext()) {
innerIter=iterSegment.next().iterator();
}
return innerIter.hasNext();
}
@Override
public CycleResult next() {
return innerIter.next();
}
};
}
};
}
}

View File

@ -0,0 +1,24 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.buffers;
public enum CycleSorting {
Keep,
Discard,
Ignore
}

View File

@ -0,0 +1,26 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.buffers.op_output;
import io.nosqlbench.activityapi.core.ops.fluent.opfacets.CompletedOp;
import java.util.List;
public interface StrideOutputConsumer<D> {
public void onStrideOutput(List<CompletedOp<D>> ops);
}

View File

@ -0,0 +1,30 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.buffers.op_output;
public interface StrideOutputSegment<D> extends Comparable<StrideOutputSegment<D>>, Iterable<D> {
long getCount();
long getMinCycle();
default int compareTo(StrideOutputSegment other) {
return Long.compare(getMinCycle(),other.getMinCycle());
}
}

View File

@ -0,0 +1,47 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.buffers.op_output;
import io.nosqlbench.activityapi.core.ops.fluent.opfacets.CompletedOp;
import java.util.Iterator;
import java.util.List;
public class StrideOutputSegmentImpl<D extends CompletedOp> implements StrideOutputSegment<D> {
List<D> data;
public StrideOutputSegmentImpl(List<D> strideData) {
data = strideData;
}
@Override
public long getCount() {
return data.size();
}
@Override
public long getMinCycle() {
return data.get(0).getCycle();
}
@Override
public Iterator<D> iterator() {
return data.iterator();
}
}

View File

@ -0,0 +1,84 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.buffers.results;
import io.nosqlbench.activityapi.input.Input;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Just cycle numbers in a long array.
*/
public class CycleArray implements Input {
private AtomicInteger offset=new AtomicInteger();
private long[] cycles;
public CycleArray(long... values) {
this.cycles = values;
}
@Override
public CycleSegment getInputSegment(int segmentLength) {
while (true) {
int current = offset.get();
int nextOffset=current+segmentLength;
if (nextOffset>cycles.length) {
return null;
}
if (offset.compareAndSet(current,nextOffset)) {
return new ArraySegment(Arrays.copyOfRange(cycles,current,nextOffset));
}
// in all other cases, there was a CAS race condition, and we want to retry
}
}
public static class ArraySegment implements CycleSegment {
private long[] values;
private int offset=0;
public ArraySegment(long[] values) {
this.values = values;
}
@Override
public long nextCycle() {
if (offset<values.length) {
return values[offset++];
}
return -100;
}
@Override
public long peekNextCycle() {
if (offset<values.length) {
return values[offset];
}
return -100;
}
@Override
public boolean isExhausted() {
return (offset>=values.length);
}
}
}

View File

@ -0,0 +1,26 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.buffers.results;
public interface CycleMutable extends CycleReadable {
/**
* set the cycle number associated with this element.
* @param cycle The cycle for this operation
*/
void setCycle(long cycle);
}

View File

@ -0,0 +1,26 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.buffers.results;
public interface CycleReadable {
/**
* get the cycle number associated with this element.
* @return a cycle number
*/
long getCycle();
}

View File

@ -0,0 +1,36 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.buffers.results;
/**
* A readable interface for (cycle, result) tuple types.
*/
public interface CycleResult extends Comparable<CycleResult>, CycleReadable, ResultReadable {
/**
* By default, allow cycle results to be ordered according to the cycle number.
* @param o CycleResult to compare to
* @return -1, 0, or 1, depending on ordering
*/
default int compareTo( CycleResult o) {
return Long.compare(getCycle(),o.getCycle());
}
}

View File

@ -0,0 +1,87 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.buffers.results;
import io.nosqlbench.activityapi.cyclelog.outputs.CanSortCycles;
import java.util.Arrays;
import java.util.Iterator;
import java.util.NoSuchElementException;
public class CycleResultArray implements CycleResultsSegment, CanSortCycles {
private CycleResult[] cycleResults;
public CycleResultArray(CycleResult[] cycleResults) {
this.cycleResults = cycleResults;
}
public CycleResultArray(CycleResultsSegment segment) {
cycleResults = new CycleResult[(int) segment.getCount()];
Iterator<CycleResult> iterator = segment.iterator();
for (int i = 0; i < cycleResults.length; i++) {
cycleResults[i]=iterator.next();
}
}
@Override
public long getCount() {
return cycleResults.length;
}
@Override
public long getMinCycle() {
return cycleResults[0].getCycle();
}
@Override
public Iterator<CycleResult> iterator() {
return new CycleResultArrayIterator(cycleResults);
}
@Override
public void sort() {
Arrays.sort(cycleResults);
}
private static class CycleResultArrayIterator implements Iterator<CycleResult> {
private final CycleResult[] results;
private int idx;
public CycleResultArrayIterator(CycleResult[] results) {
this.results = results;
this.idx=0;
}
@Override
public boolean hasNext() {
return (idx<results.length);
}
@Override
public CycleResult next() {
if (idx>=results.length) {
throw new NoSuchElementException("Unable to read array past last value");
}
CycleResult result = results[idx];
idx++;
return result;
}
}
}

View File

@ -0,0 +1,76 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.buffers.results;
import java.nio.ByteBuffer;
/**
* Implements a cycle result segment in a basic buffer
* that contains the cycle and the result in long, byte format.
* This is not thread safe.
*/
public class CycleResultSegmentBuffer {
private ByteBuffer buf;
private final static int BYTES = Long.BYTES + Byte.BYTES;
private final Sink sink;
public CycleResultSegmentBuffer(Sink sink, int resultCount) {
this.sink = sink;
this.buf = ByteBuffer.allocate(resultCount*BYTES);
}
public CycleResultSegmentBuffer(int resultCount) {
this.sink = null;
this.buf = ByteBuffer.allocate(resultCount*BYTES);
}
public void append(long cycle, int result) {
buf.putLong(cycle).put((byte) result);
if (sink!=null) {
if (!buf.hasRemaining()) {
sink.handle(toReader());
}
}
}
public void append(CycleResult result) {
buf.putLong(result.getCycle()).put((byte) result.getResult());
if (sink!=null) {
if (!buf.hasRemaining()) {
sink.handle(toReader());
}
}
}
public CycleResultsSegment toReader() {
buf.flip();
CycleResultsSegmentReadable readable = new CycleResultsSegmentReadable(buf);
buf=null;
return readable;
}
public boolean hasRemaining() {
return buf.hasRemaining();
}
public static interface Sink {
void handle(CycleResultsSegment buffer);
}
}

View File

@ -0,0 +1,44 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.buffers.results;
import java.util.Iterator;
public class CycleResultStrider {
private Iterator<CycleResult> iterator;
public CycleResultStrider(Iterator<CycleResult> iterator) {
this.iterator = iterator;
}
public CycleResultsSegment getCycleResultsSegment(int stride) {
if (!iterator.hasNext()) {
return null;
}
CycleResultSegmentBuffer buffer = new CycleResultSegmentBuffer(stride);
for (int i = 0; i < stride; i++) {
if (iterator.hasNext()) {
buffer.append(iterator.next());
}
}
return buffer.toReader();
}
}

View File

@ -0,0 +1,126 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.buffers.results;
import java.util.Arrays;
import java.util.Iterator;
/**
* This is just a typed-data holder for efficient transfer of tracked data.
* It holds a base cycle value, and a byte array view of result values.
*/
public class CycleResultsIntervalSegment implements CycleResultsSegment {
/**
* The base cycle value, the minimum cycle in the segment.
*/
public long cycle;
/**
* A view of status codes in byte form.
*/
public byte[] codes;
public static CycleResultsIntervalSegment forData(long cycle, byte[] buffer, int offset, int len) {
CycleResultsIntervalSegment s = new CycleResultsIntervalSegment();
s.cycle = cycle;
s.codes = Arrays.copyOfRange(buffer,offset,offset+len);
return s;
}
public static CycleResultsIntervalSegment forData(long cycle, byte[] buffer) {
CycleResultsIntervalSegment s = new CycleResultsIntervalSegment();
s.cycle=cycle;
s.codes = buffer;
return s;
}
@Override
public Iterator<CycleResult> iterator() {
return new CycleSegmentIterator();
}
@Override
public long getCount() {
return codes.length;
}
@Override
public long getMinCycle() {
return cycle;
}
private class CycleSegmentIterator implements Iterator<CycleResult> {
private int index=0;
@Override
public boolean hasNext() {
return (index<codes.length);
}
@Override
public CycleResult next() {
CycleSegmentResult cycleSegmentResult = new CycleSegmentResult(cycle + index, codes[index]);
index++;
return cycleSegmentResult;
}
}
@Override
public String toString() {
return "CycleSegment{" +
"cycle=" + cycle +
", codes=" +
( codes.length<100 ? Arrays.toString(codes) : Arrays.toString(Arrays.copyOfRange(codes,0,100))) +
'}';
}
private class CycleSegmentResult implements CycleResult {
private final long cycle;
private final int result;
public CycleSegmentResult(long cycle, int result) {
this.cycle = cycle;
this.result = result;
}
@Override
public long getCycle() {
return cycle;
}
@Override
public int getResult() {
return result;
}
@Override
public String toString() {
return "CycleSegmentResult{" +
"cycle=" + cycle +
", result=" + result +
'}';
}
}
}

View File

@ -0,0 +1,60 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.buffers.results;
import java.util.Collections;
import java.util.Iterator;
import java.util.function.Predicate;
import java.util.stream.StreamSupport;
public interface CycleResultsSegment extends Comparable<CycleResultsSegment>, Iterable<CycleResult> {
long getCount();
long getMinCycle();
// TODO: Specialize this for push-down performance
default CycleResultsSegment filter(Predicate<ResultReadable> filter) {
CycleResult[] filteredResults = StreamSupport.stream(spliterator(), false).filter(filter).toArray(CycleResult[]::new);
return new CycleResultArray(filteredResults);
}
default int compareTo( CycleResultsSegment other) {
return Long.compare(getMinCycle(),other.getMinCycle());
}
CycleResultsSegment EMPTY = new EmptySegment();
public class EmptySegment implements CycleResultsSegment {
@Override
public long getCount() {
return 0;
}
@Override
public long getMinCycle() {
return Long.MAX_VALUE;
}
@Override
public Iterator<CycleResult> iterator() {
return Collections.emptyIterator();
}
}
}

View File

@ -0,0 +1,121 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.buffers.results;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.function.Predicate;
import java.util.stream.StreamSupport;
/**
* Implements a cycle result segment in a basic buffer
* that contains the cycle and the result in long, byte format.
*/
public class CycleResultsSegmentReadable implements CycleResultsSegment {
private final static int BYTES = Long.BYTES + Byte.BYTES;
private final ByteBuffer buf;
public CycleResultsSegmentReadable(ByteBuffer buf) {
this.buf = buf;
}
public static CycleResultsSegment forCycleResult(long completedCycle, int result) {
ByteBuffer single = ByteBuffer.allocate(BYTES);
single.putLong(completedCycle).put((byte) result);
single.flip();
return new CycleResultsSegmentReadable(single);
}
@Override
public Iterator<CycleResult> iterator() {
return new Iter();
}
@Override
public String toString() {
ByteBuffer bb = ByteBuffer.wrap(buf.array());
StringBuilder sb = new StringBuilder();
while (bb.remaining() > 0) {
long cycle = bb.getLong();
byte value = bb.get();
sb.append(cycle).append("=>").append(value).append("\n");
}
return sb.toString();
}
@Override
public long getCount() {
return (buf.limit())/ BYTES;
}
@Override
public long getMinCycle() {
if (buf != null && buf.limit() > 0) {
return buf.getLong(0);
}
return Long.MIN_VALUE;
}
// TODO: Make this work with RLE segments
@Override
public CycleResultsSegment filter(Predicate<ResultReadable> filter) {
CycleResult[] filteredResults = StreamSupport.stream(spliterator(), false).filter(filter).toArray(CycleResult[]::new);
return new CycleResultArray(filteredResults);
}
private class Iter implements Iterator<CycleResult> {
private int offset = 0;
@Override
public boolean hasNext() {
return (offset + BYTES <= buf.limit());
}
@Override
public CycleResult next() {
BBCycleResult cycleResult = new BBCycleResult(offset);
offset += BYTES;
return cycleResult;
}
}
private class BBCycleResult implements CycleResult {
private int offset;
BBCycleResult(int offset) {
this.offset = offset;
}
@Override
public long getCycle() {
return buf.getLong(offset);
}
@Override
public int getResult() {
return buf.get(offset + Long.BYTES);
}
}
}

View File

@ -0,0 +1,58 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.buffers.results;
/**
* A segment of cycle numbers to iterate over. Usage of an InputSegment
* is meant to be stack-local, or at least single threaded, so no
* precautions are needed to make it thread safe.
*/
public interface CycleSegment {
/**
* The next cycle, which should be a positive number between 0 and Long.MAX_VALUE.
* If a negative value is returned, then the caller should disregard the value
* and assume that any further input segments will be invalid.
*
* <p>Implementations of this method should not worry about thread safety.
* @return a positive and valid long cycle, or a negative indicator of end of input
*/
long nextCycle();
/**
* @return true if the input can provide no further cycles
*/
boolean isExhausted();
default long[] nextCycles(int len) {
long[] values = new long[len];
for (int i = 0; i <values.length; i++) {
long c = nextCycle();
values[i]=c;
}
return values;
}
/**
* Return the value of the next cycle which would be returned by {@link #nextCycle()}}
* without modifying the segment, or a negative number if the cycle range would be
* outside the valid range for this segment.
* @return the next cycle that will be returned
*/
long peekNextCycle();
}

View File

@ -0,0 +1,61 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.buffers.results;
import java.util.Arrays;
public class CycleSegmentBuffer {
long[] cycleNumbers;
int pos = 0;
public CycleSegmentBuffer(int size) {
cycleNumbers = new long[size];
}
public void append(long cycleNumber) {
cycleNumbers[pos++] = cycleNumber;
}
public CycleSegment toReadable() {
if (pos == cycleNumbers.length) {
return new CycleArray.ArraySegment(cycleNumbers);
} else {
return new CycleArray.ArraySegment(Arrays.copyOfRange(cycleNumbers, 0, pos));
}
}
public int remaining() {
return cycleNumbers.length - pos;
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("CycleSegmentBuffer (size=").append(cycleNumbers.length).append(")=>");
if (cycleNumbers.length > 100) {
sb.append(Arrays.toString(Arrays.copyOfRange(cycleNumbers, 0, 20)))
.append(", ..., ")
.append(Arrays.toString(Arrays.copyOfRange(cycleNumbers, cycleNumbers.length - 21, cycleNumbers.length - 1)));
} else {
sb.append(Arrays.toString(cycleNumbers));
}
return sb.toString();
}
}

View File

@ -0,0 +1,80 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.buffers.results;
public class MutableCycleResult implements CycleResult {
private final long cycle;
private int result;
private long startTimeNanos;
private long endTimeNanos=Long.MIN_VALUE; // you will get some strange results if you forget to update this
private long schedulingDelay;
public MutableCycleResult(long cycle, int result, long startTimeNanos, long schedulingDelay) {
this.cycle = cycle;
this.result = result;
this.startTimeNanos = startTimeNanos;
this.schedulingDelay=schedulingDelay;
}
public MutableCycleResult(long cycle, int result, long startTimeNanos) {
this(cycle,result,startTimeNanos,Long.MIN_VALUE);
}
public MutableCycleResult(long cycle, int result) {
this(cycle,result, System.nanoTime());
}
@Override
public long getCycle() {
return cycle;
}
@Override
public int getResult() {
return result;
}
public String toString() {
return this.cycle +"->" + this.result;
}
public void setResult(int result) {
this.result = result;
}
public long getStartTimeNanos() {
return startTimeNanos;
}
public void setStartTimeNanos(long startTimeNanos) {
this.startTimeNanos = startTimeNanos;
}
public long getEndTimeNanos() {
return endTimeNanos;
}
public void setEndTimeNanos(long endTimeNanos) {
this.endTimeNanos = endTimeNanos;
}
public long getOpNanos() {
return schedulingDelay + (endTimeNanos - startTimeNanos);
}
}

View File

@ -0,0 +1,26 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.buffers.results;
public interface ResultReadable {
/**
* Get a result associated with some operation, according to the activity-specific result map
* @return an activity-specific result code
*/
int getResult();
}

View File

@ -0,0 +1,21 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.buffers.results;
public interface SegmentedResultInput {
}

View File

@ -0,0 +1,131 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.buffers.results_rle;
import io.nosqlbench.activityapi.cyclelog.buffers.CycleResultSegmentsReadable;
import io.nosqlbench.activityapi.cyclelog.buffers.results.CycleResultsSegment;
import io.nosqlbench.activityapi.cyclelog.buffers.results.ResultReadable;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.function.Predicate;
/**
* Implements a cycle result segment in a run-length encoded buffer
* that contains the cycle interval and the result in long, long, byte format,
* where the last value (the second long value) is *not* included in the
* cycle inteval. (closed-open interval)
* <p>This is <em>not</em> a threadsafe iterator. It references buffer data
* that is presumed to be access by only one reader for the sake of efficiency.
*/
public class CycleResultsRLEBufferReadable implements CycleResultSegmentsReadable {
public final static int BYTES = Long.BYTES + Long.BYTES + Byte.BYTES;
private final ByteBuffer buf;
// private long count = Long.MIN_VALUE;
// private long min = Long.MAX_VALUE;
public CycleResultsRLEBufferReadable(ByteBuffer buf) {
this.buf = buf;
}
public CycleResultsRLEBufferReadable(int readSizeInSpans, ByteBuffer src) {
readSizeInSpans = readSizeInSpans * BYTES;
int bufsize = Math.min(readSizeInSpans, src.remaining());
byte[] bbuf = new byte[bufsize];
src.get(bbuf);
this.buf = ByteBuffer.wrap(bbuf);
}
public Iterator<CycleResultsSegment> iterator(Predicate<ResultReadable> filter) {
return new ResultSpanIterator(buf,filter);
}
// public long getMin() {
// if (min==Long.MAX_VALUE) {
// long min=Long.MAX_VALUE;
// Optional<CycleResultsSegment> minSeg = StreamSupport.stream(spliterator(), false).min(CycleResultsSegment::compareTo);
// min=minSeg.map(CycleResultsSegment::getMinCycle).orElse(Long.MAX_VALUE);
// }
// return min;
// }
//
// public long getCount() {
// if (count<=0) {
// LongAccumulator acc = new LongAccumulator((l1,l2)->l1+l2,0);
// iterator().forEachRemaining(crs -> acc.accumulate(crs.getCount()));
// count = acc.get();
// }
// return count;
// }
//
@Override
public Iterator<CycleResultsSegment> iterator() {
return new ResultSpanIterator(buf,null);
}
private class ResultSpanIterator implements Iterator<CycleResultsSegment> {
private final ByteBuffer iterbuf;
private Predicate<ResultReadable> filter;
private CycleResultsSegment next;
public ResultSpanIterator(ByteBuffer buf, Predicate<ResultReadable> filter) {
this.iterbuf = buf;
this.filter = filter;
}
@Override
public boolean hasNext() {
while (next==null && iterbuf.remaining()>0) {
CycleSpanResults csr = read(iterbuf);
if (filter==null || filter.test(csr)) {
next = csr;
}
}
return next!=null;
}
@Override
public CycleResultsSegment next() {
if (next==null) {
hasNext();
if (next==null) {
throw new RuntimeException("Possible call to next() without calling hasNext(). There was no remaining unfiltered data.");
}
}
CycleResultsSegment wasNext = this.next;
next=null;
return wasNext;
}
private CycleSpanResults read(ByteBuffer iterbuf) {
long min = iterbuf.getLong();
long nextMin = iterbuf.getLong();
int result = iterbuf.get();
return new CycleSpanResults(min, nextMin, result);
}
public String toString() {
return "ResultSpanIterator (" + iterbuf.toString() + ")";
}
}
}

View File

@ -0,0 +1,200 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.buffers.results_rle;
import io.nosqlbench.activityapi.cyclelog.buffers.results.CycleResult;
import io.nosqlbench.activityapi.cyclelog.buffers.results.ResultReadable;
import io.nosqlbench.activityapi.cyclelog.inputs.cyclelog.CanFilterResultValue;
import io.nosqlbench.activityapi.output.Output;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.ByteBuffer;
import java.util.function.Predicate;
/**
* Implements a convenient target buffer for Marker data that can be used
* to create nio ByteBuffers easily.
*
* This is not thread-safe. It is not meant to be used by concurrent callers.
*
* It is recommended to use the {@link AutoCloseable} method to ensure that
* partial runs are flushed automatically. Access the buffer for read via either
* the {@link #toByteBuffer()} or the {@link #toSegmentsReadable()} methods will
* automatically {@link #flush()} and invalidate the writable buffer, so further writes
* will be deemed invalid and will cause an exception to be thrown.
*/
public class CycleResultsRLEBufferTarget implements Output,CanFilterResultValue {
private final static Logger logger = LoggerFactory.getLogger(CycleResultsRLEBufferTarget.class);
public final static int BYTES = Long.BYTES + Long.BYTES + Byte.BYTES;
private ByteBuffer buf;
private long lastCycle = Long.MIN_VALUE;
private long lastResult = Integer.MIN_VALUE;
private long runlength = 0L;
private boolean flushed = false;
private long count=0L;
private long min=Long.MAX_VALUE;
private Predicate<ResultReadable> filter;
/**
* Create a buffer with the provided ByteBuffer.
*
* @param buf the source data
*/
public CycleResultsRLEBufferTarget(ByteBuffer buf) {
this.buf = buf;
}
// /**
// * Create a buffer with an automatic capacity of around 1MiB.
// */
// public CycleResultsRLEBufferTarget() {
// this(1024 * 1024);
// }
//
/**
* Create a target RLE buffer for the specified getCount in memory,
* rounded to the nearest record getCount.
*
* @param elementCount The number of elements to buffer.
*/
public CycleResultsRLEBufferTarget(int elementCount) {
this(ByteBuffer.allocate(elementCount * BYTES));
}
/**
* Convert the contents of this RLE buffer to a readable and
* invalide it for writing.
* @return a CycleResultRLEBuffer
*/
public CycleResultsRLEBufferReadable toSegmentsReadable() {
flush();
ByteBuffer readable = buf.duplicate();
readable.flip();
return new CycleResultsRLEBufferReadable(readable);
}
public ByteBuffer toByteBuffer() {
flush();
ByteBuffer bb = buf.duplicate();
bb.flip();
return bb;
}
/**
* Record new cycle result data in the buffer, and optionally flush any
* completed RLE segments to the internal ByteBuffer.
*
* @param cycle The cycle number being marked.
* @param result the result ordinal
*
* @throws RuntimeException if the buffer has been converted to a readable form
* @return false if there was no more room in the buffer for another tuple, true otherwise.
*/
@Override
public boolean onCycleResult(long cycle, int result) {
ResultReadableWrapper resultReadableWrapper = new ResultReadableWrapper(result);
if (filter!=null && !filter.test(resultReadableWrapper)) {
return true;
}
if (cycle != lastCycle + 1 || lastResult != result) {
if (lastCycle != Long.MIN_VALUE) {
checkpoint(lastCycle + 1 - runlength, lastCycle + 1, lastResult);
}
}
lastCycle = cycle;
lastResult = result;
runlength++;
flushed = false;
return true;
}
private void checkpoint(long istart, long iend, long lastResult) {
if (buf.remaining()==0) {
buf=resize(buf);
}
if (lastResult > Byte.MAX_VALUE) {
throw new RuntimeException("Unable to encode result values greater than Byte.MAX_VALUE.");
}
if (lastCycle>=0) {
buf.putLong(istart).putLong(iend).put((byte) lastResult);
runlength = 0;
return;
}
if (lastCycle!=Long.MIN_VALUE) {
throw new RuntimeException("Unable to encode cycle values less than 0");
} {
logger.trace("checkpoint with no active RLE segment data.");
}
}
private static class ResultReadableWrapper implements ResultReadable {
private int result;
ResultReadableWrapper(int result) {
this.result = result;
}
public int getResult() { return result; }
}
private ByteBuffer resize(ByteBuffer buf) {
ByteBuffer doubled=ByteBuffer.allocate(buf.capacity()*2);
buf.flip();
doubled.put(buf);
logger.warn("resized buffer to " + doubled + " to ensure capacity.");
return doubled;
}
public int getRawBufferCapacity() {
return buf.capacity();
}
public int getRecordCapacity() {
return buf.capacity() / BYTES;
}
/**
* Flushes any partial data that was submitted (an incomplete run of results,
* for example), to the internal ByteBuffer, and marks flushed status.
*
* @return the getCount of the current buffer, in bytes.
*/
private int flush() {
if (!flushed) {
checkpoint(lastCycle + 1 - runlength, lastCycle + 1, lastResult);
flushed = true;
}
return buf.position();
}
@Override
public void close() {
flush();
}
public boolean onCycleResult(CycleResult cycleResult) {
return this.onCycleResult(cycleResult.getCycle(),cycleResult.getResult());
}
@Override
public void setFilter(Predicate<ResultReadable> filter) {
this.filter = filter;
}
}

View File

@ -0,0 +1,100 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.buffers.results_rle;
import io.nosqlbench.activityapi.cyclelog.buffers.results.CycleResult;
import io.nosqlbench.activityapi.cyclelog.buffers.results.CycleResultsSegment;
import io.nosqlbench.activityapi.cyclelog.buffers.results.ResultReadable;
import io.nosqlbench.activityapi.cyclelog.buffers.results.MutableCycleResult;
/**
* Compact encoding of a result that doesn't change over a range of one or more cycles.
*/
import java.util.Iterator;
import java.util.function.Predicate;
public class CycleSpanResults implements CycleResultsSegment, ResultReadable {
private final long min;
private final long nextMin;
private final int result;
public CycleSpanResults(long min, long nextMin, int result) {
this.min = min;
this.nextMin = nextMin;
this.result = result;
}
@Override
public long getCount() {
return (int) nextMin-min;
}
@Override
public long getMinCycle() {
return min;
}
@Override
public int getResult() {
return result;
}
public String toString() {
return "[" + min + "," + nextMin + ")->" + result;
}
@Override
public CycleResultsSegment filter(Predicate<ResultReadable> filter) {
if (filter.test(this)) {
return this;
} else {
return CycleResultsSegment.EMPTY;
}
}
@Override
public Iterator<CycleResult> iterator() {
return new Iter(min,nextMin);
}
private class Iter implements Iterator<CycleResult> {
private final long nextMin;
private long next;
public Iter(long min, long nextMin) {
next = min;
this.nextMin = nextMin;
}
@Override
public boolean hasNext() {
return next < nextMin;
}
@Override
public CycleResult next() {
return new MutableCycleResult(next++,result);
}
}
}

View File

@ -0,0 +1,107 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.filters;
import io.nosqlbench.activityapi.cyclelog.buffers.results.ResultReadable;
import io.nosqlbench.activityapi.cyclelog.filters.tristate.ResultFilteringSieve;
import io.nosqlbench.activityapi.cyclelog.filters.tristate.TristateFilter;
import io.nosqlbench.util.ConfigTuples;
import io.virtdata.annotations.Service;
import java.util.function.Predicate;
/**
* This cycle result filter implements a filter that allows for the
* inclusion or exclusion of single-values or intervals. It parses a format
* that looks like this:
*
* <pre>include:54,exclude:32-35,...</pre>
*
* The default terminal policy -- the one that is applied if none of the
* clauses match a given item -- is set as the opposite of the first
* clause. In the example above, the default policy would be "exclude",
* given that the fist clause is "include".
*/
@Service(ResultValueFilterType.class)
public class CoreResultValueFilter implements ResultValueFilterType {
@Override
public String getName() {
return "core";
}
@Override
public ResultFilterDispenser getDispenser(String config) {
return new Dispenser(config);
}
public static class Dispenser implements ResultFilterDispenser {
Predicate<ResultReadable> predicate;
public Dispenser(String config) {
ConfigTuples conf = new ConfigTuples(config);
ConfigTuples includesAndExcludes = conf.getAllMatching("in.*", "ex.*");
ResultFilteringSieve.Builder builder = new ResultFilteringSieve.Builder();
includesAndExcludes.forEach(s -> mapPredicate(s,builder));
ResultFilteringSieve sieve = builder.build();
predicate = sieve.toDefaultingPredicate(getDefaultFromHead(includesAndExcludes.get(0)));
}
@Override
public Predicate<ResultReadable> getResultFilter() {
return predicate;
}
}
private static TristateFilter.Policy getDefaultFromHead(ConfigTuples.Section section) {
if (section.get(0).startsWith("in")) return TristateFilter.Policy.Discard;
return TristateFilter.Policy.Keep;
}
private static void mapPredicate(ConfigTuples.Section section, ResultFilteringSieve.Builder builder) {
int min, max;
String incexc = section.get(0);
if (incexc.startsWith("in")) {
incexc = "include";
} else if (incexc.startsWith("ex")) {
incexc = "exclude";
} else {
throw new RuntimeException("pattern does not start with 'in' or 'ex' for include or exclude:" + incexc);
}
if (section.get(1).matches("\\d+-\\d+")) {
String[] split = section.get(1).split("-");
min = Integer.valueOf(split[0]);
max = Integer.valueOf(split[1]);
} else {
min = Integer.valueOf(section.get(1));
max = min;
}
if (min == max) {
if (incexc.equals("include")) builder.include(min);
else builder.exclude(min);
} else {
if (incexc.equals("include")) builder.include(min,max);
else builder.exclude(min,max);
}
}
}

View File

@ -0,0 +1,57 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.filters;
import io.nosqlbench.activityapi.core.Activity;
import io.nosqlbench.util.Named;
import io.nosqlbench.util.SimpleConfig;
import io.nosqlbench.util.SimpleServiceLoader;
import java.util.function.IntPredicate;
public interface ExperimentalResultFilterType extends Named {
public static SimpleServiceLoader<ExperimentalResultFilterType> FINDER =
new SimpleServiceLoader<>(ExperimentalResultFilterType.class);
default IntPredicateDispenser getFilterDispenser(Activity activity) {
SimpleConfig conf = new SimpleConfig(activity, "resultfilter");
return getFilterDispenser(conf);
}
default IntPredicateDispenser getFilterDispenser(SimpleConfig conf) {
IntPredicate intPredicate = getIntPredicate(conf);
return new StaticDispenser(intPredicate);
}
IntPredicate getIntPredicate(SimpleConfig conf);
public static class StaticDispenser implements IntPredicateDispenser {
private final IntPredicate predicate;
public StaticDispenser(IntPredicate predicate) {
this.predicate = predicate;
}
@Override
public IntPredicate getIntPredicate(int slot) {
return predicate;
}
}
}

View File

@ -0,0 +1,76 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.filters;
import io.nosqlbench.util.SimpleConfig;
import io.virtdata.annotations.Service;
import java.util.Arrays;
import java.util.function.IntPredicate;
/**
* A naive implementation of set filtering on integer values.
* For now, given the (byte) constrained data type width, a simple
* array is used. When the type widens, this will need to use a native
* int trie or something else that is time and space efficient.
*/
@Service(ExperimentalResultFilterType.class)
public class IncludeCodesTypeExperimental implements ExperimentalResultFilterType {
@Override
public String getName() {
return "include";
}
@Override
public IntPredicate getIntPredicate(SimpleConfig conf) {
return new IncludeCodes(conf);
}
private static class IncludeCodes implements IntPredicate {
private final int[] lut;
public IncludeCodes(SimpleConfig conf) {
lut=parseCodes(128, conf.getString("codes").orElseThrow(
() -> new RuntimeException("codes= was not provided in the int predicate config for " + IncludeCodes.this.toString())
));
}
private int[] parseCodes(int len, String codes) {
int[] lut = new int[len];
int[] values = Arrays.stream(codes.split(";")).mapToInt(Integer::valueOf).toArray();
for (int value : values) {
if (value < 0 || value > Byte.MAX_VALUE) {
throw new RuntimeException("this filter only allows values in [0..127] for now.");
}
lut[value] = 1;
}
return lut;
}
@Override
public boolean test(int value) {
if (value<0) {
return false;
}
return lut[value] > 0;
}
}
}

View File

@ -0,0 +1,27 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.filters;
import io.nosqlbench.activityapi.cyclelog.buffers.results.CycleResult;
import java.util.function.Predicate;
public interface InputFilterDispenser {
Predicate<CycleResult> getCycleResultFilter();
}

View File

@ -0,0 +1,52 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.filters;
import io.nosqlbench.activityapi.cyclelog.filters.tristate.TristateFilter;
import io.nosqlbench.activityapi.input.Input;
import java.util.function.IntPredicate;
public abstract class InputMapper implements TristateFilter {
private Input input;
private IntPredicate predicate;
public InputMapper setInput(Input input) {
this.input = input;
return this;
}
public InputMapper setPredicate(IntPredicate predicate) {
this.predicate = predicate;
return this;
}
// @Override
// public InputSegment getInputSegment(int segmentLength) {
// CycleArrayBuffer buf = new CycleArrayBuffer(segmentLength);
// while (buf.remaining()>0) {
// int remaining = buf.remaining();
// InputSegment inputSegment = input.getInputSegment(remaining);
// }
// input.getInputSegment(segmentLength);
// input.getInputSegment(1);
// input.getInputSegment()
// return null;
// }
}

View File

@ -0,0 +1,24 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.filters;
import java.util.function.IntPredicate;
public interface IntPredicateDispenser {
IntPredicate getIntPredicate(int slot);
}

View File

@ -0,0 +1,26 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.filters;
import io.nosqlbench.activityapi.cyclelog.buffers.results.ResultReadable;
import java.util.function.Predicate;
public interface ResultFilterDispenser {
Predicate<ResultReadable> getResultFilter();
}

View File

@ -0,0 +1,28 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.filters;
import io.nosqlbench.util.Named;
import io.nosqlbench.util.SimpleServiceLoader;
public interface ResultValueFilterType extends Named {
SimpleServiceLoader<ResultValueFilterType> FINDER = new SimpleServiceLoader<>(ResultValueFilterType.class);
ResultFilterDispenser getDispenser(String config);
}

View File

@ -0,0 +1,80 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.filters.tristate;
import io.nosqlbench.activityapi.cyclelog.buffers.results.ResultReadable;
import java.util.function.Predicate;
public interface CycleResultPredicate extends Predicate<ResultReadable> {
public static class ResultHasSomeBits implements CycleResultPredicate {
private int mask;
public ResultHasSomeBits(int mask) {
this.mask = mask;
}
@Override
public boolean test(ResultReadable cycleResult) {
return ((cycleResult.getResult() & mask)>0);
}
}
public static class ResultHasAllBits implements CycleResultPredicate {
private int mask;
public ResultHasAllBits(int mask) {
this.mask = mask;
}
@Override
public boolean test(ResultReadable cycleResult) {
return ((cycleResult.getResult() & mask) == mask);
}
}
public static class ResultInRange implements CycleResultPredicate {
private final int min;
private final int max;
public ResultInRange(int minInclusive, int maxExclusive) {
this.min = minInclusive;
this.max = maxExclusive;
}
@Override
public boolean test(ResultReadable cycleResult) {
return (min<=cycleResult.getResult() && max>=cycleResult.getResult());
}
}
public static class ResultEquals implements CycleResultPredicate {
private final int value;
public ResultEquals(int value) {
this.value = value;
}
@Override
public boolean test(ResultReadable cycleResult) {
return cycleResult.getResult() == value;
}
}
}

View File

@ -0,0 +1,23 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.filters.tristate;
import io.nosqlbench.activityapi.cyclelog.buffers.results.CycleResult;
public interface CycleResultTristateFilter extends TristateFilter<CycleResult> {
}

View File

@ -0,0 +1,90 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.filters.tristate;
import io.nosqlbench.activityapi.cyclelog.buffers.results.ResultReadable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.regex.Pattern;
/**
* A result reading filter which uses an Enum as a set of elements to filter.
* If you have an Enum that implements ResultReadable, then you can easily create
* an enum-aware filter for it with this class.
*
* @param <E> The type of the Enum which implements TristateFilter
*/
public class EnumReadableMappingFilter<E extends Enum<E> & ResultReadable> implements TristateFilter<ResultReadable> {
private final static Logger logger = LoggerFactory.getLogger(EnumReadableMappingFilter.class);
private final E[] enumValues;
private ResultMappingArrayFilter arrayFilter = new ResultMappingArrayFilter();
public EnumReadableMappingFilter(E[] enumValues, Policy defaultPolicy) {
this.enumValues = enumValues;
for (E enumValue : enumValues) {
arrayFilter.addPolicy(enumValue,defaultPolicy);
}
}
public void addPolicy(String s, Policy policy) {
Pattern p = null;
int matched=0;
if (s.matches("\\w+")) {
p = Pattern.compile("^" + s + "$");
} else {
p = Pattern.compile(s);
}
for (E enumValue : enumValues) {
if (enumValue.toString().matches(p.pattern())) {
matched++;
logger.debug("Setting policy for " + enumValue + " to " + policy);
int resultCode = enumValue.getResult();
arrayFilter.addPolicy(enumValue,policy);
}
}
if (matched==0) {
StringBuilder sb = new StringBuilder();
for (E enumValue : this.enumValues) {
sb.append(enumValue.toString()).append(",");
}
logger.warn("Unable to match any known type with pattern '" + s + "', available names: " + sb.toString());
}
}
@Override
public Policy apply(ResultReadable cycleResult) {
return arrayFilter.apply(cycleResult);
}
public String toString () {
StringBuilder sb = new StringBuilder();
for (E enumValue : enumValues) {
int result = enumValue.getResult();
sb.append(enumValue.toString())
.append("->")
.append(result)
.append("->")
.append(arrayFilter.getPolicy(result)).append("\n");
}
return sb.toString();
}
}

View File

@ -0,0 +1,41 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.filters.tristate;
import io.nosqlbench.activityapi.cyclelog.buffers.results.ResultReadable;
import java.util.function.Predicate;
public class ResultFilterPhase implements TristateFilter<ResultReadable> {
private final Policy matchingPolicy;
private final Predicate<ResultReadable> cycleResultPredicate;
public ResultFilterPhase(Predicate<ResultReadable> cycleResultPredicate, Policy matchingPolicy) {
this.cycleResultPredicate = cycleResultPredicate;
this.matchingPolicy = matchingPolicy;
}
@Override
public Policy apply(ResultReadable cycleResult) {
if (cycleResultPredicate.test(cycleResult)) {
return matchingPolicy;
}
return Policy.Ignore;
}
}

View File

@ -0,0 +1,123 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.filters.tristate;
import io.nosqlbench.activityapi.cyclelog.buffers.results.ResultReadable;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
public class ResultFilteringSieve implements TristateFilter<ResultReadable> {
private Policy defaultPolicy;
private List<TristateFilter<ResultReadable>> phases;
private ResultFilteringSieve(Policy defaultPolicy, List<TristateFilter<ResultReadable>> phases) {
this.defaultPolicy = defaultPolicy;
this.phases = phases;
}
@Override
public Policy apply(ResultReadable resultReadable) {
Policy policy;
for (TristateFilter<ResultReadable> phase : phases) {
policy = phase.apply(resultReadable);
if (policy!=Policy.Ignore) {
return policy;
}
}
policy=defaultPolicy;
return policy;
}
public Predicate<ResultReadable> toExclusivePredicate() {
return new ExclusiveFilterPredicate(this);
}
public Predicate<ResultReadable> toDefaultingPredicate(Policy defaultPolicy) {
if (defaultPolicy==Policy.Discard) return toExclusivePredicate();
return toInclusivePredicate();
}
private class InclusiveFilterPredicate implements Predicate<ResultReadable> {
private ResultFilteringSieve resultFilteringSieve;
public InclusiveFilterPredicate(ResultFilteringSieve resultFilteringSieve) {
this.resultFilteringSieve = resultFilteringSieve;
}
@Override
public boolean test(ResultReadable cycleResult) {
return resultFilteringSieve.apply(cycleResult)!=Policy.Discard;
}
}
public Predicate<ResultReadable> toInclusivePredicate() {
return new InclusiveFilterPredicate(this);
}
private static class ExclusiveFilterPredicate implements Predicate<ResultReadable> {
private final ResultFilteringSieve sieve;
public ExclusiveFilterPredicate(ResultFilteringSieve sieve) {
this.sieve = sieve;
}
@Override
public boolean test(ResultReadable cycleResult) {
return sieve.apply(cycleResult)== Policy.Keep;
}
}
public static class Builder {
private List<TristateFilter<ResultReadable>> phaseFilters = new ArrayList<>();
private Policy defaultPolicy = Policy.Ignore;
public Builder keepByDefault() {
this.defaultPolicy = Policy.Keep;
return this;
}
public Builder discardByDefault() {
this.defaultPolicy = Policy.Discard;
return this;
}
public Builder withPhase(TristateFilter<ResultReadable> phaseFilter) {
this.phaseFilters.add(phaseFilter);
return this;
}
public Builder include(int value) {
return withPhase(new ResultFilterPhase(new CycleResultPredicate.ResultEquals(value),Policy.Keep));
}
public Builder exclude(int value) {
return withPhase(new ResultFilterPhase(new CycleResultPredicate.ResultEquals(value),Policy.Discard));
}
public Builder include(int start, int end) {
return withPhase(new ResultFilterPhase(new CycleResultPredicate.ResultInRange(start,end),Policy.Keep));
}
public Builder exclude(int start, int end) {
return withPhase(new ResultFilterPhase(new CycleResultPredicate.ResultInRange(start,end),Policy.Discard));
}
public ResultFilteringSieve build() {
return new ResultFilteringSieve(defaultPolicy, phaseFilters);
}
}
}

View File

@ -0,0 +1,61 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.filters.tristate;
import io.nosqlbench.activityapi.cyclelog.buffers.results.ResultReadable;
import java.util.Arrays;
public class ResultMappingArrayFilter implements TristateFilter<ResultReadable> {
private Policy[] policyResultMap = new Policy[0];
public void addPolicy(ResultReadable readable, Policy defaultPolicy) {
int result = readable.getResult();
if (policyResultMap.length < result + 1) {
policyResultMap = Arrays.copyOf(policyResultMap, result + 1);
}
policyResultMap[result] = defaultPolicy;
}
@Override
public Policy apply(ResultReadable readable) {
int result = readable.getResult();
if (result > policyResultMap.length + 1) {
throw new RuntimeException(
"Looking up a cycleResult of " + result +
" is not possible with a map array length of " + policyResultMap.length);
}
return policyResultMap[result];
}
public String toString() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < policyResultMap.length; i++) {
sb.append(i).append("->").append(policyResultMap[i]).append("\n");
}
return sb.toString();
}
public Policy getPolicy(int result) {
return this.policyResultMap[result];
}
}

View File

@ -0,0 +1,131 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.filters.tristate;
import java.util.function.Function;
import java.util.function.Predicate;
/**
* A tri-state filter allows for flexible configuration of
* multi-phase filtering. It effectively allows a conditional behavior
* for filtering logic that can answer "yes", "no", <em>and</em> "I don't know."
*
* This can also be used to build classic bi-state filtering, such as
* filters that use a boolean predicate to say "keep" or "discard." Where the
* tri-state filtering pattern shines, however, is in the ability to combine
* different filtering rules to build a sophisticated filter at run-time
* that bi-state filtering would prevent.
*
* In contrast to the bi-state filter, the default policy that is applied when
* <em>not</em> matching an item with the predicate is to simply ignore it.
* This means that in order to implement both matching and discarding
* policies like a bi-state filter, you must do one of the following:
* <ul>
* <li>Implement a default policy that overrides the "Ignore" action.</li>
* <li>Use both "keep" and "discard" predicates together in sequence.</li>
* </ul>
*
* The two techniques above are not mutually exclusive. In practice, tri-state
* filters are used to build up chains of filters which can delegate down
* the chain if up-stream filters do not have enough information to make
* a keep or discard determination. Even in chained filters will have a
* default policy that will override the "ignore" outcome.
*
* Filter chains that
* have a default "exclude" policy that overrides "ignore" policies are
* called "exclusive" filters. Their counterparts are "inclusive" filters.
* In other words, Exclusive tri-state filters include an element if and only
* if there was a matching include rule before any matching exclude rules
* or the end of the filter chain.
* Inclusive tri-state filters exclude an element if and only if there was
* a matching exclude rule before any matching include rules or the end of
* the filter chain.
*/
public interface TristateFilter<T> extends Function<T, TristateFilter.Policy> {
@Override
Policy apply(T cycleResult);
/**
* The filter action determines what action is taken for a given
* element that matches the predicate. If the whether to include or exclude a result
* of the filter matching. If the filter does not match, then neither
* include nor exclude are presumed. See the class docs for more details.
*/
public enum Policy {
Keep,
Discard,
Ignore
}
/**
* Create a predicate that will override any Ignore outcomes with the provided policy.
* @param defaultPolicy The policy that will override non-actionable outcomes
* @return a Predicate that can be used to filter elements
*/
default Predicate<T> toDefaultingPredicate(Policy defaultPolicy) {
return new DefaultingPredicate<>(this,defaultPolicy);
}
class DefaultingPredicate<T> implements Predicate<T> {
private final TristateFilter<T> filter;
private final Policy defaultPolicy;
public DefaultingPredicate(TristateFilter<T> filter, Policy defaultPolicy) {
this.filter = filter;
this.defaultPolicy = defaultPolicy;
}
@Override
public boolean test(T t) {
Policy policyResult = filter.apply(t);
if (policyResult==Policy.Ignore) {
policyResult= defaultPolicy;
}
return policyResult==Policy.Keep;
}
}
/**
* Create a predicate that will return true if and only if the filter
* outcome matches the provided policy.
* @param matchingPolicy The policy that will signal true in the predicate.
* @return a Predicate that can be used to filter elements
*/
default Predicate<T> toMatchingPredicate(Policy matchingPolicy) {
return new MatchingPredicate<>(this,matchingPolicy);
}
class MatchingPredicate<T> implements Predicate<T> {
private final TristateFilter<T> filter;
private final Policy matchOn;
public MatchingPredicate(TristateFilter<T> filter, Policy matchOn) {
this.filter = filter;
this.matchOn = matchOn;
}
@Override
public boolean test(T t) {
return filter.apply(t)==matchOn;
}
}
}

View File

@ -0,0 +1,26 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.inputs.cyclelog;
import io.nosqlbench.activityapi.cyclelog.buffers.results.ResultReadable;
import java.util.function.Predicate;
public interface CanFilterResultValue {
void setFilter(Predicate<ResultReadable> filter);
}

View File

@ -0,0 +1,156 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.inputs.cyclelog;
import io.nosqlbench.activityapi.core.Activity;
import io.nosqlbench.activityapi.cyclelog.buffers.results.CycleSegment;
import io.nosqlbench.activityapi.cyclelog.buffers.results.CycleSegmentBuffer;
import io.nosqlbench.activityapi.cyclelog.buffers.results.CycleResult;
import io.nosqlbench.activityapi.cyclelog.buffers.results.CycleResultsSegment;
import io.nosqlbench.activityapi.cyclelog.buffers.results.ResultReadable;
import io.nosqlbench.activityapi.cyclelog.buffers.results_rle.CycleResultsRLEBufferReadable;
import io.nosqlbench.activityapi.input.Input;
import io.nosqlbench.util.SimpleConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Iterator;
import java.util.function.Predicate;
public class CycleLogInput implements Input, AutoCloseable, Iterable<CycleResultsSegment>, CanFilterResultValue {
private final static Logger logger = LoggerFactory.getLogger(CycleLogInput.class);
private final Iterator<CycleResultsSegment> cycleResultSegmentIterator;
private RandomAccessFile raf;
private MappedByteBuffer mbb;
private Iterator<CycleResult> segmentIter;
private Predicate<ResultReadable> filter;
public CycleLogInput(Activity activity) {
SimpleConfig conf = new SimpleConfig(activity, "input");
mbb = initMappedBuffer(conf.getString("file").orElse(activity.getAlias()) + ".cyclelog");
cycleResultSegmentIterator = iterator();
segmentIter = cycleResultSegmentIterator.next().iterator();
}
public CycleLogInput(String filename) {
File cycleFile = null;
try {
cycleFile = new File(filename);
if (!cycleFile.exists()) {
cycleFile = new File(cycleFile + ".cyclelog");
if (!cycleFile.exists()) {
throw new RuntimeException("Cyclelog file does not exist:" + filename);
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
mbb = initMappedBuffer(cycleFile.getPath());
cycleResultSegmentIterator = new CycleResultsRLEBufferReadable(mbb).iterator();
segmentIter = cycleResultSegmentIterator.next().iterator();
}
@Override
public void setFilter(Predicate<ResultReadable> filter) {
this.filter = filter;
}
@Override
public synchronized CycleSegment getInputSegment(int segmentLength) {
CycleSegmentBuffer csb = new CycleSegmentBuffer(segmentLength);
while (csb.remaining() > 0) {
while (!segmentIter.hasNext() && cycleResultSegmentIterator.hasNext()) {
segmentIter = cycleResultSegmentIterator.next().iterator();
}
if (segmentIter.hasNext()) {
CycleResult cycleResult = segmentIter.next();
if (filter==null || filter.test(cycleResult)) {
csb.append(cycleResult.getCycle());
}
} else {
if (csb.remaining() == segmentLength) {
return null;
} else {
break;
}
}
}
return csb.toReadable();
}
// // acquire a buffered interval result
// if (currentBuffer == null) {
// currentBuffer = CycleResultsRLEBufferReadable.forOneRleSpan(mbb);
// if (currentBuffer == null) {
// // or return null if none are left
// return null;
// } else {
// strider = new CycleResultStrider(currentBuffer.getCycleResultIterable().iterator());
// }
// }
// CycleResultsSegment cycleResultsSegment = strider.getCycleResultsSegment(remaining);
// if (cycleResultsSegment!=null) {
// for (CycleResult cycleResult : cycleResultsSegment) {
// csb.append(cycleResult.getCycle());
// }
// }
// // else try again, because there are apparently more RLESegments to read.
//
// remaining = csb.remaining();
private MappedByteBuffer initMappedBuffer(String filename) {
File filepath = new File(filename);
if (!filepath.exists()) {
throw new RuntimeException("file path '" + filename + "' does not exist!");
}
try {
raf = new RandomAccessFile(filepath, "r");
mbb = raf.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, raf.length());
} catch (Exception e) {
throw new RuntimeException(e);
}
return mbb;
}
@Override
public void close() throws Exception {
if (raf != null) {
raf.close();
mbb = null;
}
}
@Override
public Iterator<CycleResultsSegment> iterator() {
CycleResultsRLEBufferReadable cycleResultsSegments = new CycleResultsRLEBufferReadable(mbb.duplicate());
if (cycleResultsSegments instanceof CanFilterResultValue) {
((CanFilterResultValue)cycleResultsSegments).setFilter(filter);
}
return cycleResultsSegments.iterator();
}
}

View File

@ -0,0 +1,54 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.inputs.cyclelog;
import io.nosqlbench.activityapi.core.Activity;
import io.nosqlbench.activityapi.input.Input;
import io.nosqlbench.activityapi.input.InputDispenser;
import io.nosqlbench.activityapi.input.InputType;
import io.virtdata.annotations.Service;
@Service(InputType.class)
public class CycleLogInputType implements InputType {
@Override
public String getName() {
return "cyclelog";
}
@Override
public InputDispenser getInputDispenser(Activity activity) {
return new Dispenser(activity);
}
public static class Dispenser implements InputDispenser {
private final Activity activity;
private final Input input;
public Dispenser(Activity activity) {
this.activity = activity;
this.input = new CycleLogInput(activity);
}
@Override
public Input getInput(long slot) {
return input;
}
}
}

View File

@ -0,0 +1,22 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.outputs;
public interface CanSortCycles {
void sort();
}

View File

@ -0,0 +1,105 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.outputs;
import io.nosqlbench.activityapi.cyclelog.buffers.results.CycleResultArray;
import io.nosqlbench.activityapi.cyclelog.buffers.results.CycleResultsSegment;
import io.nosqlbench.activityapi.cyclelog.buffers.results.CycleResultsSegmentReadable;
import io.nosqlbench.activityapi.cyclelog.buffers.results.ResultReadable;
import io.nosqlbench.activityapi.cyclelog.inputs.cyclelog.CanFilterResultValue;
import io.nosqlbench.activityapi.output.Output;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collections;
import java.util.LinkedList;
import java.util.function.Predicate;
/**
* This will implement a result buffer that puts cycles in order when possible,
* according to a sliding window.
*/
public class ReorderingConcurrentResultBuffer implements Output, CanFilterResultValue {
private final static Logger logger = LoggerFactory.getLogger(ReorderingConcurrentResultBuffer.class);
private LinkedList<CycleResultsSegment> segments = new LinkedList<>();
private Output downstream;
private final int threshold;
private int currentCount;
private int segmentCount;
private Predicate<ResultReadable> resultFilter;
public ReorderingConcurrentResultBuffer(Output downstream) {
this(downstream,1000);
}
public ReorderingConcurrentResultBuffer(Output downstream, int threshold) {
this.downstream = downstream;
this.threshold = threshold;
}
@Override
public synchronized boolean onCycleResult(long completedCycle, int result) {
this.onCycleResultSegment(CycleResultsSegmentReadable.forCycleResult(completedCycle, result));
return true;
}
@Override
public synchronized void onCycleResultSegment(CycleResultsSegment segment) {
if (resultFilter!=null) {
segment = segment.filter(resultFilter);
}
if (!(segment instanceof CanSortCycles)) {
segment = new CycleResultArray(segment);
}
((CanSortCycles)segment).sort();
segments.add(segment);
segmentCount++;
currentCount+=segment.getCount();
if (currentCount>=threshold) {
logger.trace("Reordering threshold met: " + currentCount +"/" + threshold + ", sorting and pushing. (" + segments.size() + " segments)");
Collections.sort(segments);
while(currentCount>=threshold) {
CycleResultsSegment head = segments.removeFirst();
downstream.onCycleResultSegment(head);
segmentCount--;
currentCount-=head.getCount();
}
}
}
@Override
public synchronized void close() throws Exception {
logger.trace("closing and flushing " + segments.size() + " segments");
Collections.sort(segments);
for (CycleResultsSegment segment : segments) {
downstream.onCycleResultSegment(segment);
segmentCount--;
currentCount-=segment.getCount();
}
downstream.close();
}
@Override
public void setFilter(Predicate<ResultReadable> filter) {
this.resultFilter = filter;
}
}

View File

@ -0,0 +1,93 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.outputs.cyclelog;
import io.nosqlbench.activityapi.cyclelog.buffers.results.CycleResult;
import io.nosqlbench.activityapi.cyclelog.buffers.results.CycleResultsSegment;
import io.nosqlbench.activityapi.cyclelog.buffers.results_rle.CycleResultsRLEBufferReadable;
import java.io.File;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
public class CycleLogDumperUtility {
public static void main(String[] args) {
if (args.length == 0) {
System.out.println("USAGE: CyclesCLI <filename>");
}
String filename = args[0];
DisplayType displayType = DisplayType.spans;
if (args.length >= 2) {
displayType = DisplayType.valueOf(args[1]);
}
new CycleLogDumperUtility().dumpData(filename, displayType);
}
private void dumpData(String filename, DisplayType displayType) {
File filepath = new File(filename);
MappedByteBuffer mbb = null;
if (!filepath.exists()) {
if (!filepath.getPath().endsWith(".cyclelog")) {
filepath = new File(filename+".cyclelog");
if (!filepath.exists()) {
throw new RuntimeException("neither '" + filename + "' nor '" + filename + ".cyclelog' exists!");
}
}
}
try {
RandomAccessFile raf = new RandomAccessFile(filepath, "rw");
mbb = raf.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, raf.length());
} catch (Exception e) {
throw new RuntimeException(e);
}
int readsize = 100;
if (mbb.remaining() > 0) {
CycleResultsRLEBufferReadable readable = null;
while (mbb.remaining() > 0) {
readable = new CycleResultsRLEBufferReadable(readsize, mbb);
for (CycleResultsSegment segment : readable) {
switch (displayType) {
case cycles:
for (CycleResult cycleResult : segment) {
System.out.println(cycleResult);
}
break;
case spans:
System.out.println(segment.toString());
break;
}
}
}
}
}
static enum DisplayType {
cycles,
spans
}
}

View File

@ -0,0 +1,69 @@
/*
*
* Copyright 2016 jshook
* 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.activityapi.cyclelog.outputs.cyclelog;
import io.nosqlbench.activityapi.cyclelog.buffers.results_rle.CycleSpanResults;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class CycleLogImporterUtility {
private final static Pattern linePattern = Pattern.compile("\\[?(?<start>\\d+)(,(?<end>\\d+)\\))?->(?<result>\\d+)");
public static void main(String[] args) {
if (args.length == 0) {
System.out.println("USAGE: CyclesCLI <input-textfile>, <output-cyclelog>");
}
String infile = args[0];
String outfile = args[1];
try {
new CycleLogImporterUtility().convert(infile, outfile);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private void convert(String infile, String outfile) throws Exception {
CycleLogOutput output = new CycleLogOutput(new File(outfile), 1024);
BufferedReader reader = new BufferedReader(new FileReader(infile));
String line = reader.readLine();
while (line != null) {
Matcher matcher = linePattern.matcher(line);
if (matcher.matches()) {
long start = Long.valueOf(matcher.group("start"));
int result = Integer.valueOf(matcher.group("result"));
String endMatched = matcher.group("end");
if (endMatched == null) {
output.onCycleResult(start, result);
} else {
long end = Long.valueOf(endMatched);
output.onCycleResultSegment(new CycleSpanResults(start, end, result));
}
} else {
throw new RuntimeException("Unrecognized line format on import: " + line);
}
line = reader.readLine();
}
output.close();
}
}

Some files were not shown because too many files have changed in this diff Show More