Skip to content

FileChangelogDB.removeDomain() throws NullPointerException when it races shutdownDB() #816

Description

@vharseko

FileChangelogDB.removeDomain() reassigns the local variable which the monitor it holds is
supposed to protect:

// FileChangelogDB.java:509-521
Map<Integer, FileReplicaDB> domainMap = domainToReplicaDBs.get(baseDN);
if (domainMap != null)
{
  ...
  synchronized (domainMap)
  {
    domainMap = domainToReplicaDBs.remove(baseDN);
    for (FileReplicaDB replicaDB : domainMap.values())

shutdownDB() removes the same entry, under the same monitor, in its drain of
domainToReplicaDBs (:355-366). A removeDomain() which acquires that monitor after the
drain has released it therefore gets null back from remove(baseDN) and dereferences it on
the very next line.

The result is a NullPointerException where the caller expects a ChangelogException:
ReplicationServerDomain.clearDbs() (:2066-2076) catches ChangelogException only, so the
NPE propagates out of the generation id change which called it.

The same window exists between two concurrent removeDomain() calls, and between
removeDomain() and clearDB(), which calls it for every domain it finds (:478).

Proposed fix

Remove conditionally, and keep iterating the map the monitor was taken on:

synchronized (domainMap)
{
  domainToReplicaDBs.remove(baseDN, domainMap);
  for (FileReplicaDB replicaDB : domainMap.values())

A replica DB which the drain has already released is then visited twice, which is harmless:
Log.clear() returns at once on a closed log (Log.java:772-780) and FileReplicaDB.shutdown()
is guarded by a CAS (FileReplicaDB.java:218).

Found while analysing #813.

Activity

  1. added a commit that references this issue on Aug 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions