mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Valery Kharseko
yesterday e86f702f8e11d85eb7fcbde8de64657a4e308a21
[#966] Tell the import and restore task listeners the task is over on every path (#969)
3 files modified
134 ■■■■ changed files
opendj-server-legacy/src/main/java/org/opends/server/tasks/ImportTask.java 28 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/tasks/RestoreTask.java 27 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/tasks/TestImportAndExport.java 79 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/tasks/ImportTask.java
@@ -627,10 +627,20 @@
    // and to take appropriate actions.
    DirectoryServer.notifyImportBeginning(backend, importConfig);
    /*
     * From here the listeners must be told that the import is over whichever way this
     * method returns: a listener which took something offline when it began - a
     * replication domain disables itself - gets no other chance to put it back.
     */
    boolean backendDisabled = false;
    boolean successful = false;
    try
    {
    // Disable the backend.
    try
    {
      TaskUtils.disableBackend(backend.getBackendID());
        backendDisabled = true;
    }
    catch (DirectoryException e)
    {
@@ -640,8 +650,6 @@
      return TaskState.STOPPED_BY_ERROR;
    }
    try
    {
      // Acquire an exclusive lock for the backend.
      try
      {
@@ -665,12 +673,12 @@
      try
      {
        backend.importLDIF(importConfig, DirectoryServer.getInstance().getServerContext());
        successful = true;
      }
      catch (DirectoryException de)
      {
        logger.traceException(de);
        DirectoryServer.notifyImportEnded(backend, importConfig, false);
        if (de.getResultCode().equals(DirectoryServer.getCoreConfigManager().getServerErrorResultCode()))
        {
          logger.error(ERR_LDIFIMPORT_ERROR_DURING_IMPORT.get(de.getMessageObject()));
@@ -685,7 +693,6 @@
      {
        logger.traceException(e);
        DirectoryServer.notifyImportEnded(backend, importConfig, false);
        logger.error(ERR_LDIFIMPORT_ERROR_DURING_IMPORT, getExceptionMessage(e));
        return TaskState.STOPPED_BY_ERROR;
      }
@@ -713,7 +720,10 @@
    }
    finally
    {
      // Enable the backend.
      // Enable the backend, if it was this task which disabled it.
      boolean backendLeftDisabled = false;
      if (backendDisabled)
      {
      try
      {
        TaskUtils.enableBackend(backend.getBackendID());
@@ -727,9 +737,15 @@
        logger.traceException(e);
        logger.error(e.getMessageObject());
          backendLeftDisabled = true;
        }
      }
      // Notified once, after the backend is back, so that a listener can read it again.
      DirectoryServer.notifyImportEnded(backend, importConfig, successful);
      if (backendLeftDisabled)
      {
        return TaskState.STOPPED_BY_ERROR;
      }
      DirectoryServer.notifyImportEnded(backend, importConfig, true);
    }
    // Clean up after the import by closing the import config.
opendj-server-legacy/src/main/java/org/opends/server/tasks/RestoreTask.java
@@ -13,6 +13,7 @@
 *
 * Copyright 2006-2008 Sun Microsystems, Inc.
 * Portions Copyright 2014-2016 ForgeRock AS.
 * Portions Copyright 2026 3A Systems, LLC.
 */
package org.opends.server.tasks;
@@ -262,25 +263,32 @@
    // and to take appropriate actions.
    DirectoryServer.notifyRestoreBeginning(backend, restoreConfig);
    // Disable the backend.
    /*
     * From here the listeners must be told that the restore is over whichever way this
     * method returns: a listener which took something offline when it began - a
     * replication domain disables itself - gets no other chance to put it back.
     */
    boolean backendDisabled = false;
    boolean errorsEncountered = false;
    try
    {
      // Disable the backend. From here the finally below re-enables it before returning.
    if ( !verifyOnly)
    {
      try
      {
        TaskUtils.disableBackend(backendID);
          backendDisabled = true;
      } catch (DirectoryException e)
      {
        logger.traceException(e);
        logger.error(e.getMessageObject());
          errorsEncountered = true;
        return TaskState.STOPPED_BY_ERROR;
      }
    }
    // From here we must make sure to re-enable the backend before returning.
    boolean errorsEncountered = false;
    try
    {
      // Acquire an exclusive lock for the backend.
      if (verifyOnly || lockBackend(backend))
      {
@@ -294,13 +302,11 @@
          }
          catch (DirectoryException de)
          {
            DirectoryServer.notifyRestoreEnded(backend, restoreConfig, false);
            logger.error(ERR_RESTOREDB_ERROR_DURING_BACKUP, backupID, backupDir.getPath(), de.getMessageObject());
            errorsEncountered = true;
          }
          catch (Exception e)
          {
            DirectoryServer.notifyRestoreEnded(backend, restoreConfig, false);
            logger.error(ERR_RESTOREDB_ERROR_DURING_BACKUP, backupID, backupDir.getPath(), getExceptionMessage(e));
            errorsEncountered = true;
          }
@@ -317,8 +323,8 @@
    }
    finally
    {
      // Enable the backend.
      if (! verifyOnly)
      // Enable the backend, if it was this task which disabled it.
      if (backendDisabled)
      {
        try
        {
@@ -335,7 +341,8 @@
          errorsEncountered = true;
        }
      }
      DirectoryServer.notifyRestoreEnded(backend, restoreConfig, true);
      // Notified once, after the backend is back, so that a listener can read it again.
      DirectoryServer.notifyRestoreEnded(backend, restoreConfig, !errorsEncountered);
    }
    if (errorsEncountered)
opendj-server-legacy/src/test/java/org/opends/server/tasks/TestImportAndExport.java
@@ -22,9 +22,11 @@
import org.forgerock.opendj.ldap.ResultCode;
import org.opends.server.TestCaseUtils;
import org.opends.server.api.LocalBackend;
import org.opends.server.api.TestTaskListener;
import org.opends.server.backends.task.TaskState;
import org.opends.server.core.AddOperation;
import org.opends.server.core.BackendConfigManager;
import org.opends.server.core.DirectoryServer;
import org.opends.server.types.Entry;
import org.forgerock.opendj.ldap.schema.ObjectClass;
@@ -383,6 +385,83 @@
 }
  /**
   * An import which cannot disable its backend must still tell the import task listeners
   * that the import is over: a listener which took something offline when the import began
   * - a replication domain disables itself - has no other chance to put it back.
   */
  @Test
  public void testImportEndsWhenTheBackendCannotBeDisabled() throws Exception
  {
    /*
     * A backend registered at runtime has no entry in cn=config, and disabling a backend
     * is a modification of that entry, so TaskUtils.disableBackend() cannot do it.
     */
    final String backendID = "importTaskUnconfiguredBackend";
    TestCaseUtils.initializeMemoryBackend(backendID, "dc=unconfigured,dc=com", true);
    try
    {
      int importBeginCount = TestTaskListener.importBeginCount.get();
      int importEndCount   = TestTaskListener.importEndCount.get();
      Entry taskEntry = TestCaseUtils.makeEntry(
          "dn: ds-task-id=" + UUID.randomUUID() + ",cn=Scheduled Tasks,cn=Tasks",
          "objectclass: top",
          "objectclass: ds-task",
          "objectclass: ds-task-import",
          "ds-task-class-name: org.opends.server.tasks.ImportTask",
          "ds-task-import-backend-id: " + backendID,
          "ds-task-import-ldif-file: " + ldifFile.getPath());
      testTask(taskEntry, TaskState.STOPPED_BY_ERROR, 60);
      assertEquals(TestTaskListener.importBeginCount.get(), importBeginCount + 1);
      assertEquals(TestTaskListener.importEndCount.get(), importEndCount + 1);
    }
    finally
    {
      removeMemoryBackend(backendID);
    }
  }
  /**
   * A failed import must notify the listeners exactly once, as its beginning was notified
   * once: a replication domain enabled a second time reloads and rewinds its replication
   * state for nothing.
   */
  @Test
  public void testFailedImportEndsOnlyOnce() throws Exception
  {
    int importBeginCount = TestTaskListener.importBeginCount.get();
    int importEndCount   = TestTaskListener.importEndCount.get();
    // A directory can be read, so the task accepts it, but it cannot be read as LDIF.
    Entry taskEntry = TestCaseUtils.makeEntry(
        "dn: ds-task-id=" + UUID.randomUUID() + ",cn=Scheduled Tasks,cn=Tasks",
        "objectclass: top",
        "objectclass: ds-task",
        "objectclass: ds-task-import",
        "ds-task-class-name: org.opends.server.tasks.ImportTask",
        "ds-task-import-backend-id: userRoot",
        "ds-task-import-ldif-file: " + ldifFile.getParent());
    testTask(taskEntry, TaskState.STOPPED_BY_ERROR, 60);
    assertEquals(TestTaskListener.importBeginCount.get(), importBeginCount + 1);
    assertEquals(TestTaskListener.importEndCount.get(), importEndCount + 1);
  }
  private void removeMemoryBackend(String backendID) throws Exception
  {
    BackendConfigManager backendConfigManager = TestCaseUtils.getServerContext().getBackendConfigManager();
    LocalBackend<?> backend = backendConfigManager.getLocalBackendById(backendID);
    if (backend != null)
    {
      backend.finalizeBackend();
      backendConfigManager.deregisterLocalBackend(backend);
    }
  }
  /**
   * Add a task definition and check that it completes with the expected state.
   * @param taskEntry The task entry.
   * @param resultCode The expected result code of the task add.