Search in sources :

Example 1 with HandlerNano

use of org.spf4j.base.HandlerNano in project spf4j by zolyfarkas.

the class JdbcSemaphore method tryAcquire.

@SuppressFBWarnings("UW_UNCOND_WAIT")
@CheckReturnValue
@Override
public boolean tryAcquire(final int nrPermits, final long timeout, final TimeUnit unit) throws InterruptedException {
    if (nrPermits < 1) {
        throw new IllegalArgumentException("You should try to acquire something! not " + nrPermits);
    }
    if (timeout <= 0) {
        throw new IllegalArgumentException("Illegal timeout, please reasonable values, and not: " + timeout);
    }
    synchronized (syncObj) {
        long toNanos = unit.toNanos(timeout);
        long deadlineNanos;
        if (toNanos < 0) {
            deadlineNanos = Long.MAX_VALUE;
        } else {
            deadlineNanos = TimeSource.nanoTime() + toNanos;
            if (deadlineNanos < 0) {
                // Overflow
                deadlineNanos = Long.MAX_VALUE;
            }
        }
        boolean acquired = false;
        final MutableHolder<Boolean> beat = MutableHolder.of(Boolean.FALSE);
        do {
            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;
                            }
                            if (deadlineNanos - TimeSource.nanoTime() > heartBeat.getBeatDurationNanos()) {
                                // do a heartbeat if have time, and if it makes sense.
                                beat.setValue(heartBeat.tryBeat(conn, deadlineNanos));
                            }
                            return acquired;
                        }
                    }
                }, timeout, unit);
            } 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.getTimeoutToDeadlineSeconds(deadlineNanos);
                if (secondsLeft < CLEANUP_TIMEOUT_SECONDS) {
                    Future<Integer> fut = DefaultExecutor.INSTANCE.submit(new Callable<Integer>() {

                        @Override
                        public Integer call() throws Exception {
                            return 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 (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;
    }
}
Also used : SQLException(java.sql.SQLException) Connection(java.sql.Connection) PreparedStatement(java.sql.PreparedStatement) LockRuntimeException(org.spf4j.concurrent.LockRuntimeException) TimeoutException(java.util.concurrent.TimeoutException) SQLIntegrityConstraintViolationException(java.sql.SQLIntegrityConstraintViolationException) SQLException(java.sql.SQLException) ExecutionException(java.util.concurrent.ExecutionException) HandlerNano(org.spf4j.base.HandlerNano) LockRuntimeException(org.spf4j.concurrent.LockRuntimeException) ExecutionException(java.util.concurrent.ExecutionException) TimeoutException(java.util.concurrent.TimeoutException) CheckReturnValue(javax.annotation.CheckReturnValue) SuppressFBWarnings(edu.umd.cs.findbugs.annotations.SuppressFBWarnings)

Example 2 with HandlerNano

use of org.spf4j.base.HandlerNano 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;
    }
}
Also used : SQLException(java.sql.SQLException) Connection(java.sql.Connection) PreparedStatement(java.sql.PreparedStatement) HandlerNano(org.spf4j.base.HandlerNano) LockRuntimeException(org.spf4j.concurrent.LockRuntimeException) SQLTimeoutException(java.sql.SQLTimeoutException) ExecutionException(java.util.concurrent.ExecutionException) SQLTimeoutException(java.sql.SQLTimeoutException) TimeoutException(java.util.concurrent.TimeoutException) CheckReturnValue(javax.annotation.CheckReturnValue) SuppressFBWarnings(edu.umd.cs.findbugs.annotations.SuppressFBWarnings)

Aggregations

SuppressFBWarnings (edu.umd.cs.findbugs.annotations.SuppressFBWarnings)2 Connection (java.sql.Connection)2 PreparedStatement (java.sql.PreparedStatement)2 SQLException (java.sql.SQLException)2 ExecutionException (java.util.concurrent.ExecutionException)2 TimeoutException (java.util.concurrent.TimeoutException)2 CheckReturnValue (javax.annotation.CheckReturnValue)2 HandlerNano (org.spf4j.base.HandlerNano)2 LockRuntimeException (org.spf4j.concurrent.LockRuntimeException)2 SQLIntegrityConstraintViolationException (java.sql.SQLIntegrityConstraintViolationException)1 SQLTimeoutException (java.sql.SQLTimeoutException)1