Skip to content
Open
Original file line number Diff line number Diff line change
Expand Up @@ -2179,6 +2179,9 @@ The directory server detects that its configuration has been manually edited wit
`org.opends.server.replication.UnresolvedConflict`::
Multimaster replication cannot resolve a conflict automatically.

`org.opends.server.replication.UnreplayedChange`::
Multimaster replication gave up on a change it could not replay. This replica now diverges from the rest of the topology and must be reinitialized.

`org.opends.server.UncaughtException`::
A directory server thread has encountered an uncaught exception that caused that thread to terminate abnormally. The impact that this problem has on the server depends on which thread was impacted and the nature of the exception.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
! CCPL HEADER END
!
! Copyright 2011-2013 ForgeRock AS
! Portions Copyright 2024 3A Systems, LLC
! Portions Copyright 2024-2026 3A Systems, LLC
!
-->
<chapter xml:id='chap-monitoring'
Expand Down Expand Up @@ -983,6 +983,14 @@ $ dsconfig
automatically.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>org.opends.server.replication.UnreplayedChange</literal></term>
<listitem>
<para>Multimaster replication gave up on a change it could not replay.
This replica now diverges from the rest of the topology and must be
reinitialized.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>org.opends.server.UncaughtException</literal></term>
<listitem>
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -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.replication.plugin;

Expand All @@ -29,7 +30,29 @@ class PendingChange implements Comparable<PendingChange>
{
private final CSN csn;
private boolean committed;
private UpdateMsg msg;
/**
* Written when the delivery which owns a remote change is taken over by the one which
* follows it, and read by the dependency checks without the pending changes lock.
*/
private volatile UpdateMsg msg;
/**
* Whether a replay thread owns this change: it is being replayed, or it waits for the
* change it depends on. A remote change which no thread owns is one whose replay
* failed and which the replication server is expected to deliver again.
*/
private boolean owned;
/**
* How many times in a row the replay of this change failed, and when the first of
* those failures happened - on a clock which only moves forward.
* <p>
* They live here, on the change which stays listed as the barrier holding the
* ServerState back, rather than in a map on the side: a bound on such a map would have
* a change evicted between two of its own failures and its give-up budget restarted,
* so a replica failing more changes than the bound would never give up on any of them
* (issue #889).
*/
private int replayFailures;
private long firstReplayFailureTimeMs;
private final PluginOperation op;

/**
Expand Down Expand Up @@ -107,6 +130,65 @@ public void setMsg(LDAPUpdateMsg msg)
this.msg = msg;
}

/**
* Returns whether a replay thread owns this change.
*
* @return {@code true} if a replay thread is replaying this change or waiting for the
* change it depends on
*/
public boolean isOwned()
{
return owned;
}

/**
* Sets whether a replay thread owns this change.
*
* @param owned {@code true} when a replay thread takes the change over, {@code false}
* when its replay failed and the change must be delivered again
*/
public void setOwned(boolean owned)
{
this.owned = owned;
}

/**
* Records that the replay of this change failed once more.
*
* @param nowMs
* when it failed, on a clock which only moves forward
*/
public void recordReplayFailure(long nowMs)
{
if (replayFailures == 0)
{
firstReplayFailureTimeMs = nowMs;
}
replayFailures++;
}

/**
* Returns how many times in a row the replay of this change failed.
*
* @return the number of failures, 0 when its replay never failed
*/
public int getReplayFailures()
{
return replayFailures;
}

/**
* Returns how long the replay of this change has been failing.
*
* @param nowMs
* the current time, on the clock {@link #recordReplayFailure(long)} was given
* @return the duration in milliseconds, 0 when its replay never failed
*/
public long getReplayFailingForMs(long nowMs)
{
return replayFailures == 0 ? 0 : nowMs - firstReplayFailureTimeMs;
}

/**
* Get the operation associated to the PendingChange.
* @return the operation
Expand Down
Loading
Loading