Skip to content

JDBC backend: removeStorageFiles() drops only the tables this process has touched, so an offline import-ldif --clearBackend clears nothing #888

Description

@vharseko

Describe the bug

listTrees() of the JDBC backend answers from a lazily populated cache rather than from the database:

// opendj-server-legacy/src/main/java/org/opends/server/backends/jdbc/JDBCStorage.java:665
public Set<TreeName> listTrees() {
	return tree2table.asMap().keySet();
}

tree2table gains an entry the first time this process names a table for a tree — openTree, read, put, getRecordCount, a cursor. Nothing seeds it: open() only takes a connection and sets the storage status.

removeStorageFiles() is the one caller that runs before the root container is opened, and it drops exactly what that cache names:

// opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/BackendImpl.java:670
if (importConfig.clearBackend())
{
  // clear all files before opening the root container
  storage.removeStorageFiles();
}
// opendj-server-legacy/src/main/java/org/opends/server/backends/jdbc/JDBCStorage.java:147
final Set<TreeName> trees=listTrees();
if (!trees.isEmpty()) {
    ... drop table ...
}

In the offline import-ldif tool the backend is configured but never opened — BackendImpl.importLDIF refuses to run when rootContainer != null, so nothing has touched a tree yet — the cache is empty, trees.isEmpty() holds and the drop loop is skipped entirely. Nothing is cleared.

In the online import task the same command does drop the tables: ImportTask disables the backend and then calls importLDIF on the Backend object it already holds, so the JDBCStorage instance is the one that has been serving traffic with a fully populated tree2tableclose() does not invalidate it.

JE and PDB enumerate the environment itself (JEStorage.listTrees() -> env.getDatabaseNames()), and the Cassandra backend truncates the single table it names after the backend id, so both honour the contract regardless of process history. JDBC is the only storage whose answer depends on what the process happened to do earlier.

Impact

import-ldif --clearBackend does not clear a JDBC backend when run offline. The trees the import rebuilds are cleared by the importer itself, so the imported entries still come out right and the damage is confined to what the new import never touches:

  • the table of a base DN or of an index that is no longer configured keeps its rows for good, where on JE the same command removes the whole backend directory;
  • the compressed-schema tables survive an operation documented to clear everything;
  • the same command behaves differently offline and online, so the leftovers are hard to attribute to anything.

Expected behavior

removeStorageFiles() clears the backend's tables whether or not this process has opened the backend, and listTrees() answers from the database rather than from a per-process cache.

The naming makes this harder than it looks: a table is opendj_<sha224 of the tree name>, so the catalog cannot be filtered by a per-backend prefix and a hash cannot be turned back into a TreeName. Two ways out:

  • keep the mapping in the database — a small opendj_trees(tree_name, table_name) row written by openTree() and read back by listTrees(), which also gives backendstat a real answer before the root container is open;
  • or derive the table name from the backend id and the tree name, so that the backend's tables can be enumerated from the catalog by prefix.

Environment

master (5.2.x), JDBC backend, all four dialects.

Found while reviewing #881 (#873).

Activity

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