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

Valery Kharseko
yesterday d6a5316c7055055f2da0310748dc5a46dc777144
[#870] Stop replaying a rolled back read in the PersistIt backend (#871)
3 files modified
55 ■■■■■ changed files
opendj-server-legacy/src/main/java/org/opends/server/backends/pdb/PDBStorage.java 43 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/spi/ReadOperation.java 5 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/spi/Storage.java 7 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/backends/pdb/PDBStorage.java
@@ -598,29 +598,30 @@
    @Override
    public <T> T read(ReadOperation<T> operation) throws Exception
    {
      /*
       * A rolled back read is not replayed. Unlike WriteOperation, a ReadOperation is not required to be
       * idempotent, and four of them are not: ExportJob has written entries to its LDIF stream, whose writer is
       * opened once so that a replay appends rather than truncates; VerifyJob has accumulated its counters in
       * instance fields that no attempt resets; and the two reads of BackendStat have printed records and
       * appended to a map owned by their caller. Replaying corrupts their result rather than repairing it, so
       * the failure goes to the caller, as it does in the JE, Cassandra and JDBC backends.
       */
      final Transaction txn = db.getTransaction();
      for (;;)
      txn.begin();
      try
      {
        txn.begin();
        try
        {
          final T result = operation.run(this);
          txn.commit(commitPolicy);
          return result;
        }
        catch (final RollbackException e)
        {
          // retry
        }
        catch (final Exception e)
        {
          txn.rollback();
          throw e;
        }
        finally
        {
          txn.end();
        }
        final T result = operation.run(this);
        txn.commit(commitPolicy);
        return result;
      }
      catch (final Exception e)
      {
        txn.rollback();
        throw e;
      }
      finally
      {
        txn.end();
      }
    }
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/spi/ReadOperation.java
@@ -12,6 +12,7 @@
 * information: "Portions Copyright [year] [name of copyright owner]".
 *
 * Copyright 2014-2015 ForgeRock AS.
 * Portions Copyright 2026 3A Systems, LLC.
 */
package org.opends.server.backends.pluggable.spi;
@@ -26,6 +27,10 @@
{
  /**
   * Executes a read operation, and returns the read value.
   * <p>
   * Implementations need not be idempotent: unlike {@link WriteOperation}, a read operation is never replayed by
   * {@link Storage#read(ReadOperation)}, so it is free to print, to write to a stream, or to accumulate state
   * outside of the transaction.
   *
   * @param txn
   *          the read transaction where to execute the read operation
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/spi/Storage.java
@@ -12,6 +12,7 @@
 * information: "Portions Copyright [year] [name of copyright owner]".
 *
 * Copyright 2014-2015 ForgeRock AS.
 * Portions Copyright 2026 3A Systems, LLC.
 */
package org.opends.server.backends.pluggable.spi;
@@ -56,8 +57,10 @@
  void open(AccessMode accessMode) throws Exception;
  /**
   * Executes a read operation. In case of a read operation rollback, implementations must ensure
   * the read operation is retried until it succeeds.
   * Executes a read operation. In case of a read operation rollback, implementations must propagate the failure
   * to the caller rather than replay the operation: unlike {@link WriteOperation}, a {@link ReadOperation} is not
   * required to be idempotent, and several of them are not - they write to a stream, print, or accumulate state
   * that a second attempt would double.
   *
   * @param <T>
   *          type of the value returned