Description
AbstractDatabaseManager checks isRunning() on the shutdown path but not on the write path.
After startupInternal() throws, startup() logs the cause and leaves running = false. Then:
write() (line 297) does not check it — keeps accepting events and dereferences state startup never assigned. NPE per event, naming an internal field, burying the one line that named the cause.
shutdown() (line 230) does check it — so shutdownInternal() never runs and whatever startup built is leaked. Returns true anyway.
Affects every subclass whose startup fails: JDBC, JPA, NoSQL. #4242 is the case where the leak prevents JVM exit.
Version: 2.x 04c93c1d33, and main — unchanged in this respect.
Logs
main ERROR CassandraManager Could not perform database startup operations:
InvalidQueryException: Keyspace 'log4j' does not exist
at AbstractDatabaseManager.startup(AbstractDatabaseManager.java:259)
main ERROR Unable to write to database [Cassandra] for appender [Cassandra].
java.lang.NullPointerException: Cannot invoke "PreparedStatement.bind(Object[])"
because "this.preparedStatement" is null <- then this, per event
Suggested fix
write(): return early when !isRunning(), logging once rather than per event.
shutdown(): run shutdownInternal() regardless of running, since startup may have acquired resources before throwing.
Description
AbstractDatabaseManagerchecksisRunning()on the shutdown path but not on the write path.After
startupInternal()throws,startup()logs the cause and leavesrunning = false. Then:write()(line 297) does not check it — keeps accepting events and dereferences state startup never assigned. NPE per event, naming an internal field, burying the one line that named the cause.shutdown()(line 230) does check it — soshutdownInternal()never runs and whatever startup built is leaked. Returnstrueanyway.Affects every subclass whose startup fails: JDBC, JPA, NoSQL. #4242 is the case where the leak prevents JVM exit.
Version: 2.x
04c93c1d33, andmain— unchanged in this respect.Logs
Suggested fix
write(): return early when!isRunning(), logging once rather than per event.shutdown(): runshutdownInternal()regardless ofrunning, since startup may have acquired resources before throwing.