package ch.sla.jdbcperflogger.console.net; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.TimeUnit; import org.eclipse.jdt.annotation.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ch.sla.jdbcperflogger.console.db.LogRepositoryUpdate; import ch.sla.jdbcperflogger.console.db.StatementFullyExecutedLog; import ch.sla.jdbcperflogger.model.BatchedNonPreparedStatementsLog; import ch.sla.jdbcperflogger.model.BatchedPreparedStatementsLog; import ch.sla.jdbcperflogger.model.BufferFullLogMessage; import ch.sla.jdbcperflogger.model.ConnectionInfo; import ch.sla.jdbcperflogger.model.LogMessage; import ch.sla.jdbcperflogger.model.ResultSetLog; import ch.sla.jdbcperflogger.model.StatementExecutedLog; import ch.sla.jdbcperflogger.model.StatementLog; import ch.sla.jdbcperflogger.model.TxCompleteLog; class LogPersister extends Thread implements AutoCloseable { final static Logger LOGGER = LoggerFactory.getLogger(LogPersister.class); private volatile boolean disposed = false; protected final LogRepositoryUpdate logRepository; private final BlockingQueue<LogMessage> logs = new ArrayBlockingQueue<>(10000); LogPersister(final LogRepositoryUpdate logRepository) { this.logRepository = logRepository; this.setName("LogPersister"); } void putMessage(final LogMessage msg) { try { logs.put(msg); } catch (final InterruptedException e) { LOGGER.warn("interrupted", e); } } @Override public void close() { disposed = true; try { this.join(); } catch (final InterruptedException e) { LOGGER.error("error while waiting for LogPersister thread to finish", e); } } @Override public void run() { final List<LogMessage> drainedLogs = new ArrayList<>(1000); final List<StatementFullyExecutedLog> statementFullyExecutedLogs = new ArrayList<StatementFullyExecutedLog>( 100); while (!disposed) { @Nullable LogMessage logMessage; try { logMessage = logs.poll(1, TimeUnit.SECONDS); } catch (final InterruptedException e) { LOGGER.warn("interrupted", e); continue; } if (logMessage == null) { continue; } drainedLogs.clear(); drainedLogs.add(logMessage); logs.drainTo(drainedLogs); for (int i = 0; i < drainedLogs.size(); i++) { logMessage = drainedLogs.get(i); if (i < drainedLogs.size() - 2 && logMessage instanceof StatementLog && drainedLogs.get(i + 1) instanceof StatementExecutedLog) { final StatementExecutedLog statementExecutedLog = (StatementExecutedLog) drainedLogs.get(i + 1); ResultSetLog resultSetLog = null; if (drainedLogs.get(i + 2) instanceof ResultSetLog) { resultSetLog = (ResultSetLog) drainedLogs.get(i + 2); } final StatementFullyExecutedLog statementFullyExecutedLog = new StatementFullyExecutedLog( (StatementLog) logMessage, statementExecutedLog, resultSetLog); statementFullyExecutedLogs.add(statementFullyExecutedLog); i += 1 + (resultSetLog != null ? 1 : 0); continue; } if (!statementFullyExecutedLogs.isEmpty()) { logRepository.addStatementFullyExecutedLog(statementFullyExecutedLogs); statementFullyExecutedLogs.clear(); } if (logMessage instanceof ConnectionInfo) { logRepository.addConnection((ConnectionInfo) logMessage); } else if (logMessage instanceof StatementLog) { logRepository.addStatementLog((StatementLog) logMessage); } else if (logMessage instanceof StatementExecutedLog) { logRepository.updateLogAfterExecution((StatementExecutedLog) logMessage); } else if (logMessage instanceof ResultSetLog) { logRepository.updateLogWithResultSetLog((ResultSetLog) logMessage); } else if (logMessage instanceof BatchedNonPreparedStatementsLog) { logRepository.addBatchedNonPreparedStatementsLog((BatchedNonPreparedStatementsLog) logMessage); } else if (logMessage instanceof BatchedPreparedStatementsLog) { logRepository.addBatchedPreparedStatementsLog((BatchedPreparedStatementsLog) logMessage); } else if (logMessage instanceof TxCompleteLog) { logRepository.addTxCompletionLog((TxCompleteLog) logMessage); } else if (logMessage instanceof BufferFullLogMessage) { logRepository.setLastLostMessageTime(((BufferFullLogMessage) logMessage).getTimestamp()); } else { throw new IllegalArgumentException("unexpected log, class=" + logMessage.getClass()); } } if (!statementFullyExecutedLogs.isEmpty()) { logRepository.addStatementFullyExecutedLog(statementFullyExecutedLogs); statementFullyExecutedLogs.clear(); } } } }