|
@@ -1,14 +1,12 @@
|
|
package com.techempower;
|
|
package com.techempower;
|
|
|
|
|
|
import java.util.List;
|
|
import java.util.List;
|
|
-import java.util.concurrent.CountDownLatch;
|
|
|
|
import java.util.concurrent.ExecutionException;
|
|
import java.util.concurrent.ExecutionException;
|
|
import java.util.function.BiConsumer;
|
|
import java.util.function.BiConsumer;
|
|
|
|
|
|
import com.typesafe.config.Config;
|
|
import com.typesafe.config.Config;
|
|
import io.jooby.SneakyThrows;
|
|
import io.jooby.SneakyThrows;
|
|
import io.vertx.core.AsyncResult;
|
|
import io.vertx.core.AsyncResult;
|
|
-import io.vertx.core.CompositeFuture;
|
|
|
|
import io.vertx.core.Future;
|
|
import io.vertx.core.Future;
|
|
import io.vertx.core.Handler;
|
|
import io.vertx.core.Handler;
|
|
import io.vertx.core.Vertx;
|
|
import io.vertx.core.Vertx;
|
|
@@ -23,63 +21,103 @@ import io.vertx.sqlclient.Tuple;
|
|
import io.vertx.sqlclient.impl.SqlClientInternal;
|
|
import io.vertx.sqlclient.impl.SqlClientInternal;
|
|
|
|
|
|
public class PgClient {
|
|
public class PgClient {
|
|
|
|
+
|
|
|
|
+ static {
|
|
|
|
+ // Should be all I/O processing for SQL responses
|
|
|
|
+ System.setProperty("vertx.nettyIORatio", "100");
|
|
|
|
+ }
|
|
|
|
+
|
|
private static final String UPDATE_WORLD = "UPDATE world SET randomnumber=$1 WHERE id=$2";
|
|
private static final String UPDATE_WORLD = "UPDATE world SET randomnumber=$1 WHERE id=$2";
|
|
private static final String SELECT_WORLD = "SELECT id, randomnumber from WORLD where id=$1";
|
|
private static final String SELECT_WORLD = "SELECT id, randomnumber from WORLD where id=$1";
|
|
private static final String SELECT_FORTUNE = "SELECT id, message from FORTUNE";
|
|
private static final String SELECT_FORTUNE = "SELECT id, message from FORTUNE";
|
|
- private SqlClientInternal client;
|
|
|
|
- private PreparedQuery<RowSet<Row>> SELECT_WORLD_QUERY;
|
|
|
|
- private PreparedQuery<RowSet<Row>> SELECT_FORTUNE_QUERY;
|
|
|
|
- private PreparedQuery<RowSet<Row>> UPDATE_WORLD_QUERY;
|
|
|
|
|
|
|
|
- public PgClient(Config config) {
|
|
|
|
- try {
|
|
|
|
- Vertx vertx = Vertx.vertx(
|
|
|
|
- new VertxOptions().setPreferNativeTransport(true).setWorkerPoolSize(4));
|
|
|
|
- PgConnectOptions connectOptions = pgPoolOptions(config);
|
|
|
|
-
|
|
|
|
- Future future = PgConnection.connect(vertx, connectOptions)
|
|
|
|
- .flatMap(conn -> {
|
|
|
|
- client = (SqlClientInternal) conn;
|
|
|
|
- Future<PreparedStatement> f1 = conn.prepare(SELECT_WORLD);
|
|
|
|
- Future<PreparedStatement> f2 = conn.prepare(SELECT_FORTUNE);
|
|
|
|
- Future<PreparedStatement> f3 = conn.prepare(UPDATE_WORLD);
|
|
|
|
- f1.onSuccess(ps -> SELECT_WORLD_QUERY = ps.query());
|
|
|
|
- f2.onSuccess(ps -> SELECT_FORTUNE_QUERY = ps.query());
|
|
|
|
- f3.onSuccess(ps -> UPDATE_WORLD_QUERY = ps.query());
|
|
|
|
- return Future.all(f1, f2, f3);
|
|
|
|
- })
|
|
|
|
- .toCompletionStage()
|
|
|
|
- .toCompletableFuture()
|
|
|
|
- .get();
|
|
|
|
- Throwable cause = future.cause();
|
|
|
|
- if (cause != null) {
|
|
|
|
- throw SneakyThrows.propagate(cause);
|
|
|
|
|
|
+ private static class DbConnection {
|
|
|
|
+ private PreparedQuery<RowSet<Row>> SELECT_WORLD_QUERY;
|
|
|
|
+ private PreparedQuery<RowSet<Row>> SELECT_FORTUNE_QUERY;
|
|
|
|
+ private PreparedQuery<RowSet<Row>> UPDATE_WORLD_QUERY;
|
|
|
|
+ private SqlClientInternal connection;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private static class DbConnectionFactory extends ThreadLocal<DbConnection> {
|
|
|
|
+
|
|
|
|
+ private final PgConnectOptions options;
|
|
|
|
+
|
|
|
|
+ public DbConnectionFactory(PgConnectOptions options) {
|
|
|
|
+ this.options = options;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private <T> Handler<AsyncResult<T>> onSuccess(Handler<T> handler) {
|
|
|
|
+ return ar -> {
|
|
|
|
+ if (ar.succeeded()) {
|
|
|
|
+ handler.handle(ar.result());
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override protected DbConnection initialValue() {
|
|
|
|
+ try {
|
|
|
|
+ DbConnection result = new DbConnection();
|
|
|
|
+ Vertx vertx = Vertx.vertx(
|
|
|
|
+ new VertxOptions()
|
|
|
|
+ .setPreferNativeTransport(true)
|
|
|
|
+ .setEventLoopPoolSize(1)
|
|
|
|
+ .setWorkerPoolSize(1)
|
|
|
|
+ .setInternalBlockingPoolSize(1)
|
|
|
|
+ );
|
|
|
|
+ var future = PgConnection.connect(vertx, options)
|
|
|
|
+ .flatMap(conn -> {
|
|
|
|
+ result.connection = (SqlClientInternal) conn;
|
|
|
|
+ Future<PreparedStatement> f1 = conn.prepare(SELECT_WORLD)
|
|
|
|
+ .andThen(onSuccess(ps -> result.SELECT_WORLD_QUERY = ps.query()));
|
|
|
|
+ Future<PreparedStatement> f2 = conn.prepare(SELECT_FORTUNE)
|
|
|
|
+ .andThen(onSuccess(ps -> result.SELECT_FORTUNE_QUERY = ps.query()));
|
|
|
|
+ Future<PreparedStatement> f3 = conn.prepare(UPDATE_WORLD)
|
|
|
|
+ .andThen(onSuccess(ps -> result.UPDATE_WORLD_QUERY = ps.query()));
|
|
|
|
+ return Future.join(f1, f2, f3);
|
|
|
|
+ })
|
|
|
|
+ .toCompletionStage()
|
|
|
|
+ .toCompletableFuture()
|
|
|
|
+ .get();
|
|
|
|
+
|
|
|
|
+ Throwable cause = future.cause();
|
|
|
|
+ if (cause != null) {
|
|
|
|
+ throw SneakyThrows.propagate(cause);
|
|
|
|
+ }
|
|
|
|
+ return result;
|
|
|
|
+ } catch (InterruptedException ex) {
|
|
|
|
+ Thread.currentThread().interrupt();
|
|
|
|
+ throw SneakyThrows.propagate(ex);
|
|
|
|
+ } catch (ExecutionException ex) {
|
|
|
|
+ throw SneakyThrows.propagate(ex.getCause());
|
|
}
|
|
}
|
|
- } catch (InterruptedException | ExecutionException cause) {
|
|
|
|
- throw SneakyThrows.propagate(cause);
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ private final ThreadLocal<DbConnection> sqlClient;
|
|
|
|
+
|
|
|
|
+ public PgClient(Config config) {
|
|
|
|
+ this.sqlClient = new DbConnectionFactory(pgPoolOptions(config));
|
|
|
|
+ }
|
|
|
|
+
|
|
public void selectWorld(Tuple row, Handler<AsyncResult<RowSet<Row>>> handler) {
|
|
public void selectWorld(Tuple row, Handler<AsyncResult<RowSet<Row>>> handler) {
|
|
- SELECT_WORLD_QUERY.execute(row, handler);
|
|
|
|
|
|
+ this.sqlClient.get().SELECT_WORLD_QUERY.execute(row, handler);
|
|
}
|
|
}
|
|
|
|
|
|
- public void selectWorldQuery(int queries,
|
|
|
|
- BiConsumer<Integer, PreparedQuery<RowSet<Row>>> consumer) {
|
|
|
|
- client.group(c -> {
|
|
|
|
|
|
+ public void selectWorlds(int queries, Handler<AsyncResult<RowSet<Row>>> handler) {
|
|
|
|
+ this.sqlClient.get().connection.group(c -> {
|
|
for (int i = 0; i < queries; i++) {
|
|
for (int i = 0; i < queries; i++) {
|
|
- consumer.accept(i, c.preparedQuery(SELECT_WORLD));
|
|
|
|
|
|
+ c.preparedQuery(SELECT_WORLD).execute(Tuple.of(Util.randomWorld()), handler);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
- public PreparedQuery<RowSet<Row>> fortuneQuery() {
|
|
|
|
- return SELECT_FORTUNE_QUERY;
|
|
|
|
|
|
+ public void fortunes(Handler<AsyncResult<RowSet<Row>>> handler) {
|
|
|
|
+ this.sqlClient.get().SELECT_FORTUNE_QUERY.execute(handler);
|
|
}
|
|
}
|
|
|
|
|
|
public void selectWorldForUpdate(int queries,
|
|
public void selectWorldForUpdate(int queries,
|
|
BiConsumer<Integer, PreparedQuery<RowSet<Row>>> consumer) {
|
|
BiConsumer<Integer, PreparedQuery<RowSet<Row>>> consumer) {
|
|
- client.group(c -> {
|
|
|
|
|
|
+ this.sqlClient.get().connection.group(c -> {
|
|
PreparedQuery<RowSet<Row>> statement = c.preparedQuery(SELECT_WORLD);
|
|
PreparedQuery<RowSet<Row>> statement = c.preparedQuery(SELECT_WORLD);
|
|
for (int i = 0; i < queries; i++) {
|
|
for (int i = 0; i < queries; i++) {
|
|
consumer.accept(i, statement);
|
|
consumer.accept(i, statement);
|
|
@@ -88,7 +126,7 @@ public class PgClient {
|
|
}
|
|
}
|
|
|
|
|
|
public void updateWorld(List<Tuple> batch, Handler<AsyncResult<RowSet<Row>>> handler) {
|
|
public void updateWorld(List<Tuple> batch, Handler<AsyncResult<RowSet<Row>>> handler) {
|
|
- UPDATE_WORLD_QUERY.executeBatch(batch, handler);
|
|
|
|
|
|
+ this.sqlClient.get().UPDATE_WORLD_QUERY.executeBatch(batch, handler);
|
|
}
|
|
}
|
|
|
|
|
|
private PgConnectOptions pgPoolOptions(Config config) {
|
|
private PgConnectOptions pgPoolOptions(Config config) {
|