ReplayThread.run() wraps the take-and-replay loop in catch (Exception e) with the comment "catch all exceptions happening so that the thread never dies even in case of problems" (opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/ReplayThread.java:116-124).
An Error is not an Exception, so it does exactly what the comment says must not happen: it unwinds run() and the thread ends. MultimasterReplication.createReplayThreads() runs at initialization and on a ds-cfg-num-update-replay-threads change only, so nothing replaces it - the pool keeps a terminated Thread in its list and the shared updateToReplayQueue has one consumer fewer for every domain of the server. DirectoryThread's handler logs ERR_UNCAUGHT_THREAD_EXCEPTION and raises an ALERT_TYPE_UNCAUGHT_EXCEPTION, which is the only trace of it.
Repeated, this stops replication for the whole server: processUpdate() blocks in its offer loop once no thread takes from the queue.
Widening the catch to Throwable is not enough on its own:
Both halves want doing together, or an Error which repeats turns into a change nobody can replay while the thread which reports it lives on.
Found while reviewing #892.
ReplayThread.run()wraps the take-and-replay loop incatch (Exception e)with the comment "catch all exceptions happening so that the thread never dies even in case of problems" (opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/ReplayThread.java:116-124).An
Erroris not anException, so it does exactly what the comment says must not happen: it unwindsrun()and the thread ends.MultimasterReplication.createReplayThreads()runs at initialization and on ads-cfg-num-update-replay-threadschange only, so nothing replaces it - the pool keeps a terminatedThreadin its list and the sharedupdateToReplayQueuehas one consumer fewer for every domain of the server.DirectoryThread's handler logsERR_UNCAUGHT_THREAD_EXCEPTIONand raises anALERT_TYPE_UNCAUGHT_EXCEPTION, which is the only trace of it.Repeated, this stops replication for the whole server:
processUpdate()blocks in its offer loop once no thread takes from the queue.Widening the catch to
Throwableis not enough on its own:VirtualMachineErroris not something to report and carry on from - the report itself allocates - so it belongs on its own arm, rethrown;Both halves want doing together, or an
Errorwhich repeats turns into a change nobody can replay while the thread which reports it lives on.Found while reviewing #892.