/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at
* trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
* add the following below this CDDL HEADER, with the fields enclosed
* by brackets "[]" replaced with your own identifying information:
* Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
*
* Copyright 2007-2009 Sun Microsystems, Inc.
* Portions Copyright 2013 ForgeRock AS.
*/
/**
*
* This class is used to store the list of remote changes received
* from a replication server and that are either currently being replayed
* or that are waiting for being replayed.
*
* It is used to know when the ServerState must be updated and to compute
* the dependencies between operations.
*
* One of this object is instantiated for each ReplicationDomain.
*
*/
public final class RemotePendingChanges
{
/**
* A map used to store the pending changes.
*/
/**
* A sorted set containing the list of PendingChanges that have
* not been replayed correctly because they are dependent on
* another change to be completed.
*/
new TreeSet<PendingChange>();
/**
* The ServerState that will be updated when LDAPUpdateMsg are fully replayed.
*/
/**
* Creates a new RemotePendingChanges using the provided ServerState.
*
* @param state The ServerState that will be updated when LDAPUpdateMsg
* have been fully replayed.
*/
{
}
/**
* Returns the number of changes currently in this list.
*
* @return The number of changes currently in this list.
*/
public synchronized int getQueueSize()
{
return pendingChanges.size();
}
/**
* Add a new LDAPUpdateMsg that was received from the replication server
* to the pendingList.
*
* @param update The LDAPUpdateMsg that was received from the replication
* server and that will be added to the pending list.
*/
{
update));
}
/**
* Mark an update message as committed.
*
* @param changeNumber The ChangeNumber of the update message that must be
* set as committed.
*/
{
{
throw new NoSuchElementException();
}
curChange.setCommitted(true);
{
if (pendingChanges.isEmpty())
{
firstChange = null;
}
else
{
}
}
}
/**
* Get the first update in the list that have some dependencies cleared.
*
* @return The LDAPUpdateMsg to be handled.
*/
{
/*
* Parse the list of Update with dependencies and check if the dependencies
* are now cleared until an Update without dependencies is found.
*/
{
{
}
}
return null;
}
/**
* Mark the first pendingChange as dependent on the second PendingChange.
* @param dependentChange The PendingChange that depend on the second
* PendingChange.
* @param pendingChange The PendingChange on which the first PendingChange
* is dependent.
*/
private void addDependency(
{
}
/**
* Check if the given AddOperation has some dependencies on any
* currently running previous operation.
* Update the dependency list in the associated PendingChange if
* there are some dependencies.
* AddOperation depends on
*
* - DeleteOperation done on the same DN
* - ModifyDnOperation with the same target DN as the ADD DN
* - ModifyDnOperation with new DN equals to the ADD DN parent
* - AddOperation done on the parent DN of the ADD DN
*
* @param op The AddOperation to be checked.
*
* @return A boolean indicating if this operation has some dependencies.
*/
{
boolean hasDependencies = false;
return false;
{
{
if (pendingMsg != null)
{
if (pendingMsg instanceof DeleteMsg)
{
/*
* Check is the operation to be run is a deleteOperation on the
* same DN.
*/
{
hasDependencies = true;
}
}
else if (pendingMsg instanceof AddMsg)
{
/*
* Check if the operation to be run is an addOperation on a
* parent of the current AddOperation.
*/
{
hasDependencies = true;
}
}
else if (pendingMsg instanceof ModifyDNMsg)
{
/*
* Check if the operation to be run is ModifyDnOperation with
* the same target DN as the ADD DN
* or a ModifyDnOperation with new DN equals to the ADD DN parent
*/
{
hasDependencies = true;
}
else
{
{
hasDependencies = true;
}
}
}
}
}
else
{
// We reached an operation that is newer than the operation
// for which we are doing the dependency check so it is
// not possible to find another operation with some dependency.
// break the loop to avoid going through the potentially large
// list of pending changes.
break;
}
}
return hasDependencies;
}
/**
* Check if the given ModifyOperation has some dependencies on any
* currently running previous operation.
* Update the dependency list in the associated PendingChange if
* there are some dependencies.
*
* ModifyOperation depends on
* - AddOperation done on the same DN
*
* @param op The ModifyOperation to be checked.
*
* @return A boolean indicating if this operation has some dependencies.
*/
{
boolean hasDependencies = false;
return false;
{
{
if (pendingMsg != null)
{
if (pendingMsg instanceof AddMsg)
{
/*
* Check if the operation to be run is an addOperation on a
* same DN.
*/
{
hasDependencies = true;
}
}
}
}
else
{
// We reached an operation that is newer than the operation
// for which we are doing the dependency check so it is
// not possible to find another operation with some dependency.
// break the loop to avoid going through the potentially large
// list of pending changes.
break;
}
}
return hasDependencies;
}
/**
* Check if the given ModifyDNMsg has some dependencies on any
* currently running previous operation.
* Update the dependency list in the associated PendingChange if
* there are some dependencies.
*
* Modify DN Operation depends on
* - AddOperation done on the same DN as the target DN of the MODDN operation
* - AddOperation done on the new parent of the MODDN operation
* - DeleteOperation done on the new DN of the MODDN operation
* - ModifyDNOperation done from the new DN of the MODDN operation
*
* @param msg The ModifyDNMsg to be checked.
*
* @return A boolean indicating if this operation has some dependencies.
*/
{
boolean hasDependencies = false;
return false;
{
{
if (pendingMsg != null)
{
if (pendingMsg instanceof DeleteMsg)
{
// Check if the target of the Delete is the same
// as the new DN of this ModifyDN
{
hasDependencies = true;
}
}
else if (pendingMsg instanceof AddMsg)
{
// Check if the Add Operation was done on the new parent of
// the MODDN operation
{
hasDependencies = true;
}
// Check if the AddOperation was done on the same DN as the
// target DN of the MODDN operation
{
hasDependencies = true;
}
}
else if (pendingMsg instanceof ModifyDNMsg)
{
// Check if the ModifyDNOperation was done from the new DN of
// the MODDN operation
{
hasDependencies = true;
}
}
}
}
else
{
// We reached an operation that is newer than the operation
// for which we are doing the dependency check so it is
// not possible to find another operation with some dependency.
// break the loop to avoid going through the potentially large
// list of pending changes.
break;
}
}
return hasDependencies;
}
/**
* Check if the given DeleteOperation has some dependencies on any
* currently running previous operation.
* Update the dependency list in the associated PendingChange if
* there are some dependencies.
*
* DeleteOperation depends on
* - DeleteOperation done on children DN
* - ModifyDnOperation with target DN that are children of the DEL DN
* - AddOperation done on the same DN
*
*
* @param op The DeleteOperation to be checked.
*
* @return A boolean indicating if this operation has some dependencies.
*/
{
boolean hasDependencies = false;
return false;
{
{
if (pendingMsg != null)
{
if (pendingMsg instanceof DeleteMsg)
{
/*
* Check if the operation to be run is a deleteOperation on a
* children of the current DeleteOperation.
*/
{
hasDependencies = true;
}
}
else if (pendingMsg instanceof AddMsg)
{
/*
* Check if the operation to be run is an addOperation on a
* parent of the current DeleteOperation.
*/
{
hasDependencies = true;
}
}
else if (pendingMsg instanceof ModifyDNMsg)
{
/*
* Check if the operation to be run is an ModifyDNOperation
* on a children of the current DeleteOperation
*/
{
hasDependencies = true;
}
}
}
}
else
{
// We reached an operation that is newer than the operation
// for which we are doing the dependency check so it is
// not possible to find another operation with some dependency.
// break the loop to avoid going through the potentially large
// list of pending changes.
break;
}
}
return hasDependencies;
}
/**
*
* @param op The Operation for which dependencies must be checked.
* @param msg The Message for which dependencies must be checked.
* @return A boolean indicating if an operation cannot be replayed
* because of dependencies.
*/
{
if (op instanceof ModifyOperation)
{
return checkDependencies(newOp);
} else if (op instanceof DeleteOperation)
{
return checkDependencies(newOp);
} else if (op instanceof AddOperation)
{
return checkDependencies(newOp);
} else if (op instanceof ModifyDNOperationBasis)
{
return checkDependencies(newMsg);
} else
{
return true; // unknown type of operation ?!
}
}
}