mirror of
https://github.com/nosqlbench/nosqlbench.git
synced 2025-02-25 18:55:28 -06:00
import nosqlbench
This commit is contained in:
parent
62d53ecec6
commit
fdc3d79856
169
nb-api/pom.xml
Normal file
169
nb-api/pom.xml
Normal 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>
|
129
nb-api/src/main/java/activityconfig/MultiMapLookup.java
Normal file
129
nb-api/src/main/java/activityconfig/MultiMapLookup.java
Normal 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(","));
|
||||
}
|
||||
}
|
163
nb-api/src/main/java/activityconfig/ParsedStmt.java
Normal file
163
nb-api/src/main/java/activityconfig/ParsedStmt.java
Normal 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();
|
||||
}
|
||||
}
|
43
nb-api/src/main/java/activityconfig/StatementsLoader.java
Normal file
43
nb-api/src/main/java/activityconfig/StatementsLoader.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
64
nb-api/src/main/java/activityconfig/rawyaml/BlockParams.java
Normal file
64
nb-api/src/main/java/activityconfig/rawyaml/BlockParams.java
Normal 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());
|
||||
}
|
||||
}
|
86
nb-api/src/main/java/activityconfig/rawyaml/RawStmtDef.java
Normal file
86
nb-api/src/main/java/activityconfig/rawyaml/RawStmtDef.java
Normal 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());
|
||||
}
|
||||
}
|
@ -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 {
|
||||
|
||||
}
|
60
nb-api/src/main/java/activityconfig/rawyaml/RawStmtsDoc.java
Normal file
60
nb-api/src/main/java/activityconfig/rawyaml/RawStmtsDoc.java
Normal 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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
40
nb-api/src/main/java/activityconfig/rawyaml/Tags.java
Normal file
40
nb-api/src/main/java/activityconfig/rawyaml/Tags.java
Normal 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);
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
70
nb-api/src/main/java/activityconfig/yaml/StmtDef.java
Normal file
70
nb-api/src/main/java/activityconfig/yaml/StmtDef.java
Normal 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);
|
||||
}
|
||||
}
|
87
nb-api/src/main/java/activityconfig/yaml/StmtsBlock.java
Normal file
87
nb-api/src/main/java/activityconfig/yaml/StmtsBlock.java
Normal 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();
|
||||
}
|
||||
}
|
107
nb-api/src/main/java/activityconfig/yaml/StmtsDoc.java
Normal file
107
nb-api/src/main/java/activityconfig/yaml/StmtsDoc.java
Normal 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();
|
||||
}
|
||||
|
||||
|
||||
}
|
85
nb-api/src/main/java/activityconfig/yaml/StmtsDocList.java
Normal file
85
nb-api/src/main/java/activityconfig/yaml/StmtsDocList.java
Normal 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;
|
||||
}
|
||||
}
|
@ -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() {
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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();
|
||||
}
|
@ -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);
|
||||
}
|
@ -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 {
|
||||
}
|
@ -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);
|
||||
}
|
@ -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();
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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);
|
||||
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
@ -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();
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
@ -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();
|
||||
}
|
@ -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();
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package io.nosqlbench.activityapi.core.ops.fluent;
|
||||
|
||||
public interface FluentOp {
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
@ -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) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
@ -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);
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
@ -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();
|
||||
}
|
@ -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();
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
@ -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);
|
||||
|
||||
}
|
@ -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");
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
@ -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);
|
||||
}
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
@ -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();
|
||||
}
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
@ -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 +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
@ -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();
|
||||
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
@ -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 {
|
||||
}
|
@ -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() + ")";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
|
||||
}
|
@ -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;
|
||||
// }
|
||||
}
|
@ -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);
|
||||
}
|
@ -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();
|
||||
}
|
@ -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);
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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> {
|
||||
}
|
@ -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();
|
||||
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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];
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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
Loading…
Reference in New Issue
Block a user