com.coditory.sherlock.sql.rxjava.SqlTableInitializer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of sherlock-sql-rxjava Show documentation
Show all versions of sherlock-sql-rxjava Show documentation
Distributed Lock Library for JVM
The newest version!
package com.coditory.sherlock.sql.rxjava;
import com.coditory.sherlock.SherlockException;
import com.coditory.sherlock.sql.SqlLockQueries;
import io.r2dbc.spi.Connection;
import io.r2dbc.spi.ConnectionFactory;
import io.r2dbc.spi.Result;
import io.r2dbc.spi.Statement;
import io.reactivex.rxjava3.core.Flowable;
import io.reactivex.rxjava3.core.Single;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.atomic.AtomicBoolean;
import static com.coditory.sherlock.Preconditions.expectNonNull;
final class SqlTableInitializer {
private final Logger logger = LoggerFactory.getLogger(getClass());
private final ConnectionFactory connectionFactory;
private final SqlLockQueries sqlQueries;
private final AtomicBoolean initialized = new AtomicBoolean(false);
SqlTableInitializer(ConnectionFactory connectionFactory, SqlLockQueries sqlQueries) {
expectNonNull(connectionFactory, "connectionFactory");
expectNonNull(sqlQueries, "sqlQueries");
this.connectionFactory = connectionFactory;
this.sqlQueries = sqlQueries;
}
Single getInitializedConnection() {
return initialized.compareAndSet(false, true)
? initialize()
: createConnectionWithRetry();
}
private Single initialize() {
return createConnectionWithRetry()
.flatMap(this::createTable)
.flatMap(this::createIndex);
}
private Single createTable(Connection connection) {
Statement createTableStatement = connection.createStatement(sqlQueries.createLocksTable());
return Single.fromPublisher(createTableStatement.execute())
.flatMap(__ -> commit(connection))
.onErrorResumeNext(e -> {
Statement checkTableStatement = connection.createStatement(sqlQueries.checkTableExits());
return Single.fromPublisher(checkTableStatement.execute())
.flatMap(r -> Single.fromPublisher(r.getRowsUpdated()).map(__ -> connection));
})
.onErrorResumeNext(e -> {
initialized.set(false);
return Single.error(new SherlockException("Could not initialize locks table", e));
});
}
private Single createIndex(Connection connection) {
Statement createIndexStatement = connection.createStatement(sqlQueries.createLocksIndex());
return Single.fromPublisher(createIndexStatement.execute())
.flatMap(__ -> commit(connection))
.onErrorResumeNext(e -> {
initialized.set(false);
return Single.error(new SherlockException("Could not initialize locks table index", e));
});
}
private Single createConnectionWithRetry() {
// Retrying connection because of a bug in connection pool
// https://github.com/r2dbc/r2dbc-pool/issues/164
// it seems that retrying connection once solves the issue
return Single.fromPublisher(connectionFactory.create())
.onErrorResumeNext(e -> {
logger.debug("Could ne create connection. Retrying one more time", e);
return Single.fromPublisher(connectionFactory.create());
})
.doOnSuccess(c -> c.setAutoCommit(true));
}
private Single commit(Connection connection) {
return Flowable.fromPublisher(connection.commitTransaction())
.firstElement()
.map(__ -> connection)
.defaultIfEmpty(connection);
}
}