diff --git a/nb-adapters/adapter-gcp-spanner/src/main/java/io/nosqlbench/adapter/gcpspanner/GCPSpannerAdapterUtils.java b/nb-adapters/adapter-gcp-spanner/src/main/java/io/nosqlbench/adapter/gcpspanner/GCPSpannerAdapterUtils.java index 1fc2bad27..55cf996d4 100644 --- a/nb-adapters/adapter-gcp-spanner/src/main/java/io/nosqlbench/adapter/gcpspanner/GCPSpannerAdapterUtils.java +++ b/nb-adapters/adapter-gcp-spanner/src/main/java/io/nosqlbench/adapter/gcpspanner/GCPSpannerAdapterUtils.java @@ -16,6 +16,12 @@ package io.nosqlbench.adapter.gcpspanner; +import com.google.cloud.spanner.ResultSet; + public class GCPSpannerAdapterUtils { public static final String SPANNER = "gcp_spanner"; + + public static int[] getKeyArrayFromResultSet(ResultSet rs) { + return rs.getLongList(0).stream().mapToInt(Math::toIntExact).toArray(); + } } diff --git a/nb-adapters/adapter-gcp-spanner/src/main/java/io/nosqlbench/adapter/gcpspanner/GCPSpannerOpMapper.java b/nb-adapters/adapter-gcp-spanner/src/main/java/io/nosqlbench/adapter/gcpspanner/GCPSpannerOpMapper.java index c2071da3b..f066ee4cc 100644 --- a/nb-adapters/adapter-gcp-spanner/src/main/java/io/nosqlbench/adapter/gcpspanner/GCPSpannerOpMapper.java +++ b/nb-adapters/adapter-gcp-spanner/src/main/java/io/nosqlbench/adapter/gcpspanner/GCPSpannerOpMapper.java @@ -55,10 +55,12 @@ public class GCPSpannerOpMapper implements OpMapper> { logger.info(() -> "Using '" + typeAndTarget.enumId + "' op type for op template '" + op.getName() + "'"); return switch (typeAndTarget.enumId) { - case create_table -> - new GCPSpannerCreateTableOpDispenser(adapter, op, typeAndTarget.targetFunction); + case update_database_ddl -> + new GCPSpannerUpdateDatabaseDdlOpDispenser(adapter, op, typeAndTarget.targetFunction); case insert_vector -> new GCPSpannerInsertVectorOpDispenser(adapter, op, typeAndTarget.targetFunction); + case execute_dml -> + new GCPSpannerExecuteDmlOpDispenser(adapter, op, typeAndTarget.targetFunction); }; } } diff --git a/nb-adapters/adapter-gcp-spanner/src/main/java/io/nosqlbench/adapter/gcpspanner/GCPSpannerSpace.java b/nb-adapters/adapter-gcp-spanner/src/main/java/io/nosqlbench/adapter/gcpspanner/GCPSpannerSpace.java index abdb6a3e4..13f7feabf 100644 --- a/nb-adapters/adapter-gcp-spanner/src/main/java/io/nosqlbench/adapter/gcpspanner/GCPSpannerSpace.java +++ b/nb-adapters/adapter-gcp-spanner/src/main/java/io/nosqlbench/adapter/gcpspanner/GCPSpannerSpace.java @@ -113,7 +113,7 @@ public class GCPSpannerSpace implements AutoCloseable { .asReadOnly(); } @Override - public void close() throws Exception { + public void close() { if (spanner != null) { spanner.close(); } diff --git a/nb-adapters/adapter-gcp-spanner/src/main/java/io/nosqlbench/adapter/gcpspanner/opdispensers/GCPSpannerExecuteDmlOpDispenser.java b/nb-adapters/adapter-gcp-spanner/src/main/java/io/nosqlbench/adapter/gcpspanner/opdispensers/GCPSpannerExecuteDmlOpDispenser.java new file mode 100644 index 000000000..7e567da70 --- /dev/null +++ b/nb-adapters/adapter-gcp-spanner/src/main/java/io/nosqlbench/adapter/gcpspanner/opdispensers/GCPSpannerExecuteDmlOpDispenser.java @@ -0,0 +1,57 @@ +/* + * 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.gcpspanner.opdispensers; + +import com.google.cloud.spanner.Statement; +import io.nosqlbench.adapter.gcpspanner.GCPSpannerDriverAdapter; +import io.nosqlbench.adapter.gcpspanner.ops.GCPSpannerBaseOp; +import io.nosqlbench.adapter.gcpspanner.ops.GCPSpannerExecuteDmlOp; +import io.nosqlbench.adapters.api.templating.ParsedOp; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.function.LongFunction; + +public class GCPSpannerExecuteDmlOpDispenser extends GCPSpannerBaseOpDispenser { + private static final Logger logger = LogManager.getLogger(GCPSpannerExecuteDmlOpDispenser.class); + private final LongFunction opFunction; + + public GCPSpannerExecuteDmlOpDispenser(GCPSpannerDriverAdapter adapter, ParsedOp op, LongFunction targetFunction) { + super(adapter, op, targetFunction); + this.opFunction = createOpFunction(op); + } + + private LongFunction createOpFunction(ParsedOp op) { + + return (l) -> new GCPSpannerExecuteDmlOp( + spaceFunction.apply(l).getSpanner(), + l, + generateStatement(op.getAsRequiredFunction("DML", String.class).apply(l)), + spaceFunction.apply(l).getDbClient() + ); + } + + private Statement generateStatement(String dml) { + return Statement.of(dml); + } + + @Override + public GCPSpannerBaseOp getOp(long value) { + return opFunction.apply(value); + } +} diff --git a/nb-adapters/adapter-gcp-spanner/src/main/java/io/nosqlbench/adapter/gcpspanner/opdispensers/GCPSpannerCreateTableOpDispenser.java b/nb-adapters/adapter-gcp-spanner/src/main/java/io/nosqlbench/adapter/gcpspanner/opdispensers/GCPSpannerUpdateDatabaseDdlOpDispenser.java similarity index 70% rename from nb-adapters/adapter-gcp-spanner/src/main/java/io/nosqlbench/adapter/gcpspanner/opdispensers/GCPSpannerCreateTableOpDispenser.java rename to nb-adapters/adapter-gcp-spanner/src/main/java/io/nosqlbench/adapter/gcpspanner/opdispensers/GCPSpannerUpdateDatabaseDdlOpDispenser.java index 56cdc4692..c3224db1d 100644 --- a/nb-adapters/adapter-gcp-spanner/src/main/java/io/nosqlbench/adapter/gcpspanner/opdispensers/GCPSpannerCreateTableOpDispenser.java +++ b/nb-adapters/adapter-gcp-spanner/src/main/java/io/nosqlbench/adapter/gcpspanner/opdispensers/GCPSpannerUpdateDatabaseDdlOpDispenser.java @@ -17,30 +17,27 @@ package io.nosqlbench.adapter.gcpspanner.opdispensers; -import com.google.cloud.spanner.Database; -import com.google.cloud.spanner.DatabaseAdminClient; import io.nosqlbench.adapter.gcpspanner.GCPSpannerDriverAdapter; -import io.nosqlbench.adapter.gcpspanner.GCPSpannerSpace; import io.nosqlbench.adapter.gcpspanner.ops.GCPSpannerBaseOp; -import io.nosqlbench.adapter.gcpspanner.ops.GCPSpannerCreateTableOp; +import io.nosqlbench.adapter.gcpspanner.ops.GCPSpannerUpdateDatabaseDdlOp; import io.nosqlbench.adapters.api.templating.ParsedOp; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.util.function.LongFunction; -public class GCPSpannerCreateTableOpDispenser extends GCPSpannerBaseOpDispenser { - private static final Logger logger = LogManager.getLogger(GCPSpannerCreateTableOpDispenser.class); - private final LongFunction opFunction; +public class GCPSpannerUpdateDatabaseDdlOpDispenser extends GCPSpannerBaseOpDispenser { + private static final Logger logger = LogManager.getLogger(GCPSpannerUpdateDatabaseDdlOpDispenser.class); + private final LongFunction opFunction; - public GCPSpannerCreateTableOpDispenser(GCPSpannerDriverAdapter adapter, ParsedOp op, LongFunction targetFunction) { + public GCPSpannerUpdateDatabaseDdlOpDispenser(GCPSpannerDriverAdapter adapter, ParsedOp op, LongFunction targetFunction) { super(adapter, op, targetFunction); this.opFunction = createOpFunction(op); } - private LongFunction createOpFunction(ParsedOp op) { + private LongFunction createOpFunction(ParsedOp op) { - return (l) -> new GCPSpannerCreateTableOp( + return (l) -> new GCPSpannerUpdateDatabaseDdlOp( spaceFunction.apply(l).getSpanner(), l, op.getAsRequiredFunction("DDL", String.class).apply(l), diff --git a/nb-adapters/adapter-gcp-spanner/src/main/java/io/nosqlbench/adapter/gcpspanner/ops/GCPSpannerBaseOp.java b/nb-adapters/adapter-gcp-spanner/src/main/java/io/nosqlbench/adapter/gcpspanner/ops/GCPSpannerBaseOp.java index eb6b42b0e..4565630b9 100644 --- a/nb-adapters/adapter-gcp-spanner/src/main/java/io/nosqlbench/adapter/gcpspanner/ops/GCPSpannerBaseOp.java +++ b/nb-adapters/adapter-gcp-spanner/src/main/java/io/nosqlbench/adapter/gcpspanner/ops/GCPSpannerBaseOp.java @@ -37,12 +37,6 @@ public abstract class GCPSpannerBaseOp implements CycleOp { this.apiCall = this::applyOp; } - public GCPSpannerBaseOp(Spanner spanner, T requestParam, LongFunction call) { - this.spannerClient = spanner; - this.request = requestParam; - this.apiCall = call; - } - @Override public final Object apply(long value) { logger.trace(() -> "applying op: " + this); diff --git a/nb-adapters/adapter-gcp-spanner/src/main/java/io/nosqlbench/adapter/gcpspanner/ops/GCPSpannerExecuteDmlOp.java b/nb-adapters/adapter-gcp-spanner/src/main/java/io/nosqlbench/adapter/gcpspanner/ops/GCPSpannerExecuteDmlOp.java new file mode 100644 index 000000000..992bc95d7 --- /dev/null +++ b/nb-adapters/adapter-gcp-spanner/src/main/java/io/nosqlbench/adapter/gcpspanner/ops/GCPSpannerExecuteDmlOp.java @@ -0,0 +1,39 @@ +/* + * 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.gcpspanner.ops; + +import com.google.cloud.spanner.*; + +public class GCPSpannerExecuteDmlOp extends GCPSpannerBaseOp { + private final Statement statement; + private final DatabaseClient dbClient; + + public GCPSpannerExecuteDmlOp(Spanner spanner, Long requestParam, Statement statement, + DatabaseClient dbClient) { + super(spanner, requestParam); + this.statement = statement; + this.dbClient = dbClient; + } + + @Override + public Object applyOp(long value) { + try (ReadContext context = dbClient.singleUse()) { + return context.executeQuery(statement); + } + } +} diff --git a/nb-adapters/adapter-gcp-spanner/src/main/java/io/nosqlbench/adapter/gcpspanner/ops/GCPSpannerInsertVectorOp.java b/nb-adapters/adapter-gcp-spanner/src/main/java/io/nosqlbench/adapter/gcpspanner/ops/GCPSpannerInsertVectorOp.java index 666035b10..a39c58454 100644 --- a/nb-adapters/adapter-gcp-spanner/src/main/java/io/nosqlbench/adapter/gcpspanner/ops/GCPSpannerInsertVectorOp.java +++ b/nb-adapters/adapter-gcp-spanner/src/main/java/io/nosqlbench/adapter/gcpspanner/ops/GCPSpannerInsertVectorOp.java @@ -21,7 +21,6 @@ import com.google.cloud.spanner.Spanner; import com.google.cloud.spanner.DatabaseClient; import com.google.cloud.spanner.Mutation; -import java.util.Arrays; import java.util.Collections; public class GCPSpannerInsertVectorOp extends GCPSpannerBaseOp { diff --git a/nb-adapters/adapter-gcp-spanner/src/main/java/io/nosqlbench/adapter/gcpspanner/ops/GCPSpannerCreateTableOp.java b/nb-adapters/adapter-gcp-spanner/src/main/java/io/nosqlbench/adapter/gcpspanner/ops/GCPSpannerUpdateDatabaseDdlOp.java similarity index 84% rename from nb-adapters/adapter-gcp-spanner/src/main/java/io/nosqlbench/adapter/gcpspanner/ops/GCPSpannerCreateTableOp.java rename to nb-adapters/adapter-gcp-spanner/src/main/java/io/nosqlbench/adapter/gcpspanner/ops/GCPSpannerUpdateDatabaseDdlOp.java index 166bd754b..a0903bc6b 100644 --- a/nb-adapters/adapter-gcp-spanner/src/main/java/io/nosqlbench/adapter/gcpspanner/ops/GCPSpannerCreateTableOp.java +++ b/nb-adapters/adapter-gcp-spanner/src/main/java/io/nosqlbench/adapter/gcpspanner/ops/GCPSpannerUpdateDatabaseDdlOp.java @@ -22,13 +22,13 @@ import com.google.cloud.spanner.*; import com.google.common.collect.ImmutableList; import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata; -public class GCPSpannerCreateTableOp extends GCPSpannerBaseOp { +public class GCPSpannerUpdateDatabaseDdlOp extends GCPSpannerBaseOp { private final String createTableStatement; private final DatabaseAdminClient dbAdminClient; private final Database db; - public GCPSpannerCreateTableOp(Spanner searchIndexClient, Long requestParam, String createTableStatement, - DatabaseAdminClient dbAdminClient, Database db) { + public GCPSpannerUpdateDatabaseDdlOp(Spanner searchIndexClient, Long requestParam, String createTableStatement, + DatabaseAdminClient dbAdminClient, Database db) { super(searchIndexClient, requestParam); this.createTableStatement = createTableStatement; this.dbAdminClient = dbAdminClient; diff --git a/nb-adapters/adapter-gcp-spanner/src/main/java/io/nosqlbench/adapter/gcpspanner/types/GCPSpannerOpType.java b/nb-adapters/adapter-gcp-spanner/src/main/java/io/nosqlbench/adapter/gcpspanner/types/GCPSpannerOpType.java index e5ee95281..67477d341 100644 --- a/nb-adapters/adapter-gcp-spanner/src/main/java/io/nosqlbench/adapter/gcpspanner/types/GCPSpannerOpType.java +++ b/nb-adapters/adapter-gcp-spanner/src/main/java/io/nosqlbench/adapter/gcpspanner/types/GCPSpannerOpType.java @@ -17,9 +17,20 @@ package io.nosqlbench.adapter.gcpspanner.types; /** - * https://cloud.google.com/spanner/docs/reference/standard-sql/data-definition-language#vector_index_statements + * All the spanner rpc api calls are defined here, representing a + * guide to the set of operations we should define if we want to implement full Spanner api support. + *

+ * NOTE that the vector search functionality is still in pre-GA and is not available through rpc calls other than simply + * calling ExecuteSql. The SQL functionality related to vector indices is documented + * here + *

+ * KNN and ANN search through Google SQL are documented respectively + * here + * and + * here */ public enum GCPSpannerOpType { - create_table, + update_database_ddl, insert_vector, + execute_dml, }