use of java.sql.SQLTimeoutException in project spf4j by zolyfarkas.
the class JdbcSemaphore method tryAcquire.
@SuppressFBWarnings("UW_UNCOND_WAIT")
@CheckReturnValue
@Override
public boolean tryAcquire(final int nrPermits, final long deadlineNanos) throws InterruptedException {
if (nrPermits < 1) {
throw new IllegalArgumentException("You should try to acquire something! not " + nrPermits);
}
synchronized (syncObj) {
boolean acquired = false;
final MutableHolder<Boolean> beat = MutableHolder.of(Boolean.FALSE);
do {
checkClosed();
validate();
try {
acquired = jdbc.transactOnConnection(new HandlerNano<Connection, Boolean, SQLException>() {
@Override
public Boolean handle(final Connection conn, final long deadlineNanos) throws SQLException {
try (PreparedStatement stmt = conn.prepareStatement(acquireSql)) {
stmt.setQueryTimeout(Math.min(JdbcTemplate.getTimeoutToDeadlineSeconds(deadlineNanos), jdbcTimeoutSeconds));
stmt.setInt(1, nrPermits);
stmt.setNString(2, org.spf4j.base.Runtime.PROCESS_ID);
stmt.setNString(3, semName);
stmt.setInt(4, nrPermits);
int rowsUpdated = stmt.executeUpdate();
Boolean acquired;
if (rowsUpdated == 1) {
try (PreparedStatement ostmt = conn.prepareStatement(acquireByOwnerSql)) {
ostmt.setInt(1, nrPermits);
ostmt.setNString(2, org.spf4j.base.Runtime.PROCESS_ID);
ostmt.setNString(3, semName);
ostmt.setQueryTimeout(Math.min(JdbcTemplate.getTimeoutToDeadlineSeconds(deadlineNanos), jdbcTimeoutSeconds));
int nrUpdated = ostmt.executeUpdate();
if (nrUpdated != 1) {
throw new IllegalStateException("Updated " + nrUpdated + " is incorrect for " + ostmt);
}
}
acquired = Boolean.TRUE;
} else {
if (rowsUpdated > 1) {
throw new IllegalStateException("Too many rows updated! when trying to acquire " + nrPermits);
}
acquired = Boolean.FALSE;
}
long currNanoTime = TimeSource.nanoTime();
if (deadlineNanos - currNanoTime > heartBeat.getBeatDurationNanos()) {
// do a heartbeat if have time, and if it makes sense.
beat.setValue(heartBeat.tryBeat(conn, currNanoTime, deadlineNanos));
}
return acquired;
}
}
}, deadlineNanos);
} catch (SQLTimeoutException ex) {
return false;
} catch (SQLException ex) {
throw new LockRuntimeException(ex);
}
if (beat.getValue()) {
// we did a heartbeat as part of the acquisition.
heartBeat.updateLastRunNanos(TimeSource.nanoTime());
}
if (!acquired) {
long secondsLeft = JdbcTemplate.getTimeoutToDeadlineSecondsNoEx(deadlineNanos);
if (secondsLeft < 0) {
return false;
}
if (secondsLeft < CLEANUP_TIMEOUT_SECONDS) {
Future<Integer> fut = DefaultExecutor.INSTANCE.submit(() -> removeDeadHeartBeatAndNotOwnerRows(CLEANUP_TIMEOUT_SECONDS));
try {
fut.get(secondsLeft, TimeUnit.SECONDS);
} catch (TimeoutException ex) {
// removing dead entries did not finish in time, but continues in the background.
break;
} catch (ExecutionException ex) {
throw new LockRuntimeException(ex);
}
} else {
try {
removeDeadHeartBeatAndNotOwnerRows(secondsLeft);
} catch (SQLTimeoutException ex) {
return false;
} catch (SQLException ex) {
throw new LockRuntimeException(ex);
}
}
try {
if (releaseDeadOwnerPermits(nrPermits) <= 0) {
// wait of we did not find anything dead to release.
long wtimeMilis = Math.min(TimeUnit.NANOSECONDS.toMillis(deadlineNanos - TimeSource.nanoTime()), ThreadLocalRandom.current().nextLong(acquirePollMillis));
if (wtimeMilis > 0) {
syncObj.wait(wtimeMilis);
} else {
break;
}
}
} catch (SQLException ex) {
throw new LockRuntimeException(ex);
}
}
} while (!acquired && deadlineNanos > TimeSource.nanoTime());
if (acquired) {
ownedReservations += nrPermits;
}
return acquired;
}
}
Aggregations