diff --git a/nb-adapters/adapter-cqld4/pom.xml b/nb-adapters/adapter-cqld4/pom.xml index cbd7011e8..124a9e244 100644 --- a/nb-adapters/adapter-cqld4/pom.xml +++ b/nb-adapters/adapter-cqld4/pom.xml @@ -93,7 +93,7 @@ org.bouncycastle bcprov-jdk18on - 1.77 + 1.78 com.fasterxml.jackson.core diff --git a/nb-adapters/adapter-cqld4/src/main/java/io/nosqlbench/cqlgen/grammars/CqlLexer.g4 b/nb-adapters/adapter-cqld4/src/main/java/io/nosqlbench/cqlgen/grammars/CqlLexer.g4 index 3704d355e..986367a38 100644 --- a/nb-adapters/adapter-cqld4/src/main/java/io/nosqlbench/cqlgen/grammars/CqlLexer.g4 +++ b/nb-adapters/adapter-cqld4/src/main/java/io/nosqlbench/cqlgen/grammars/CqlLexer.g4 @@ -6,26 +6,26 @@ options { // Operators and Punctuators -LR_BRACKET: '('; +LR_BRACKET: '(' -> pushMode(IDENTIFIER_MODE); RR_BRACKET: ')'; -LC_BRACKET: '{'; +LC_BRACKET: '{' -> pushMode(IDENTIFIER_MODE); RC_BRACKET: '}'; -LS_BRACKET: '['; +LS_BRACKET: '[' -> pushMode(IDENTIFIER_MODE); RS_BRACKET: ']'; -COMMA: ','; +COMMA: ',' -> pushMode(IDENTIFIER_MODE); SEMI: ';'; COLON: ':'; -DOT: '.'; +DOT: '.' -> pushMode(IDENTIFIER_MODE); STAR: '*'; DIVIDE: '/'; MODULE: '%'; -PLUS: '+'; +PLUS: '+' -> pushMode(IDENTIFIER_MODE); MINUSMINUS: '--'; MINUS: '-'; DQUOTE: '"'; SQUOTE: '\''; -OPERATOR_EQ: '='; -OPERATOR_LT: '<'; +OPERATOR_EQ: '=' -> pushMode(IDENTIFIER_MODE); +OPERATOR_LT: '<' -> pushMode(IDENTIFIER_MODE); OPERATOR_GT: '>'; OPERATOR_LTE: '<='; OPERATOR_GTE: '>='; @@ -37,7 +37,7 @@ K_AGGREGATE: 'AGGREGATE'; K_ALL: 'ALL'; K_ALLOW: 'ALLOW'; K_ALTER: 'ALTER'; -K_AND: 'AND'; +K_AND: 'AND' -> pushMode(IDENTIFIER_MODE); K_ANY: 'ANY'; K_APPLY: 'APPLY'; K_AS: 'AS'; @@ -63,7 +63,7 @@ K_DURABLE_WRITES: 'DURABLE_WRITES'; K_EACH_QUORUM: 'EACH_QUORUM'; K_ENTRIES: 'ENTRIES'; K_EXECUTE: 'EXECUTE'; -K_EXISTS: 'EXISTS'; +K_EXISTS: 'EXISTS' -> pushMode(IDENTIFIER_MODE); K_FALSE: 'FALSE'; K_FILTERING: 'FILTERING'; K_FINALFUNC: 'FINALFUNC'; @@ -84,7 +84,7 @@ K_IS: 'IS'; K_JSON: 'JSON'; K_KEY: 'KEY'; K_KEYS: 'KEYS'; -K_KEYSPACE: 'KEYSPACE'; +K_KEYSPACE: 'KEYSPACE' -> pushMode(IDENTIFIER_MODE); K_KEYSPACES: 'KEYSPACES'; K_LANGUAGE: 'LANGUAGE'; // Disabled because there was no definitive reference to this as a bare keyword in the specs @@ -101,8 +101,8 @@ K_NORECURSIVE: 'NORECURSIVE'; K_NOSUPERUSER: 'NOSUPERUSER'; K_NOT: 'NOT'; K_NULL: 'NULL'; -K_OF: 'OF'; -K_ON: 'ON'; +K_OF: 'OF' -> pushMode(IDENTIFIER_MODE); +K_ON: 'ON' -> pushMode(IDENTIFIER_MODE); K_ONE: 'ONE'; K_OPTIONS: 'OPTIONS'; K_OR: 'OR'; @@ -114,7 +114,7 @@ K_PERMISSION: 'PERMISSION'; K_PERMISSIONS: 'PERMISSIONS'; K_PRIMARY: 'PRIMARY'; K_QUORUM: 'QUORUM'; -K_RENAME: 'RENAME'; +K_RENAME: 'RENAME' -> pushMode(IDENTIFIER_MODE); K_REPLACE: 'REPLACE'; K_REPLICATION: 'REPLICATION'; K_RETURNS: 'RETURNS'; @@ -123,32 +123,34 @@ K_ROLE: 'ROLE'; K_ROLES: 'ROLES'; K_SCHEMA: 'SCHEMA'; K_SELECT: 'SELECT'; -K_SET: 'SET'; +K_SET_WITH_OPERATOR_LT: K_SET SPACE? OPERATOR_LT -> pushMode(IDENTIFIER_MODE); +K_SET: 'SET' -> pushMode(IDENTIFIER_MODE); K_SFUNC: 'SFUNC'; K_STATIC: 'STATIC'; K_STORAGE: 'STORAGE'; K_STYPE: 'STYPE'; K_SUPERUSER: 'SUPERUSER'; -K_TABLE: 'TABLE'; +K_TABLE: 'TABLE' -> pushMode(IDENTIFIER_MODE); K_THREE: 'THREE'; +K_TIMESTAMP_WITH_DECIMAL_LITERAL: K_TIMESTAMP SPACE DECIMAL_LITERAL; K_TIMESTAMP: 'TIMESTAMP'; -K_TO: 'TO'; +K_TO: 'TO' -> pushMode(IDENTIFIER_MODE); K_TOKEN: 'TOKEN'; K_TRIGGER: 'TRIGGER'; K_TRUE: 'TRUE'; -K_TRUNCATE: 'TRUNCATE'; +K_TRUNCATE: 'TRUNCATE' -> pushMode(IDENTIFIER_MODE); K_TTL: 'TTL'; K_TWO: 'TWO'; -K_TYPE: 'TYPE'; +K_TYPE: 'TYPE' -> pushMode(IDENTIFIER_MODE); K_UNLOGGED: 'UNLOGGED'; -K_UPDATE: 'UPDATE'; -K_USE: 'USE'; +K_UPDATE: 'UPDATE' -> pushMode(IDENTIFIER_MODE); +K_USE: 'USE' -> pushMode(IDENTIFIER_MODE); K_USER: 'USER'; K_USING: 'USING'; K_UUID: 'UUID'; K_VALUES: 'VALUES'; K_VIEW: 'VIEW'; -K_WHERE: 'WHERE'; +K_WHERE: 'WHERE' -> pushMode(IDENTIFIER_MODE); K_WITH: 'WITH'; K_WRITETIME: 'WRITETIME'; K_ASCII: 'ASCII'; @@ -160,10 +162,13 @@ K_DATE: 'DATE'; K_DECIMAL: 'DECIMAL'; K_DOUBLE: 'DOUBLE'; K_FLOAT: 'FLOAT'; +K_FROZEN_WITH_OPERATOR_LT: K_FROZEN SPACE? OPERATOR_LT -> pushMode(IDENTIFIER_MODE); K_FROZEN: 'FROZEN'; K_INET: 'INET'; K_INT: 'INT'; +K_LIST_WITH_OPERATOR_LT: K_LIST SPACE? OPERATOR_LT -> pushMode(IDENTIFIER_MODE); K_LIST: 'LIST'; +K_MAP_WITH_OPERATOR_LT: K_MAP SPACE? OPERATOR_LT -> pushMode(IDENTIFIER_MODE); K_MAP: 'MAP'; K_SMALLINT: 'SMALLINT'; K_TEXT: 'TEXT'; @@ -221,5 +226,99 @@ fragment DEC_DIGIT: [0-9]; fragment EXPONENT_NUM_PART: 'E' ('-'|'+') ? DEC_DIGIT+; +mode IDENTIFIER_MODE; +SEMI_: SEMI -> type(SEMI), popMode; +LC_BRACKET_: LC_BRACKET -> type(LC_BRACKET); +LS_BRACKET_: LS_BRACKET -> type(LS_BRACKET); +LR_BRACKET_: LR_BRACKET -> type(LR_BRACKET); +OPERATOR_LT_: OPERATOR_LT -> type(OPERATOR_LT); + +RR_BRACKET_: RR_BRACKET -> type(RR_BRACKET), popMode; +RC_BRACKET_: RC_BRACKET -> type(RC_BRACKET), popMode; +RS_BRACKET_: RS_BRACKET -> type(RS_BRACKET), popMode; + +OPERATOR_GT_: OPERATOR_GT -> type(OPERATOR_GT), popMode; + +// Reserved Keywords which cannot be used as identifiers +// https://cassandra.apache.org/doc/4.1/cassandra/cql/appendices.html#appendix-A +K_ADD_: K_ADD -> type(K_ADD), popMode; +K_AGGREGATE_: K_AGGREGATE -> type(K_AGGREGATE), popMode; +K_ALLOW_: K_ALLOW -> type(K_ALLOW), popMode; +K_ALTER_: K_ALTER -> type(K_ALTER), popMode; +K_AND_: K_AND -> type(K_AND), popMode; +K_ANY_: K_ANY -> type(K_ANY), popMode; +K_APPLY_: K_APPLY -> type(K_APPLY), popMode; +K_ASC_: K_ASC -> type(K_ASC), popMode; +K_AUTHORIZE_: K_AUTHORIZE -> type(K_AUTHORIZE), popMode; +K_BATCH_: K_BATCH -> type(K_BATCH), popMode; +K_BEGIN_: K_BEGIN -> type(K_BEGIN), popMode; +K_BY_: K_BY -> type(K_BY), popMode; +K_COLUMNFAMILY_: K_COLUMNFAMILY -> type(K_COLUMNFAMILY), popMode; +K_CREATE_: K_CREATE -> type(K_CREATE), popMode; +K_DELETE_: K_DELETE -> type(K_DELETE), popMode; +K_DESC_: K_DESC -> type(K_DESC), popMode; +K_DROP_: K_DROP -> type(K_DROP), popMode; +K_DURABLE_WRITES_: K_DURABLE_WRITES -> type(K_DURABLE_WRITES), popMode; +K_ENTRIES_: K_ENTRIES -> type(K_ENTRIES), popMode; +K_FALSE_: K_FALSE -> type(K_FALSE), popMode; +K_FROM_: K_FROM -> type(K_FROM), popMode; +K_FULL_: K_FULL -> type(K_FULL), popMode; +K_GRANT_: K_GRANT -> type(K_GRANT), popMode; +K_IF_: K_IF -> type(K_IF), popMode; +K_IN_: K_IN -> type(K_IN), popMode; +K_INDEX_: K_INDEX -> type(K_INDEX), popMode; +K_INFINITY_: K_INFINITY -> type(K_INFINITY), popMode; +K_INSERT_: K_INSERT -> type(K_INSERT), popMode; +K_INTO_: K_INTO -> type(K_INTO), popMode; +//K_IS: 'IS'; +K_KEYSPACE_: K_KEYSPACE -> type(K_KEYSPACE), popMode; +K_LIMIT_: K_LIMIT -> type(K_LIMIT), popMode; +K_LOGGED_: K_LOGGED -> type(K_LOGGED), popMode; +K_MODIFY_: K_MODIFY -> type(K_MODIFY), popMode; +K_NAN_: K_NAN -> type(K_NAN), popMode; +K_NORECURSIVE_: K_NORECURSIVE -> type(K_NORECURSIVE), popMode; +K_NOT_: K_NOT -> type(K_NOT), popMode; +K_NULL_: K_NULL -> type(K_NULL), popMode; +K_OF_: K_OF -> type(K_OF), popMode; +K_ON_: K_ON -> type(K_ON), popMode; +K_OR_: K_OR -> type(K_OR), popMode; +K_ORDER_: K_ORDER -> type(K_ORDER), popMode; +K_PRIMARY_: K_PRIMARY -> type(K_PRIMARY), popMode; +K_RENAME_: K_RENAME -> type(K_RENAME), popMode; +K_REPLACE_: K_REPLACE -> type(K_REPLACE), popMode; +K_REVOKE_: K_REVOKE -> type(K_REVOKE), popMode; +K_SCHEMA_: K_SCHEMA -> type(K_SCHEMA), popMode; +K_SELECT_: K_SELECT -> type(K_SELECT), popMode; +K_SET_: K_SET -> type(K_SET), popMode; +K_TABLE_: K_TABLE -> type(K_TABLE), popMode; +K_TO_: K_TO -> type(K_TO), popMode; +K_TOKEN_: K_TOKEN -> type(K_TOKEN), popMode; +K_TRUNCATE_: K_TRUNCATE -> type(K_TRUNCATE), popMode; +K_UNLOGGED_: K_UNLOGGED -> type(K_UNLOGGED), popMode; +K_UPDATE_: K_UPDATE -> type(K_UPDATE), popMode; +K_USE_: K_USE -> type(K_USE), popMode; +K_USING_: K_USING -> type(K_USING), popMode; +K_WHERE_: K_WHERE -> type(K_WHERE), popMode; +K_WITH_: K_WITH -> type(K_WITH), popMode; + +// handeling cases like 'frozen<','map<','list<','set<' and 'TIMESTAMP WITH 1234' +K_MAP_WITH_OPERATOR_LT_: K_MAP_WITH_OPERATOR_LT -> type(K_MAP_WITH_OPERATOR_LT); +K_TIMESTAMP_WITH_DECIMAL_LITERAL_: K_TIMESTAMP_WITH_DECIMAL_LITERAL -> type(K_TIMESTAMP_WITH_DECIMAL_LITERAL); +K_FROZEN_WITH_OPERATOR_LT_: K_FROZEN_WITH_OPERATOR_LT -> type(K_FROZEN_WITH_OPERATOR_LT); +K_SET_WITH_OPERATOR_LT_: K_SET_WITH_OPERATOR_LT -> type(K_SET_WITH_OPERATOR_LT); +K_LIST_WITH_OPERATOR_LT_: K_LIST_WITH_OPERATOR_LT -> type(K_LIST_WITH_OPERATOR_LT); + +OBJECT_NAME_ : OBJECT_NAME -> type(OBJECT_NAME), popMode; +SPACE_: [ \t\r\n]+ -> channel (HIDDEN); + +UUID_: UUID -> type(UUID), popMode; + +// Literals +CODE_BLOCK_: CODE_BLOCK -> type(CODE_BLOCK), popMode; +STRING_LITERAL_: STRING_LITERAL -> type(STRING_LITERAL), popMode; +DECIMAL_LITERAL_: DECIMAL_LITERAL -> type(DECIMAL_LITERAL), popMode; +FLOAT_LITERAL_: FLOAT_LITERAL -> type(FLOAT_LITERAL), popMode; +HEXADECIMAL_LITERAL_: HEXADECIMAL_LITERAL -> type(HEXADECIMAL_LITERAL), popMode; +REAL_LITERAL_ : REAL_LITERAL -> type(REAL_LITERAL), popMode; diff --git a/nb-adapters/adapter-cqld4/src/main/java/io/nosqlbench/cqlgen/grammars/CqlParser.g4 b/nb-adapters/adapter-cqld4/src/main/java/io/nosqlbench/cqlgen/grammars/CqlParser.g4 index 1a998eeec..e4b3ab6e5 100644 --- a/nb-adapters/adapter-cqld4/src/main/java/io/nosqlbench/cqlgen/grammars/CqlParser.g4 +++ b/nb-adapters/adapter-cqld4/src/main/java/io/nosqlbench/cqlgen/grammars/CqlParser.g4 @@ -136,7 +136,7 @@ createType ; typeMemberColumnList - : column dataType (syntaxComma column dataType)* + : column dataType (syntaxComma column dataType)* syntaxComma? ; createTrigger @@ -244,8 +244,8 @@ alterType ; alterTypeOperation - : alterTypeAlterType - | alterTypeAdd +// : alterTypeAlterType + : alterTypeAdd | alterTypeRename ; @@ -262,7 +262,7 @@ alterTypeRenameItem ; alterTypeAdd - : kwAdd column dataType (syntaxComma column dataType)* + : kwAdd column dataType ; alterTypeAlterType @@ -615,7 +615,7 @@ usingTtlTimestamp ; timestamp - : kwTimestamp decimalLiteral + : K_TIMESTAMP_WITH_DECIMAL_LITERAL ; ttl @@ -767,6 +767,7 @@ stringLiteral booleanLiteral : K_TRUE | K_FALSE + | OBJECT_NAME ; hexadecimalLiteral @@ -790,10 +791,10 @@ column dataType : dataTypeName - | K_FROZEN syntaxBracketLa dataType syntaxBracketRa - | K_SET syntaxBracketLa dataType syntaxBracketRa - | K_LIST syntaxBracketLa dataType syntaxBracketRa - | K_MAP syntaxBracketLa dataType syntaxComma dataType syntaxBracketRa + | K_FROZEN_WITH_OPERATOR_LT dataType syntaxBracketRa + | K_SET_WITH_OPERATOR_LT dataType syntaxBracketRa + | K_LIST_WITH_OPERATOR_LT dataType syntaxBracketRa + | K_MAP_WITH_OPERATOR_LT dataType syntaxComma dataType syntaxBracketRa ; dataTypeName @@ -901,6 +902,7 @@ kwAggregate kwAll : K_ALL + | OBJECT_NAME ; kwAllPermissions @@ -1101,6 +1103,7 @@ kwLogged kwLogin : K_LOGIN + | OBJECT_NAME ; kwMaterialized @@ -1137,6 +1140,7 @@ kwOn kwOptions : K_OPTIONS + | OBJECT_NAME ; kwOr @@ -1149,6 +1153,7 @@ kwOrder kwPassword : K_PASSWORD + | OBJECT_NAME ; kwPrimary @@ -1201,6 +1206,7 @@ kwStype kwSuperuser : K_SUPERUSER + | OBJECT_NAME ; kwTable diff --git a/nb-adapters/adapter-cqld4/src/test/java/io/nosqlbench/converters/cql/cql/parser/CqlParserHarnessTest.java b/nb-adapters/adapter-cqld4/src/test/java/io/nosqlbench/converters/cql/cql/parser/CqlParserHarnessTest.java index b630a170b..f76c2557e 100644 --- a/nb-adapters/adapter-cqld4/src/test/java/io/nosqlbench/converters/cql/cql/parser/CqlParserHarnessTest.java +++ b/nb-adapters/adapter-cqld4/src/test/java/io/nosqlbench/converters/cql/cql/parser/CqlParserHarnessTest.java @@ -21,6 +21,12 @@ import io.nosqlbench.cqlgen.parser.CqlModelParser; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Objects; + public class CqlParserHarnessTest { private final static String ksddl = """ @@ -81,5 +87,22 @@ public class CqlParserHarnessTest { """, null); } + @Test + @Disabled + public void testCqlExamples() throws IOException { + File folderPath = new File("src/test/resources/cql3_examples"); + for (final File file : Objects.requireNonNull(folderPath.listFiles())) { + String query = Files.readString(Path.of(file.getPath())); + CqlModelParser.parse(query, null); + } + } + @Disabled + @Test + public void testUdt() { + CGWorkloadExporter exporter = new CGWorkloadExporter(); + exporter.applyAsInt(new String[] {"src/test/resources/testschemas/cql_udt.cql", "cql_udt.yaml"}); + exporter.setNamingTemplate("[OPTYPE-][COLUMN-][TYPEDEF-][TABLE-]-[KEYSPACE]"); + exporter.getWorkloadAsYaml(); + } } diff --git a/nb-adapters/adapter-cqld4/src/test/resources/testschemas/cql_udt.cql b/nb-adapters/adapter-cqld4/src/test/resources/testschemas/cql_udt.cql new file mode 100644 index 000000000..9e1898b2b --- /dev/null +++ b/nb-adapters/adapter-cqld4/src/test/resources/testschemas/cql_udt.cql @@ -0,0 +1,27 @@ +CREATE KEYSPACE baselines + WITH REPLICATION = { + 'class' : 'SimpleStrategy', + 'replication_factor' : 1 + }; + +CREATE TYPE baselines.phone ( + country_code int, + number text, +); + +CREATE TYPE baselines.address ( + street text, + city text, + zip text, + phones map +); + +CREATE TABLE baselines.user ( + name text PRIMARY KEY, + addresses map> +); + +ALTER TYPE baselines.address RENAME zip TO zipcode AND city to city_code; +ALTER TYPE baselines.address ADD country text; + +DROP TYPE IF EXISTS baselines.address; diff --git a/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/Neo4JOpMapper.java b/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/Neo4JOpMapper.java index 918d52f4d..1f0691b61 100644 --- a/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/Neo4JOpMapper.java +++ b/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/Neo4JOpMapper.java @@ -43,13 +43,22 @@ public class Neo4JOpMapper implements OpMapper { LongFunction spaceNameFunc = op.getAsFunctionOr("space", "default"); LongFunction spaceFunc = l -> cache.get(spaceNameFunc.apply(l)); return switch (typeAndTarget.enumId) { - case autocommit -> new Neo4JAutoCommitOpDispenser( + case sync_autocommit -> new Neo4JSyncAutoCommitOpDispenser( adapter, op, spaceFunc, typeAndTarget.enumId.getValue() ); - case read_transaction -> new Neo4JReadTxnOpDispenser( + case async_autocommit -> new Neo4JAsyncAutoCommitOpDispenser( adapter, op, spaceFunc, typeAndTarget.enumId.getValue() ); - case write_transaction -> new Neo4JWriteTxnOpDispenser( + case sync_read_transaction -> new Neo4JSyncReadTxnOpDispenser( + adapter, op, spaceFunc, typeAndTarget.enumId.getValue() + ); + case async_read_transaction -> new Neo4JAsyncReadTxnOpDispenser( + adapter, op, spaceFunc, typeAndTarget.enumId.getValue() + ); + case sync_write_transaction -> new Neo4JSyncWriteTxnOpDispenser( + adapter, op, spaceFunc, typeAndTarget.enumId.getValue() + ); + case async_write_transaction -> new Neo4JAsyncWriteTxnOpDispenser( adapter, op, spaceFunc, typeAndTarget.enumId.getValue() ); }; diff --git a/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/opdispensers/Neo4JWriteTxnOpDispenser.java b/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/opdispensers/Neo4JAsyncAutoCommitOpDispenser.java similarity index 72% rename from nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/opdispensers/Neo4JWriteTxnOpDispenser.java rename to nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/opdispensers/Neo4JAsyncAutoCommitOpDispenser.java index cfb5d5aea..4d1079be7 100644 --- a/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/opdispensers/Neo4JWriteTxnOpDispenser.java +++ b/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/opdispensers/Neo4JAsyncAutoCommitOpDispenser.java @@ -17,24 +17,24 @@ package io.nosqlbench.adapter.neo4j.opdispensers; import io.nosqlbench.adapter.neo4j.Neo4JDriverAdapter; +import io.nosqlbench.adapter.neo4j.ops.Neo4JAsyncAutoCommitOp; import io.nosqlbench.adapter.neo4j.Neo4JSpace; -import io.nosqlbench.adapter.neo4j.ops.Neo4JWriteTxnOp; -import io.nosqlbench.adapter.neo4j.types.Neo4JOpType; import io.nosqlbench.adapters.api.templating.ParsedOp; + import org.neo4j.driver.async.AsyncSession; import java.util.function.LongFunction; -public class Neo4JWriteTxnOpDispenser extends Neo4JBaseOpDispenser { +public class Neo4JAsyncAutoCommitOpDispenser extends Neo4JBaseOpDispenser { - public Neo4JWriteTxnOpDispenser(Neo4JDriverAdapter adapter, ParsedOp op, LongFunction spaceFunc, String requiredTemplateKey) { + public Neo4JAsyncAutoCommitOpDispenser(Neo4JDriverAdapter adapter, ParsedOp op, LongFunction spaceFunc, String requiredTemplateKey) { super(adapter, op, spaceFunc, requiredTemplateKey); } @Override - public LongFunction createOpFunc() { - return l -> new Neo4JWriteTxnOp( + public LongFunction createOpFunc() { + return l -> new Neo4JAsyncAutoCommitOp( spaceFunc.apply(l).getDriver().session(AsyncSession.class), queryFunc.apply(l) ); diff --git a/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/opdispensers/Neo4JAutoCommitOpDispenser.java b/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/opdispensers/Neo4JAsyncReadTxnOpDispenser.java similarity index 73% rename from nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/opdispensers/Neo4JAutoCommitOpDispenser.java rename to nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/opdispensers/Neo4JAsyncReadTxnOpDispenser.java index f3899245e..a8eb63036 100644 --- a/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/opdispensers/Neo4JAutoCommitOpDispenser.java +++ b/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/opdispensers/Neo4JAsyncReadTxnOpDispenser.java @@ -17,8 +17,8 @@ package io.nosqlbench.adapter.neo4j.opdispensers; import io.nosqlbench.adapter.neo4j.Neo4JDriverAdapter; -import io.nosqlbench.adapter.neo4j.ops.Neo4JAutoCommitOp; import io.nosqlbench.adapter.neo4j.Neo4JSpace; +import io.nosqlbench.adapter.neo4j.ops.Neo4JAsyncReadTxnOp; import io.nosqlbench.adapters.api.templating.ParsedOp; import org.neo4j.driver.async.AsyncSession; @@ -26,15 +26,14 @@ import org.neo4j.driver.async.AsyncSession; import java.util.function.LongFunction; -public class Neo4JAutoCommitOpDispenser extends Neo4JBaseOpDispenser { - - public Neo4JAutoCommitOpDispenser(Neo4JDriverAdapter adapter, ParsedOp op, LongFunction spaceFunc, String requiredTemplateKey) { +public class Neo4JAsyncReadTxnOpDispenser extends Neo4JBaseOpDispenser { + public Neo4JAsyncReadTxnOpDispenser(Neo4JDriverAdapter adapter, ParsedOp op, LongFunction spaceFunc, String requiredTemplateKey) { super(adapter, op, spaceFunc, requiredTemplateKey); } @Override - public LongFunction createOpFunc() { - return l -> new Neo4JAutoCommitOp( + public LongFunction createOpFunc() { + return l -> new Neo4JAsyncReadTxnOp( spaceFunc.apply(l).getDriver().session(AsyncSession.class), queryFunc.apply(l) ); diff --git a/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/opdispensers/Neo4JReadTxnOpDispenser.java b/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/opdispensers/Neo4JAsyncWriteTxnOpDispenser.java similarity index 73% rename from nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/opdispensers/Neo4JReadTxnOpDispenser.java rename to nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/opdispensers/Neo4JAsyncWriteTxnOpDispenser.java index 770d148cf..5bc5dc5da 100644 --- a/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/opdispensers/Neo4JReadTxnOpDispenser.java +++ b/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/opdispensers/Neo4JAsyncWriteTxnOpDispenser.java @@ -18,21 +18,23 @@ package io.nosqlbench.adapter.neo4j.opdispensers; import io.nosqlbench.adapter.neo4j.Neo4JDriverAdapter; import io.nosqlbench.adapter.neo4j.Neo4JSpace; -import io.nosqlbench.adapter.neo4j.ops.Neo4JReadTxnOp; +import io.nosqlbench.adapter.neo4j.ops.Neo4JAsyncWriteTxnOp; import io.nosqlbench.adapters.api.templating.ParsedOp; + import org.neo4j.driver.async.AsyncSession; import java.util.function.LongFunction; -public class Neo4JReadTxnOpDispenser extends Neo4JBaseOpDispenser { - public Neo4JReadTxnOpDispenser(Neo4JDriverAdapter adapter, ParsedOp op, LongFunction spaceFunc, String requiredTemplateKey) { +public class Neo4JAsyncWriteTxnOpDispenser extends Neo4JBaseOpDispenser { + + public Neo4JAsyncWriteTxnOpDispenser(Neo4JDriverAdapter adapter, ParsedOp op, LongFunction spaceFunc, String requiredTemplateKey) { super(adapter, op, spaceFunc, requiredTemplateKey); } @Override - public LongFunction createOpFunc() { - return l -> new Neo4JReadTxnOp( + public LongFunction createOpFunc() { + return l -> new Neo4JAsyncWriteTxnOp( spaceFunc.apply(l).getDriver().session(AsyncSession.class), queryFunc.apply(l) ); diff --git a/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/opdispensers/Neo4JSyncAutoCommitOpDispenser.java b/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/opdispensers/Neo4JSyncAutoCommitOpDispenser.java new file mode 100644 index 000000000..bd08aa88d --- /dev/null +++ b/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/opdispensers/Neo4JSyncAutoCommitOpDispenser.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2024 nosqlbench + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.nosqlbench.adapter.neo4j.opdispensers; + +import io.nosqlbench.adapter.neo4j.Neo4JDriverAdapter; +import io.nosqlbench.adapter.neo4j.ops.Neo4JSyncAutoCommitOp; +import io.nosqlbench.adapter.neo4j.Neo4JSpace; +import io.nosqlbench.adapters.api.templating.ParsedOp; + +import org.neo4j.driver.Session; + +import java.util.function.LongFunction; + + +public class Neo4JSyncAutoCommitOpDispenser extends Neo4JBaseOpDispenser { + + public Neo4JSyncAutoCommitOpDispenser(Neo4JDriverAdapter adapter, ParsedOp op, LongFunction spaceFunc, String requiredTemplateKey) { + super(adapter, op, spaceFunc, requiredTemplateKey); + } + + @Override + public LongFunction createOpFunc() { + return l -> new Neo4JSyncAutoCommitOp( + spaceFunc.apply(l).getDriver().session(Session.class), + queryFunc.apply(l) + ); + } +} diff --git a/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/opdispensers/Neo4JSyncReadTxnOpDispenser.java b/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/opdispensers/Neo4JSyncReadTxnOpDispenser.java new file mode 100644 index 000000000..b1b170566 --- /dev/null +++ b/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/opdispensers/Neo4JSyncReadTxnOpDispenser.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2024 nosqlbench + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.nosqlbench.adapter.neo4j.opdispensers; + +import io.nosqlbench.adapter.neo4j.Neo4JDriverAdapter; +import io.nosqlbench.adapter.neo4j.ops.Neo4JSyncReadTxnOp; +import io.nosqlbench.adapter.neo4j.Neo4JSpace; +import io.nosqlbench.adapters.api.templating.ParsedOp; + +import org.neo4j.driver.Session; + +import java.util.function.LongFunction; + + +public class Neo4JSyncReadTxnOpDispenser extends Neo4JBaseOpDispenser { + + public Neo4JSyncReadTxnOpDispenser(Neo4JDriverAdapter adapter, ParsedOp op, LongFunction spaceFunc, String requiredTemplateKey) { + super(adapter, op, spaceFunc, requiredTemplateKey); + } + + @Override + public LongFunction createOpFunc() { + return l -> new Neo4JSyncReadTxnOp( + spaceFunc.apply(l).getDriver().session(Session.class), + queryFunc.apply(l) + ); + } +} diff --git a/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/opdispensers/Neo4JSyncWriteTxnOpDispenser.java b/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/opdispensers/Neo4JSyncWriteTxnOpDispenser.java new file mode 100644 index 000000000..7c7d095aa --- /dev/null +++ b/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/opdispensers/Neo4JSyncWriteTxnOpDispenser.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2024 nosqlbench + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.nosqlbench.adapter.neo4j.opdispensers; + +import io.nosqlbench.adapter.neo4j.Neo4JDriverAdapter; +import io.nosqlbench.adapter.neo4j.ops.Neo4JSyncWriteTxnOp; +import io.nosqlbench.adapter.neo4j.Neo4JSpace; +import io.nosqlbench.adapters.api.templating.ParsedOp; + +import org.neo4j.driver.Session; + +import java.util.function.LongFunction; + + +public class Neo4JSyncWriteTxnOpDispenser extends Neo4JBaseOpDispenser { + + public Neo4JSyncWriteTxnOpDispenser(Neo4JDriverAdapter adapter, ParsedOp op, LongFunction spaceFunc, String requiredTemplateKey) { + super(adapter, op, spaceFunc, requiredTemplateKey); + } + + @Override + public LongFunction createOpFunc() { + return l -> new Neo4JSyncWriteTxnOp( + spaceFunc.apply(l).getDriver().session(Session.class), + queryFunc.apply(l) + ); + } +} diff --git a/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/ops/Neo4JAutoCommitOp.java b/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/ops/Neo4JAsyncAutoCommitOp.java similarity index 90% rename from nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/ops/Neo4JAutoCommitOp.java rename to nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/ops/Neo4JAsyncAutoCommitOp.java index 7505553af..b1fd89869 100644 --- a/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/ops/Neo4JAutoCommitOp.java +++ b/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/ops/Neo4JAsyncAutoCommitOp.java @@ -26,10 +26,12 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -public class Neo4JAutoCommitOp extends Neo4JBaseOp { +public class Neo4JAsyncAutoCommitOp extends Neo4JBaseOp { + private final AsyncSession session; - public Neo4JAutoCommitOp(AsyncSession session, Query query) { - super(session, query); + public Neo4JAsyncAutoCommitOp(AsyncSession session, Query query) { + super(query); + this.session = session; } /** diff --git a/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/ops/Neo4JReadTxnOp.java b/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/ops/Neo4JAsyncReadTxnOp.java similarity index 91% rename from nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/ops/Neo4JReadTxnOp.java rename to nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/ops/Neo4JAsyncReadTxnOp.java index 861e1d33d..26f2deb93 100644 --- a/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/ops/Neo4JReadTxnOp.java +++ b/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/ops/Neo4JAsyncReadTxnOp.java @@ -26,10 +26,12 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -public class Neo4JReadTxnOp extends Neo4JBaseOp{ +public class Neo4JAsyncReadTxnOp extends Neo4JBaseOp{ + private final AsyncSession session; - public Neo4JReadTxnOp(AsyncSession session, Query query) { - super(session, query); + public Neo4JAsyncReadTxnOp(AsyncSession session, Query query) { + super(query); + this.session = session; } /** diff --git a/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/ops/Neo4JWriteTxnOp.java b/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/ops/Neo4JAsyncWriteTxnOp.java similarity index 91% rename from nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/ops/Neo4JWriteTxnOp.java rename to nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/ops/Neo4JAsyncWriteTxnOp.java index 1fec09fd6..aca7fa68b 100644 --- a/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/ops/Neo4JWriteTxnOp.java +++ b/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/ops/Neo4JAsyncWriteTxnOp.java @@ -26,10 +26,12 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -public class Neo4JWriteTxnOp extends Neo4JBaseOp{ +public class Neo4JAsyncWriteTxnOp extends Neo4JBaseOp{ + private final AsyncSession session; - public Neo4JWriteTxnOp(AsyncSession session, Query query) { - super(session, query); + public Neo4JAsyncWriteTxnOp(AsyncSession session, Query query) { + super(query); + this.session = session; } /** diff --git a/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/ops/Neo4JBaseOp.java b/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/ops/Neo4JBaseOp.java index 261b5cf19..aaced604e 100644 --- a/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/ops/Neo4JBaseOp.java +++ b/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/ops/Neo4JBaseOp.java @@ -24,20 +24,17 @@ import org.neo4j.driver.async.AsyncSession; public abstract class Neo4JBaseOp implements CycleOp { - - protected final AsyncSession session; protected final Query query; - public Neo4JBaseOp(AsyncSession session, Query query) { - this.session = session; + public Neo4JBaseOp(Query query) { this.query = query; } /** * In the child classes, this method will be responsible for: - * - using the Neo4J AsyncSession object to run the Neo4J Query + * - using the Neo4J Session/AsyncSession object to run the Neo4J Query * - process the Result to get an array of Records - * - close the AsyncSession + * - close the Session/AsyncSession * - Return the array of Records * * Session creation and closing is considered light-weight. Reference: diff --git a/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/ops/Neo4JSyncAutoCommitOp.java b/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/ops/Neo4JSyncAutoCommitOp.java new file mode 100644 index 000000000..9b1fa5f31 --- /dev/null +++ b/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/ops/Neo4JSyncAutoCommitOp.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2024 nosqlbench + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.nosqlbench.adapter.neo4j.ops; + +import org.neo4j.driver.Query; +import org.neo4j.driver.Record; +import org.neo4j.driver.Session; + +import java.util.List; + + +public class Neo4JSyncAutoCommitOp extends Neo4JBaseOp { + private final Session session; + + public Neo4JSyncAutoCommitOp(Session session, Query query) { + super(query); + this.session = session; + } + + @Override + public final Record[] apply(long value) { + List recordList = session.run(query).list(); + if (session.isOpen()) { + session.close(); + } + return recordList.toArray(new Record[recordList.size()]); + } +} diff --git a/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/ops/Neo4JSyncReadTxnOp.java b/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/ops/Neo4JSyncReadTxnOp.java new file mode 100644 index 000000000..9d6876633 --- /dev/null +++ b/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/ops/Neo4JSyncReadTxnOp.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2024 nosqlbench + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.nosqlbench.adapter.neo4j.ops; + +import org.neo4j.driver.Query; +import org.neo4j.driver.Record; +import org.neo4j.driver.Session; + +import java.util.List; + + +public class Neo4JSyncReadTxnOp extends Neo4JBaseOp{ + private final Session session; + + public Neo4JSyncReadTxnOp(Session session, Query query) { + super(query); + this.session = session; + } + + @Override + public final Record[] apply(long value) { + List recordList = session.executeRead( + txn -> { + var result = txn.run(query); + return result.list(); + } + ); + if (session.isOpen()) { + session.close(); + } + return recordList.toArray(new Record[recordList.size()]); + } +} diff --git a/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/ops/Neo4JSyncWriteTxnOp.java b/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/ops/Neo4JSyncWriteTxnOp.java new file mode 100644 index 000000000..746fee0fc --- /dev/null +++ b/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/ops/Neo4JSyncWriteTxnOp.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2024 nosqlbench + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.nosqlbench.adapter.neo4j.ops; + +import org.neo4j.driver.Query; +import org.neo4j.driver.Record; +import org.neo4j.driver.Session; + +import java.util.List; + +public class Neo4JSyncWriteTxnOp extends Neo4JBaseOp{ + private final Session session; + + public Neo4JSyncWriteTxnOp(Session session, Query query) { + super(query); + this.session = session; + } + + + @Override + public final Record[] apply(long value) { + List recordList = session.executeWrite( + txn -> { + var result = txn.run(query); + return result.list(); + } + ); + if (session.isOpen()) { + session.close(); + } + return recordList.toArray(new Record[recordList.size()]); + } +} diff --git a/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/types/Neo4JOpType.java b/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/types/Neo4JOpType.java index 8c5040ade..6f356deff 100644 --- a/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/types/Neo4JOpType.java +++ b/nb-adapters/adapter-neo4j/src/main/java/io/nosqlbench/adapter/neo4j/types/Neo4JOpType.java @@ -18,11 +18,17 @@ package io.nosqlbench.adapter.neo4j.types; public enum Neo4JOpType { - autocommit("autocommit"), + sync_autocommit("sync_autocommit"), - read_transaction("read_transaction"), + async_autocommit("async_autocommit"), - write_transaction("write_transaction"); + sync_read_transaction("sync_read_transaction"), + + async_read_transaction("async_read_transaction"), + + sync_write_transaction("sync_write_transaction"), + + async_write_transaction("async_write_transaction"); private final String value; diff --git a/nb-adapters/adapter-neo4j/src/main/resources/activities/neo4j.yaml b/nb-adapters/adapter-neo4j/src/main/resources/activities/neo4j.yaml index 825d8c05b..ee44a4a5e 100644 --- a/nb-adapters/adapter-neo4j/src/main/resources/activities/neo4j.yaml +++ b/nb-adapters/adapter-neo4j/src/main/resources/activities/neo4j.yaml @@ -24,7 +24,7 @@ blocks: ops: # Reference: https://support.neo4j.com/s/article/360059882854-Deleting-large-numbers-of-nodes#h_01H95CXNJ8TN4126T3Y01BRWKS delete_nodes: - autocommit: | + sync_autocommit: | MATCH (n) CALL { WITH n DETACH DELETE n @@ -32,14 +32,14 @@ blocks: query_params: delete_batch_size: TEMPLATE(delete_batch_size,5000) drop_index: - autocommit: DROP INDEX $index_name IF EXISTS + sync_autocommit: DROP INDEX $index_name IF EXISTS query_params: index_name: vector_index schema: ops: create_vector_index: - autocommit: | + sync_autocommit: | CREATE VECTOR INDEX $index_name IF NOT EXISTS FOR (n:TEMPLATE(node_label,Node)) ON (n.embedding) OPTIONS {indexConfig: {`vector.dimensions`: $dimension, `vector.similarity_function`: $similarity_function}} @@ -51,7 +51,7 @@ blocks: rampup: ops: insert_node: - write_transaction: | + async_write_transaction: | CREATE (v:TEMPLATE(node_label,Node) {id: $id, embedding: $vector}) query_params: id: '{id}' @@ -61,7 +61,7 @@ blocks: ops: # Reference: https://community.neo4j.com/t/unwind-multiple-arrays-to-set-property/59908/5 insert_nodes: - write_transaction: | + async_write_transaction: | WITH $id_list as ids, $vector_list as vectors UNWIND RANGE(0, size(ids) - 1) as idx CREATE (v:TEMPLATE(node_label,Node) {id: ids[idx], embedding: vectors[idx]}) @@ -72,7 +72,7 @@ blocks: search: ops: search: - read_transaction: | + async_read_transaction: | WITH $query_vector AS queryVector CALL db.index.vector.queryNodes($index_name, $k, queryVector) YIELD node diff --git a/nb-adapters/adapter-neo4j/src/main/resources/neo4j.md b/nb-adapters/adapter-neo4j/src/main/resources/neo4j.md index 0a49784a5..e986529d0 100644 --- a/nb-adapters/adapter-neo4j/src/main/resources/neo4j.md +++ b/nb-adapters/adapter-neo4j/src/main/resources/neo4j.md @@ -13,10 +13,13 @@ instance of the Neo4J/Aura database: ## Op Templates -The Neo4J adapter supports three different op types: -- autocommit -- read_transaction -- write_transaction +The Neo4J adapter supports six different op types: +- sync_autocommit +- async_autocommit +- sync_read_transaction +- async_read_transaction +- sync_write_transaction +- async_write_transaction A good reference for when to use each is located at https://neo4j.com/docs/driver-manual/1.7/sessions-transactions/ @@ -32,7 +35,7 @@ vector search functionality has been properly worked through, currently. ```yaml ops: example_create_vector_index: - autocommit: | + sync_autocommit: | CREATE VECTOR INDEX $index_name IF NOT EXISTS FOR (n:TEMPLATE(node_label,Node)) ON (n.embedding) OPTIONS {indexConfig: {`vector.dimensions`: $dimension, `vector.similarity_function`: $similarity_function}} @@ -42,14 +45,14 @@ ops: similarity_function: TEMPLATE(similarity_function,cosine) example_insert_node: - write_transaction: | + async_write_transaction: | CREATE (v:TEMPLATE(node_label,Node) {id: $id, embedding: $vector}) query_params: id: '{id}' vector: '{train_vector}' example_search: - read_transaction: | + async_read_transaction: | WITH $query_vector AS queryVector CALL db.index.vector.queryNodes($index_name, $k, queryVector) YIELD node diff --git a/nb-adapters/adapter-s4j/pom.xml b/nb-adapters/adapter-s4j/pom.xml index b3fec0325..3c154f816 100644 --- a/nb-adapters/adapter-s4j/pom.xml +++ b/nb-adapters/adapter-s4j/pom.xml @@ -37,7 +37,7 @@ - 4.0.1 + 4.1.2-alpha diff --git a/nb-adapters/adapter-s4j/src/main/java/io/nosqlbench/adapter/s4j/S4JSpace.java b/nb-adapters/adapter-s4j/src/main/java/io/nosqlbench/adapter/s4j/S4JSpace.java index 181bdf5c8..d9153ea01 100644 --- a/nb-adapters/adapter-s4j/src/main/java/io/nosqlbench/adapter/s4j/S4JSpace.java +++ b/nb-adapters/adapter-s4j/src/main/java/io/nosqlbench/adapter/s4j/S4JSpace.java @@ -99,8 +99,9 @@ public class S4JSpace implements AutoCloseable { // Keep track the transaction count per thread private final ThreadLocal txnBatchTrackingCnt = ThreadLocal.withInitial(() -> 0); - // Represents the JMS connection - private PulsarConnectionFactory s4jConnFactory; + // Instead of using one "physical" connection per NB process, + // allows creating multiple connections to the Pulsar broker via the "num_conn" parameter + private final ConcurrentHashMap connFactories = new ConcurrentHashMap<>(); private long totalCycleNum; @@ -125,6 +126,7 @@ public class S4JSpace implements AutoCloseable { this.sessionMode = S4JAdapterUtil.getSessionModeFromStr( cfg.getOptional("session_mode").orElse("")); this.s4JClientConf = new S4JClientConf(webSvcUrl, pulsarSvcUrl, s4jClientConfFileName); + logger.info("{}", s4JClientConf.toString()); this.setS4JActivityStartTimeMills(System.currentTimeMillis()); @@ -217,45 +219,41 @@ public class S4JSpace implements AutoCloseable { public long incTotalNullMsgRecvdCnt() { return nullMsgRecvCnt.incrementAndGet(); } - public PulsarConnectionFactory getS4jConnFactory() { return s4jConnFactory; } - public long getTotalCycleNum() { return totalCycleNum; } public void setTotalCycleNum(long cycleNum) { totalCycleNum = cycleNum; } public void initializeSpace(S4JClientConf s4JClientConnInfo) { - if (s4jConnFactory == null) { - Map cfgMap; - try { - cfgMap = s4JClientConnInfo.getS4jConfObjMap(); - s4jConnFactory = new PulsarConnectionFactory(cfgMap); + Map cfgMap; + try { + cfgMap = s4JClientConnInfo.getS4jConfObjMap(); - for (int i=0; i { - if (logger.isDebugEnabled()) { - logger.error("onException::Unexpected JMS error happened:" + e); - } - }); + // Establish a JMS connection + PulsarConnectionFactory s4jConnFactory = connFactories.computeIfAbsent( + connLvlJmsConnContextIdStr, + __ -> new PulsarConnectionFactory(cfgMap)); - connLvlJmsContexts.put(connLvlJmsConnContextIdStr, jmsConnContext); + JMSContext jmsConnContext = getOrCreateConnLvlJMSContext(s4jConnFactory, s4JClientConnInfo, sessionMode); + jmsConnContext.setClientID(connLvlJmsConnContextIdStr); + jmsConnContext.setExceptionListener(e -> { if (logger.isDebugEnabled()) { - logger.debug("[Connection level JMSContext] {} -- {}", - Thread.currentThread().getName(), - jmsConnContext ); + logger.error("onException::Unexpected JMS error happened:" + e); } + }); + + connLvlJmsContexts.put(connLvlJmsConnContextIdStr, jmsConnContext); + if (logger.isDebugEnabled()) { + logger.debug("[Connection level JMSContext] {} -- {}", + Thread.currentThread().getName(), + jmsConnContext ); } } - catch (JMSRuntimeException e) { - logger.error("Unable to initialize JMS connection factory with the following configuration parameters: {}", s4JClientConnInfo.toString()); - throw new S4JAdapterUnexpectedException("Unable to initialize JMS connection factory with the following error message: " + e.getCause()); - } - catch (Exception e) { - e.printStackTrace(); - } + } + catch (JMSRuntimeException e) { + logger.error("Unable to initialize JMS connection factory with the following configuration parameters: {}", s4JClientConnInfo.toString()); + throw new S4JAdapterUnexpectedException("Unable to initialize JMS connection factory with the following error message: " + e.getCause()); } } @@ -284,7 +282,9 @@ public class S4JSpace implements AutoCloseable { if (jmsContext != null) jmsContext.close(); } - s4jConnFactory.close(); + for (PulsarConnectionFactory s4jConnFactory : connFactories.values()) { + if (s4jConnFactory != null) s4jConnFactory.close(); + } } catch (Exception ex) { String exp = "Unexpected error when shutting down the S4J adaptor space"; diff --git a/nb-adapters/adapter-s4j/src/main/java/io/nosqlbench/adapter/s4j/dispensers/MessageProducerOpDispenser.java b/nb-adapters/adapter-s4j/src/main/java/io/nosqlbench/adapter/s4j/dispensers/MessageProducerOpDispenser.java index 584ebca04..2dac6c52f 100644 --- a/nb-adapters/adapter-s4j/src/main/java/io/nosqlbench/adapter/s4j/dispensers/MessageProducerOpDispenser.java +++ b/nb-adapters/adapter-s4j/src/main/java/io/nosqlbench/adapter/s4j/dispensers/MessageProducerOpDispenser.java @@ -40,11 +40,13 @@ public class MessageProducerOpDispenser extends S4JBaseOpDispenser { private final static Logger logger = LogManager.getLogger("MessageProducerOpDispenser"); public static final String MSG_HEADER_OP_PARAM = "msg_header"; + public static final String MSG_PRIORITY_OP_PARAM = "msg_priority"; public static final String MSG_PROP_OP_PARAM = "msg_property"; public static final String MSG_BODY_OP_PARAM = "msg_body"; public static final String MSG_TYPE_OP_PARAM = "msg_type"; private final LongFunction msgHeaderRawJsonStrFunc; + private final LongFunction msgPriorityStrFunc; private final LongFunction msgPropRawJsonStrFunc; private final LongFunction msgBodyRawJsonStrFunc; private final LongFunction msgTypeFunc; @@ -56,6 +58,7 @@ public class MessageProducerOpDispenser extends S4JBaseOpDispenser { super(adapter, op, tgtNameFunc, s4jSpace); this.msgHeaderRawJsonStrFunc = lookupOptionalStrOpValueFunc(MSG_HEADER_OP_PARAM); + this.msgPriorityStrFunc = lookupOptionalStrOpValueFunc(MSG_PRIORITY_OP_PARAM); this.msgPropRawJsonStrFunc = lookupOptionalStrOpValueFunc(MSG_PROP_OP_PARAM); this.msgBodyRawJsonStrFunc = lookupMandtoryStrOpValueFunc(MSG_BODY_OP_PARAM); this.msgTypeFunc = lookupOptionalStrOpValueFunc(MSG_TYPE_OP_PARAM); @@ -272,6 +275,7 @@ public class MessageProducerOpDispenser extends S4JBaseOpDispenser { public MessageProducerOp getOp(long cycle) { String destName = destNameStrFunc.apply(cycle); String jmsMsgHeaderRawJsonStr = msgHeaderRawJsonStrFunc.apply(cycle); + String jmsMsgPriorityStr = msgPriorityStrFunc.apply(cycle); String jmsMsgPropertyRawJsonStr = msgPropRawJsonStrFunc.apply(cycle); String jmsMsgBodyRawJsonStr = msgBodyRawJsonStrFunc.apply(cycle); @@ -294,6 +298,9 @@ public class MessageProducerOpDispenser extends S4JBaseOpDispenser { JMSProducer producer; try { producer = getJmsProducer(s4JJMSContextWrapper, asyncAPI); + int priority = NumberUtils.toInt(jmsMsgPriorityStr); + assert (priority >= 0 && priority <= 9); + producer.setPriority(priority); } catch (JMSException jmsException) { throw new S4JAdapterUnexpectedException("Unable to create the JMS producer!"); diff --git a/nb-adapters/adapter-s4j/src/main/java/io/nosqlbench/adapter/s4j/dispensers/S4JBaseOpDispenser.java b/nb-adapters/adapter-s4j/src/main/java/io/nosqlbench/adapter/s4j/dispensers/S4JBaseOpDispenser.java index 5150fe329..d1e1176e6 100644 --- a/nb-adapters/adapter-s4j/src/main/java/io/nosqlbench/adapter/s4j/dispensers/S4JBaseOpDispenser.java +++ b/nb-adapters/adapter-s4j/src/main/java/io/nosqlbench/adapter/s4j/dispensers/S4JBaseOpDispenser.java @@ -225,7 +225,7 @@ public abstract class S4JBaseOpDispenser extends BaseOpDispenser LABELS = Stream.of(values()).map(v -> v.label) + .collect(Collectors.toUnmodifiableSet()); + private static boolean isValidLabel(String label) { + return LABELS.contains(StringUtils.upperCase(label)); + } + } + public static String getValidMsgCompressionTypeList() { + return StringUtils.join(MSG_COMPRESSION_TYPE_STR.LABELS, ", "); + } + public static boolean isValidMsgCompressionTypeStr(String type) { + return MSG_COMPRESSION_TYPE_STR.isValidLabel(type); + } + /////// // Convert JSON string to a key/value map public static Map convertJsonToMap(String jsonStr) throws Exception { diff --git a/nb-adapters/adapter-s4j/src/main/java/io/nosqlbench/adapter/s4j/util/S4JClientConfConverter.java b/nb-adapters/adapter-s4j/src/main/java/io/nosqlbench/adapter/s4j/util/S4JClientConfConverter.java index 9ba86bfb3..f9908c527 100644 --- a/nb-adapters/adapter-s4j/src/main/java/io/nosqlbench/adapter/s4j/util/S4JClientConfConverter.java +++ b/nb-adapters/adapter-s4j/src/main/java/io/nosqlbench/adapter/s4j/util/S4JClientConfConverter.java @@ -22,6 +22,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; import io.nosqlbench.adapter.s4j.exception.S4JAdapterInvalidParamException; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.math.NumberUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import java.util.ArrayList; import java.util.HashMap; @@ -35,6 +37,8 @@ import java.util.Map; */ public class S4JClientConfConverter { + private final static Logger logger = LogManager.getLogger(S4JClientConfConverter.class); + public static Map convertRawClientConf(Map pulsarClientConfMapRaw) { Map s4jClientConfObjMap = new HashMap<>(); s4jClientConfObjMap.putAll(pulsarClientConfMapRaw); @@ -71,34 +75,31 @@ public class S4JClientConfConverter { /** * Non-primitive type processing for Pulsar producer configuration items */ - // "compressionType" has value type "CompressionType" - // - expecting the following values: 'LZ4', 'ZLIB', 'ZSTD', 'SNAPPY' String confKeyName = "compressionType"; String confVal = pulsarProducerConfMapRaw.get(confKeyName); - String expectedVal = "(LZ4|ZLIB|ZSTD|SNAPPY)"; - if (StringUtils.isNotBlank(confVal)) { - if (StringUtils.equalsAnyIgnoreCase(confVal, "LZ4", "ZLIB", "ZSTD", "SNAPPY")) { - CompressionType compressionType = CompressionType.NONE; - - switch (StringUtils.upperCase(confVal)) { - case "LZ4": - compressionType = CompressionType.LZ4; - case "ZLIB": - compressionType = CompressionType.ZLIB; - case "ZSTD": - compressionType = CompressionType.ZSTD; - case "SNAPPY": - compressionType = CompressionType.SNAPPY; - } - - s4jProducerConfObjMap.put(confKeyName, compressionType); - } else { - throw new S4JAdapterInvalidParamException( - getInvalidConfValStr(confKeyName, confVal, "producer", expectedVal)); + CompressionType compressionType = CompressionType.NONE; + if ( StringUtils.isNotBlank(confVal) ) { + try { + S4JAdapterUtil.MSG_COMPRESSION_TYPE_STR compressionTypeStr = + S4JAdapterUtil.MSG_COMPRESSION_TYPE_STR.valueOf(confVal); + compressionType = switch (compressionTypeStr) { + case LZ4 -> CompressionType.LZ4; + case ZLIB -> CompressionType.ZLIB; + case ZSTD -> CompressionType.ZSTD; + case SNAPPY -> CompressionType.SNAPPY; + }; + } catch (IllegalArgumentException e) { + // Any invalid value will be treated as no compression + logger.warn("Invalid producer \"compressionType\" value ({}) in the config properties file. " + + "Expecting one of the following values: {}. " + + "No message compression will be applied (for producers).", + confVal, + S4JAdapterUtil.getValidMsgCompressionTypeList()); } } + s4jProducerConfObjMap.put(confKeyName, compressionType); // TODO: Skip the following Pulsar configuration items for now because they're not really // needed in the NB S4J testing at the moment. Add support for them when needed. // * messageRoutingMode @@ -312,7 +313,9 @@ public class S4JClientConfConverter { Map.entry("jms.usePulsarAdmin","boolean"), Map.entry("jms.useServerSideFiltering","boolean"), Map.entry("jms.waitForServerStartupTimeout","int"), - Map.entry("jms.transactionsStickyPartitions", "boolean") + Map.entry("jms.transactionsStickyPartitions", "boolean"), + Map.entry("jms.enableJMSPriority","boolean"), + Map.entry("jms.priorityMapping","String") ); public static Map convertRawJmsConf(Map s4jJmsConfMapRaw) { Map s4jJmsConfObjMap = new HashMap<>(); diff --git a/nb-adapters/adapter-s4j/src/main/java/io/nosqlbench/adapter/s4j/util/S4JJMSContextWrapper.java b/nb-adapters/adapter-s4j/src/main/java/io/nosqlbench/adapter/s4j/util/S4JJMSContextWrapper.java index f22b6d78b..7219dce3b 100644 --- a/nb-adapters/adapter-s4j/src/main/java/io/nosqlbench/adapter/s4j/util/S4JJMSContextWrapper.java +++ b/nb-adapters/adapter-s4j/src/main/java/io/nosqlbench/adapter/s4j/util/S4JJMSContextWrapper.java @@ -22,19 +22,19 @@ import javax.jms.Session; * under the License. */ public class S4JJMSContextWrapper { - private final String jmsContextIdentifer; + private final String jmsContextIdentifier; private final JMSContext jmsContext; private final int jmsSessionMode; public S4JJMSContextWrapper(String identifer, JMSContext jmsContext) { - this.jmsContextIdentifer = identifer; + this.jmsContextIdentifier = identifer; this.jmsContext = jmsContext; this.jmsSessionMode = jmsContext.getSessionMode(); } public int getJmsSessionMode() { return jmsSessionMode; } public boolean isTransactedMode() { return Session.SESSION_TRANSACTED == this.getJmsSessionMode(); } - public String getJmsContextIdentifer() { return jmsContextIdentifer; } + public String getJmsContextIdentifier() { return jmsContextIdentifier; } public JMSContext getJmsContext() { return jmsContext; } public void close() { @@ -45,7 +45,7 @@ public class S4JJMSContextWrapper { public String toString() { return new ToStringBuilder(this). - append("jmsContextIdentifer", jmsContextIdentifer). + append("jmsContextIdentifier", jmsContextIdentifier). append("jmsContext", jmsContext.toString()). toString(); } diff --git a/nb-adapters/adapter-s4j/src/main/resources/scenarios/pulsar_s4j_producer.yaml b/nb-adapters/adapter-s4j/src/main/resources/scenarios/pulsar_s4j_producer.yaml index 260192c69..b9c37eb1a 100644 --- a/nb-adapters/adapter-s4j/src/main/resources/scenarios/pulsar_s4j_producer.yaml +++ b/nb-adapters/adapter-s4j/src/main/resources/scenarios/pulsar_s4j_producer.yaml @@ -5,6 +5,7 @@ bindings: mymap_val1: AlphaNumericString(10) mymap_val2: AlphaNumericString(20) mystream_val1: AlphaNumericString(50) + my_priority: WeightedLongs('2:20;4:70;8:10') # document level parameters that apply to all Pulsar client types: params: @@ -25,6 +26,12 @@ blocks: "JMSPriority": "9" } + ## (Optional) S4J Message priority emulation (since Pulsar doesn't have native message priority) + # - jms.enableJMSPriority must be set to true in S4J configuration; + # otherwise, the priority value will be ignored. + # - If this is set, the "JMSPriority" value in the header will be ignored. + msg_priority: "{my_priority}" + ## (Optional) JMS properties, predefined or customized (in JSON format). msg_property: | { diff --git a/nb-apis/nb-api/src/main/java/io/nosqlbench/nb/api/engine/activityimpl/CyclesSpec.java b/nb-apis/nb-api/src/main/java/io/nosqlbench/nb/api/engine/activityimpl/CyclesSpec.java index 3c03c561f..595232ef7 100644 --- a/nb-apis/nb-api/src/main/java/io/nosqlbench/nb/api/engine/activityimpl/CyclesSpec.java +++ b/nb-apis/nb-api/src/main/java/io/nosqlbench/nb/api/engine/activityimpl/CyclesSpec.java @@ -22,7 +22,12 @@ import org.apache.logging.log4j.Logger; import java.security.InvalidParameterException; -public record CyclesSpec(long first_inclusive, long last_exclusive, String firstSpec, String lastSpec) { +public record CyclesSpec( + long first_inclusive, + long last_exclusive, + String firstSpec, + String lastSpec +) { private final static Logger logger = LogManager.getLogger(CyclesSpec.class); public CyclesSpec { if (first_inclusive>last_exclusive) { @@ -32,16 +37,24 @@ public record CyclesSpec(long first_inclusive, long last_exclusive, String first public static CyclesSpec parse(String spec) { int rangeAt = spec.indexOf(".."); - String beginningInclusive = "0"; - String endingExclusive = spec; + String beginningSpec = "0"; + String endingSpec = spec; if (0 < rangeAt) { - beginningInclusive = spec.substring(0, rangeAt); - endingExclusive = spec.substring(rangeAt+2); + beginningSpec = spec.substring(0, rangeAt); + endingSpec = spec.substring(rangeAt+2); + } + long first = Unit.longCountFor(beginningSpec).orElseThrow(() -> new RuntimeException("Unable to parse start cycles from " + spec)); + long last=first; + if (endingSpec.startsWith("+")) { + long added=Unit.longCountFor(endingSpec.substring(1)).orElseThrow(() -> new RuntimeException( + "Unable to parse incremental cycle interval. Use one of these forms: 100 or 0..100 or 0..+100" + )); + last = first+added; + } else { + last = Unit.longCountFor(endingSpec).orElseThrow(() -> new RuntimeException("Unable to parse start cycles from " + spec)); } - long first = Unit.longCountFor(beginningInclusive).orElseThrow(() -> new RuntimeException("Unable to parse start cycles from " + spec)); - long last = Unit.longCountFor(endingExclusive).orElseThrow(() -> new RuntimeException("Unable to parse start cycles from " + spec)); - return new CyclesSpec(first, last, beginningInclusive, endingExclusive); + return new CyclesSpec(first, last, beginningSpec, endingSpec); } public String summary() { @@ -74,4 +87,30 @@ public record CyclesSpec(long first_inclusive, long last_exclusive, String first public long cycle_count() { return last_exclusive -first_inclusive; } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (!(o instanceof CyclesSpec that)) + return false; + if (last_exclusive!=that.last_exclusive) + return false; + if (first_inclusive!=that.first_inclusive) + return false; + if (!firstSpec.equals(that.firstSpec)) + return false; + if (!lastSpec.equals(that.lastSpec)) + return false; + return true; + } + + @Override + public int hashCode() { + int result = Long.hashCode(first_inclusive); + result = 31 * result + Long.hashCode(last_exclusive); + result = 31 * result + firstSpec.hashCode(); + result = 31 * result + lastSpec.hashCode(); + return result; + } } diff --git a/nb-apis/nb-api/src/test/java/io/nosqlbench/nb/api/engine/activityimpl/CyclesSpecTest.java b/nb-apis/nb-api/src/test/java/io/nosqlbench/nb/api/engine/activityimpl/CyclesSpecTest.java new file mode 100644 index 000000000..e5ffbdd3f --- /dev/null +++ b/nb-apis/nb-api/src/test/java/io/nosqlbench/nb/api/engine/activityimpl/CyclesSpecTest.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2024 nosqlbench + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.nosqlbench.nb.api.engine.activityimpl; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; + +public class CyclesSpecTest { + + @Test + public void testSingleNumberSpec() { + assertThat(CyclesSpec.parse("100")).isEqualTo( + new CyclesSpec(0,100,"0","100") + ); + } + + @Test + public void testIntervalSpec() { + assertThat(CyclesSpec.parse("3..13")).isEqualTo( + new CyclesSpec(3,13,"3","13") + ); + } + + @Test + public void testUnitsSupport() { + assertThat(CyclesSpec.parse("5M")).isEqualTo( + new CyclesSpec(0,5_000_000L,"0","5M") + ); + } + + @Test + public void testIncrementalSupport() { + assertThat(CyclesSpec.parse("5M..+100")).isEqualTo( + new CyclesSpec(5_000_000L,5_000_100L,"5M","+100") + ); + } + + @Test + public void testIncrementalUnitsSupport() { + assertThat(CyclesSpec.parse("5M..+1M")).isEqualTo( + new CyclesSpec(5_000_000L,6_000_000L,"5M","+1M") + ); + } +}