From c36a6780c20f526df1bc6e1a3a3b71dfa8b9ec3d Mon Sep 17 00:00:00 2001
From: gbellato <gbellato@localhost>
Date: Wed, 28 Feb 2007 14:06:57 +0000
Subject: [PATCH] This set of changes allow to have the schema synchronization working by configuring synchronization for suffix cn=schema (issue 613) .
---
opends/resource/schema/02-config.ldif | 3
opends/src/server/org/opends/server/synchronization/plugin/SynchronizationDomain.java | 76 ++++-
opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/StressTest.java | 4
opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/SchemaSynchronizationTest.java | 237 ++++++++++++++++++
opends/src/server/org/opends/server/synchronization/plugin/PersistentServerState.java | 95 ------
opends/src/server/org/opends/server/types/Schema.java | 30 ++
opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/UpdateOperationTest.java | 15 -
opends/tests/unit-tests-testng/src/server/org/opends/server/api/ConfigurableComponentTestCase.java | 8
opends/src/server/org/opends/server/core/SchemaConfigManager.java | 13 +
opends/src/server/org/opends/server/core/Operation.java | 35 ++
opends/src/server/org/opends/server/synchronization/plugin/MultimasterSynchronization.java | 54 +--
opends/src/server/org/opends/server/backends/SchemaBackend.java | 48 +++
opends/src/server/org/opends/server/config/ConfigConstants.java | 6
opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/plugin/PersistentStateTest.java | 125 +++++++++
opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/SynchronizationTestCase.java | 14
15 files changed, 595 insertions(+), 168 deletions(-)
diff --git a/opends/resource/schema/02-config.ldif b/opends/resource/schema/02-config.ldif
index 403c034..98110f6 100644
--- a/opends/resource/schema/02-config.ldif
+++ b/opends/resource/schema/02-config.ldif
@@ -776,7 +776,8 @@
SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
SINGLE-VALUE X-ORIGIN 'OpenDS Directory Server' )
attributeTypes: ( 1.3.6.1.4.1.26027.1.1.227 NAME 'ds-sync-state'
- SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'OpenDS Directory Server' )
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 USAGE directoryOperation
+ X-ORIGIN 'OpenDS Directory Server' )
attributeTypes: ( 1.3.6.1.4.1.26027.1.1.228
NAME 'ds-cfg-backup-directory' EQUALITY caseExactMatch
SUBSTR caseExactSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
diff --git a/opends/src/server/org/opends/server/backends/SchemaBackend.java b/opends/src/server/org/opends/server/backends/SchemaBackend.java
index 6a4a349..0d2ed35 100644
--- a/opends/src/server/org/opends/server/backends/SchemaBackend.java
+++ b/opends/src/server/org/opends/server/backends/SchemaBackend.java
@@ -189,6 +189,9 @@
// The attribute type that will be used to include the defined name forms.
private AttributeType nameFormsType;
+ // The attribute type that will be used to save the synchronization state.
+ private AttributeType synchronizationStateType;
+
// The value containing DN of the user we'll say created the configuration.
private AttributeValue creatorsName;
@@ -293,6 +296,8 @@
matchingRuleUsesType =
DirectoryServer.getAttributeType(ATTR_MATCHING_RULE_USE_LC, true);
nameFormsType = DirectoryServer.getAttributeType(ATTR_NAME_FORMS_LC, true);
+ synchronizationStateType =
+ DirectoryServer.getAttributeType(ATTR_SYNCHRONIZATION_STATE_LC, true);
// Initialize the lastmod attributes.
@@ -797,6 +802,20 @@
valueSet));
operationalAttrs.put(modifyTimestampType, attrList);
+ // Add the synchronization State attribute.
+ valueSet = DirectoryServer.getSchema().getSynchronizationState();
+ attr = new Attribute(synchronizationStateType,
+ ATTR_SYNCHRONIZATION_STATE_LC, valueSet);
+ attrList = new ArrayList<Attribute>(1);
+ attrList.add(attr);
+ if (synchronizationStateType.isOperational() && (! showAllAttributes))
+ {
+ operationalAttrs.put(synchronizationStateType, attrList);
+ }
+ else
+ {
+ userAttrs.put(synchronizationStateType, attrList);
+ }
// Add all the user-defined attributes.
for (Attribute a : userDefinedAttributes)
@@ -1350,10 +1369,19 @@
default:
- int msgID = MSGID_SCHEMA_INVALID_MODIFICATION_TYPE;
- String message = getMessage(msgID, m.getModificationType());
- throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
- msgID);
+ if (!modifyOperation.isSynchronizationOperation())
+ {
+ int msgID = MSGID_SCHEMA_INVALID_MODIFICATION_TYPE;
+ String message = getMessage(msgID, m.getModificationType());
+ throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM,
+ message, msgID);
+ }
+ else
+ {
+ if (at.equals(synchronizationStateType))
+ newSchema.setSynchronizationState(a.getValues());
+ modifiedSchemaFiles.add(FILE_USER_SCHEMA_ELEMENTS);
+ }
}
}
@@ -3438,6 +3466,18 @@
schemaEntry.putAttribute(matchingRuleUsesType, attrList);
}
+ if (schemaFile.equals(FILE_USER_SCHEMA_ELEMENTS))
+ {
+ values = schema.getSynchronizationState();
+ if (values != null)
+ {
+ ArrayList<Attribute> attrList = new ArrayList<Attribute>(1);
+ attrList.add(new Attribute(matchingRuleUsesType,
+ matchingRuleUsesType.getPrimaryName(),
+ values));
+ schemaEntry.putAttribute(matchingRuleUsesType, attrList);
+ }
+ }
// Create a temporary file to which we can write the schema entry.
File tempFile = File.createTempFile(schemaFile, "temp");
diff --git a/opends/src/server/org/opends/server/config/ConfigConstants.java b/opends/src/server/org/opends/server/config/ConfigConstants.java
index dcbb8ed..3a30ab5 100644
--- a/opends/src/server/org/opends/server/config/ConfigConstants.java
+++ b/opends/src/server/org/opends/server/config/ConfigConstants.java
@@ -1217,7 +1217,11 @@
*/
public static final String ATTR_MATCHING_RULE_USE_LC = "matchingruleuse";
-
+ /**
+ * The name of the attribute that holds the sycnhronization state,
+ * formatted in lowercase.
+ */
+ public static final String ATTR_SYNCHRONIZATION_STATE_LC = "ds-sync-state";
/**
* The default maximum request size that should be used if none is specified
diff --git a/opends/src/server/org/opends/server/core/Operation.java b/opends/src/server/org/opends/server/core/Operation.java
index 5943668..36a7ef3 100644
--- a/opends/src/server/org/opends/server/core/Operation.java
+++ b/opends/src/server/org/opends/server/core/Operation.java
@@ -138,6 +138,10 @@
// in the response to the client.
private StringBuilder errorMessage;
+ // Indicates whether this operation nneds to be synchronized to
+ // other copies of the data.
+ private boolean dontSynchronizeFlag;
+
/**
@@ -730,6 +734,21 @@
}
+ /**
+ * Specifies whether this operation must be synchronized to other copies
+ * of the data.
+ *
+ * @param dontSynchronize Specifies whether this operation must be
+ * synchronized to other copies
+ * of the data.
+ */
+ public final void setDontSynchronize(boolean dontSynchronize)
+ {
+ assert debugEnter(CLASS_NAME, "setDontSynchronize",
+ String.valueOf(dontSynchronize));
+
+ this.dontSynchronizeFlag = dontSynchronize;
+ }
/**
* Retrieves the entry for the user that should be considered the
@@ -1058,5 +1077,21 @@
* operation should be appended.
*/
public abstract void toString(StringBuilder buffer);
+
+
+ /**
+ * Indicates whether this operation needs to be synchronized to
+ * other copies of the data.
+ *
+ * @return <CODE>true</CODE> if this operation don't need to be
+ * synchronized, or
+ * <CODE>false</CODE> if it needs to be synchronized.
+ */
+ public boolean dontSynchronize()
+ {
+ assert debugEnter(CLASS_NAME, "dontSynchronize");
+
+ return dontSynchronizeFlag;
+ }
}
diff --git a/opends/src/server/org/opends/server/core/SchemaConfigManager.java b/opends/src/server/org/opends/server/core/SchemaConfigManager.java
index 7aaca38..7dc5091 100644
--- a/opends/src/server/org/opends/server/core/SchemaConfigManager.java
+++ b/opends/src/server/org/opends/server/core/SchemaConfigManager.java
@@ -1053,6 +1053,19 @@
List<Attribute> mruList = entry.getAttribute(mruAttrType);
+ AttributeType synchronizationStateType =
+ schema.getAttributeType(ATTR_SYNCHRONIZATION_STATE_LC);
+ if (synchronizationStateType == null)
+ {
+ synchronizationStateType =
+ DirectoryServer.getDefaultAttributeType(ATTR_SYNCHRONIZATION_STATE_LC,
+ new MatchingRuleUseSyntax());
+ }
+
+ List<Attribute> synchronizationState =
+ entry.getAttribute(synchronizationStateType);
+ if (synchronizationState != null && !(synchronizationState.isEmpty()))
+ schema.setSynchronizationState(synchronizationState.get(0).getValues());
// Parse the attribute type definitions if there are any.
if (attrList != null)
diff --git a/opends/src/server/org/opends/server/synchronization/plugin/MultimasterSynchronization.java b/opends/src/server/org/opends/server/synchronization/plugin/MultimasterSynchronization.java
index 0143f89..2a3210d 100644
--- a/opends/src/server/org/opends/server/synchronization/plugin/MultimasterSynchronization.java
+++ b/opends/src/server/org/opends/server/synchronization/plugin/MultimasterSynchronization.java
@@ -38,7 +38,6 @@
import org.opends.server.core.AddOperation;
import org.opends.server.synchronization.changelog.Changelog;
import org.opends.server.synchronization.common.LogMessages;
-import org.opends.server.synchronization.common.ServerState;
import org.opends.server.types.DN;
import org.opends.server.core.DeleteOperation;
import org.opends.server.types.DirectoryException;
@@ -74,20 +73,6 @@
private static Map<DN, SynchronizationDomain> domains =
new HashMap<DN, SynchronizationDomain>() ;
- /**
- * Get the ServerState associated to the SynchronizationDomain
- * with a given DN.
- *
- * @param baseDn The DN of the Synchronization Domain for which the
- * ServerState must be returned.
- * @return the ServerState associated to the SynchronizationDomain
- * with the DN in parameter.
- */
- public static ServerState getServerState(DN baseDn)
- {
- SynchronizationDomain domain = findDomain(baseDn);
- return domain.getServerState();
- }
/**
* {@inheritDoc}
@@ -323,7 +308,8 @@
public SynchronizationProviderResult handleConflictResolution(
ModifyOperation modifyOperation)
{
- SynchronizationDomain domain = findDomain(modifyOperation.getEntryDN());
+ SynchronizationDomain domain =
+ findDomain(modifyOperation.getEntryDN(), modifyOperation);
if (domain == null)
return new SynchronizationProviderResult(true);
@@ -337,7 +323,8 @@
public SynchronizationProviderResult handleConflictResolution(
AddOperation addOperation) throws DirectoryException
{
- SynchronizationDomain domain = findDomain(addOperation.getEntryDN());
+ SynchronizationDomain domain =
+ findDomain(addOperation.getEntryDN(), addOperation);
if (domain == null)
return new SynchronizationProviderResult(true);
@@ -351,7 +338,8 @@
public SynchronizationProviderResult handleConflictResolution(
DeleteOperation deleteOperation) throws DirectoryException
{
- SynchronizationDomain domain = findDomain(deleteOperation.getEntryDN());
+ SynchronizationDomain domain =
+ findDomain(deleteOperation.getEntryDN(), deleteOperation);
if (domain == null)
return new SynchronizationProviderResult(true);
@@ -365,7 +353,8 @@
public SynchronizationProviderResult handleConflictResolution(
ModifyDNOperation modifyDNOperation) throws DirectoryException
{
- SynchronizationDomain domain = findDomain(modifyDNOperation.getEntryDN());
+ SynchronizationDomain domain =
+ findDomain(modifyDNOperation.getEntryDN(), modifyDNOperation);
if (domain == null)
return new SynchronizationProviderResult(true);
@@ -379,8 +368,10 @@
public SynchronizationProviderResult
doPreOperation(ModifyOperation modifyOperation)
{
- SynchronizationDomain domain = findDomain(modifyOperation.getEntryDN());
- if (domain == null)
+ DN operationDN = modifyOperation.getEntryDN();
+ SynchronizationDomain domain = findDomain(operationDN, modifyOperation);
+
+ if ((domain == null) || (!domain.solveConflict()))
return new SynchronizationProviderResult(true);
Historical historicalInformation = (Historical)
@@ -423,7 +414,8 @@
@Override
public SynchronizationProviderResult doPreOperation(AddOperation addOperation)
{
- SynchronizationDomain domain = findDomain(addOperation.getEntryDN());
+ SynchronizationDomain domain =
+ findDomain(addOperation.getEntryDN(), addOperation);
if (domain == null)
return new SynchronizationProviderResult(true);
@@ -457,8 +449,15 @@
* @param dn The DN for which the domain must be returned.
* @return The Synchronization domain for this DN.
*/
- private static SynchronizationDomain findDomain(DN dn)
+ private static SynchronizationDomain findDomain(DN dn, Operation op)
{
+ /*
+ * Don't run the special synchronization code on Operation that are
+ * specifically marked as don't synchronize.
+ */
+ if (op.dontSynchronize())
+ return null;
+
SynchronizationDomain domain = null;
DN temp = dn;
do
@@ -471,13 +470,6 @@
}
} while (domain == null);
- /*
- * Don't apply synchronization to the special entry where the ServerState
- * is stored.
- */
- if ((domain!= null) && (domain.getServerStateDN().equals(dn)))
- return null;
-
return domain;
}
@@ -489,7 +481,7 @@
*/
private void genericPostOperation(Operation operation, DN dn)
{
- SynchronizationDomain domain = findDomain(dn);
+ SynchronizationDomain domain = findDomain(dn, operation);
if (domain == null)
return;
diff --git a/opends/src/server/org/opends/server/synchronization/plugin/PersistentServerState.java b/opends/src/server/org/opends/server/synchronization/plugin/PersistentServerState.java
index b2c5c7d..b993a45 100644
--- a/opends/src/server/org/opends/server/synchronization/plugin/PersistentServerState.java
+++ b/opends/src/server/org/opends/server/synchronization/plugin/PersistentServerState.java
@@ -35,7 +35,6 @@
import java.util.LinkedList;
import java.util.List;
-import org.opends.server.core.AddOperation;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.ModifyOperation;
import org.opends.server.protocols.asn1.ASN1OctetString;
@@ -53,7 +52,6 @@
import org.opends.server.types.Control;
import org.opends.server.types.DN;
import org.opends.server.types.DereferencePolicy;
-import org.opends.server.types.DirectoryException;
import org.opends.server.types.ErrorLogCategory;
import org.opends.server.types.ErrorLogSeverity;
import org.opends.server.types.ModificationType;
@@ -72,8 +70,7 @@
private boolean savedStatus = true;
private InternalClientConnection conn =
InternalClientConnection.getRootConnection();
- private ASN1OctetString serverStateAsn1Dn;
- private DN serverStateDn;
+ private ASN1OctetString asn1BaseDn;
/**
* The attribute name used to store the state in the backend.
@@ -87,16 +84,8 @@
public PersistentServerState(DN baseDn)
{
this.baseDn = baseDn;
- serverStateAsn1Dn = new ASN1OctetString(
- "dc=ffffffff-ffffffff-ffffffff-ffffffff,"
- + baseDn.toString());
- try
- {
- serverStateDn = DN.decode(serverStateAsn1Dn);
- } catch (DirectoryException e)
- {
- // never happens
- }
+ asn1BaseDn = new ASN1OctetString(baseDn.toString());
+ loadState();
}
/**
@@ -121,22 +110,14 @@
ResultCode resultCode = updateStateEntry();
if (resultCode != ResultCode.SUCCESS)
{
- if (resultCode == ResultCode.NO_SUCH_OBJECT)
- {
- createStateEntry();
- }
- else
- {
savedStatus = false;
-
- }
}
}
/**
* Load the ServerState from the backing entry in database to memory.
*/
- public void loadState()
+ private void loadState()
{
/*
* Read the serverState from the database,
@@ -156,10 +137,12 @@
* Search the database entry that is used to periodically
* save the ServerState
*/
- InternalSearchOperation search = conn.processSearch(serverStateAsn1Dn,
+ LinkedHashSet<String> attributes = new LinkedHashSet<String>(1);
+ attributes.add(SYNCHRONIZATION_STATE);
+ InternalSearchOperation search = conn.processSearch(asn1BaseDn,
SearchScope.BASE_OBJECT,
DereferencePolicy.DEREF_ALWAYS, 0, 0, false,
- filter,new LinkedHashSet<String>(0));
+ filter,attributes);
if (((search.getResultCode() != ResultCode.SUCCESS)) &&
((search.getResultCode() != ResultCode.NO_SUCH_OBJECT)))
{
@@ -210,51 +193,6 @@
* and an ordering index for historical attribute
*/
}
-
- if ((resultEntry == null) ||
- ((search.getResultCode() != ResultCode.SUCCESS)))
- {
- createStateEntry();
- }
- }
-
- /**
- * Create the Entry that will be used to store the ServerState information.
- * It will be updated when the server stops and periodically.
- */
- private void createStateEntry()
- {
- ArrayList<LDAPAttribute> attrs = new ArrayList<LDAPAttribute>();
-
- ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
- ASN1OctetString value = new ASN1OctetString("extensibleObject");
- values.add(value);
- LDAPAttribute attr = new LDAPAttribute("objectClass", values);
- value = new ASN1OctetString("domain");
- values.add(value);
- attr = new LDAPAttribute("objectClass", values);
- attrs.add(attr);
-
- values = new ArrayList<ASN1OctetString>();
- value = new ASN1OctetString("ffffffff-ffffffff-ffffffff-ffffffff");
- values.add(value);
- attr = new LDAPAttribute("dc", values);
- attrs.add(attr);
-
- AddOperation add = conn.processAdd(serverStateAsn1Dn, attrs);
- ResultCode resultCode = add.getResultCode();
- if ((resultCode != ResultCode.SUCCESS) &&
- (resultCode != ResultCode.NO_SUCH_OBJECT))
- {
- int msgID = MSGID_ERROR_UPDATING_RUV;
- String message = getMessage(msgID,
- add.getResultCode().getResultCodeName(),
- add.toString(), add.getErrorMessage(),
- baseDn.toString());
- logError(ErrorLogCategory.SYNCHRONIZATION,
- ErrorLogSeverity.SEVERE_ERROR,
- message, msgID);
- }
}
/**
@@ -266,8 +204,7 @@
private ResultCode updateStateEntry()
{
/*
- * Generate a modify operation on the Server State Entry :
- * cn=ffffffff-ffffffff-ffffffff-ffffffff, baseDn
+ * Generate a modify operation on the Server State baseD Entry.
*/
ArrayList<ASN1OctetString> values = this.toASN1ArrayList();
@@ -283,10 +220,11 @@
ModifyOperation op =
new ModifyOperation(conn, InternalClientConnection.nextOperationID(),
InternalClientConnection.nextMessageID(),
- new ArrayList<Control>(0), serverStateAsn1Dn,
+ new ArrayList<Control>(0), asn1BaseDn,
mods);
op.setInternalOperation(true);
op.setSynchronizationOperation(true);
+ op.setDontSynchronize(true);
op.run();
@@ -301,15 +239,4 @@
}
return result;
}
-
- /**
- * Get the Dn where the ServerState is stored.
- * @return Returns the serverStateDn.
- */
- public DN getServerStateDn()
- {
- return serverStateDn;
- }
-
-
}
diff --git a/opends/src/server/org/opends/server/synchronization/plugin/SynchronizationDomain.java b/opends/src/server/org/opends/server/synchronization/plugin/SynchronizationDomain.java
index 192eabe..8635b4b 100644
--- a/opends/src/server/org/opends/server/synchronization/plugin/SynchronizationDomain.java
+++ b/opends/src/server/org/opends/server/synchronization/plugin/SynchronizationDomain.java
@@ -139,7 +139,6 @@
private short serverId;
- private BooleanConfigAttribute receiveStatusStub;
private int listenerThreadNumber = 10;
private boolean receiveStatus = true;
@@ -157,16 +156,18 @@
private InternalClientConnection conn =
InternalClientConnection.getRootConnection();
- static String CHANGELOG_SERVER_ATTR = "ds-cfg-changelog-server";
- static String BASE_DN_ATTR = "ds-cfg-synchronization-dn";
- static String SERVER_ID_ATTR = "ds-cfg-directory-server-id";
- static String RECEIVE_STATUS = "ds-cfg-receive-status";
- static String MAX_RECEIVE_QUEUE = "ds-cfg-max-receive-queue";
- static String MAX_RECEIVE_DELAY = "ds-cfg-max-receive-delay";
- static String MAX_SEND_QUEUE = "ds-cfg-max-send-queue";
- static String MAX_SEND_DELAY = "ds-cfg-max-send-delay";
- static String WINDOW_SIZE = "ds-cfg-window-size";
- static String HEARTBEAT_INTERVAL = "ds-cfg-heartbeat-interval";
+ private boolean solveConflictFlag = true;
+
+ static final String CHANGELOG_SERVER_ATTR = "ds-cfg-changelog-server";
+ static final String BASE_DN_ATTR = "ds-cfg-synchronization-dn";
+ static final String SERVER_ID_ATTR = "ds-cfg-directory-server-id";
+ static final String RECEIVE_STATUS = "ds-cfg-receive-status";
+ static final String MAX_RECEIVE_QUEUE = "ds-cfg-max-receive-queue";
+ static final String MAX_RECEIVE_DELAY = "ds-cfg-max-receive-delay";
+ static final String MAX_SEND_QUEUE = "ds-cfg-max-send-queue";
+ static final String MAX_SEND_DELAY = "ds-cfg-max-send-delay";
+ static final String WINDOW_SIZE = "ds-cfg-window-size";
+ static final String HEARTBEAT_INTERVAL = "ds-cfg-heartbeat-interval";
private static final StringConfigAttribute changelogStub =
new StringConfigAttribute(CHANGELOG_SERVER_ATTR,
@@ -180,6 +181,10 @@
new DNConfigAttribute(BASE_DN_ATTR, "synchronization base DN",
true, false, false);
+ private static final BooleanConfigAttribute receiveStatusStub =
+ new BooleanConfigAttribute(RECEIVE_STATUS, "receive status", false);
+
+
/**
* The set of time units that will be used for expressing the heartbeat
* interval.
@@ -251,14 +256,33 @@
baseDN = baseDn.activeValue();
configAttributes.add(baseDn);
+ /*
+ * Modify conflicts are solved for all suffixes but the cn=schema suffix
+ * because we don't want to store extra information in the schema
+ * ldif files.
+ * This has no negative impact because the changes on schema should
+ * not produce conflicts.
+ */
+ try
+ {
+ if (baseDN.compareTo(DN.decode("cn=schema")) == 0)
+ {
+ solveConflictFlag = false;
+ }
+ else
+ {
+ solveConflictFlag = true;
+ }
+ } catch (DirectoryException e1)
+ {
+ // never happens because "cn=schema" is a valid DN
+ }
+
state = new PersistentServerState(baseDN);
- state.loadState();
/*
* Read the Receive Status.
*/
- receiveStatusStub = new BooleanConfigAttribute(RECEIVE_STATUS,
- "receive status", false);
BooleanConfigAttribute receiveStatusAttr = (BooleanConfigAttribute)
configEntry.getConfigAttribute(receiveStatusStub);
if (receiveStatusAttr != null)
@@ -712,6 +736,8 @@
// so this is not a synchronization operation.
ChangeNumber changeNumber = generateChangeNumber(modifyOperation);
String modifiedEntryUUID = Historical.getEntryUuid(modifiedEntry);
+ if (modifiedEntryUUID == null)
+ modifiedEntryUUID = modifyOperation.getEntryDN().toString();
ctx = new ModifyContext(changeNumber, modifiedEntryUUID);
modifyOperation.setAttachment(SYNCHROCONTEXT, ctx);
}
@@ -719,7 +745,8 @@
{
String modifiedEntryUUID = ctx.getEntryUid();
String currentEntryUUID = Historical.getEntryUuid(modifiedEntry);
- if (!currentEntryUUID.equals(modifiedEntryUUID))
+ if ((currentEntryUUID != null) &&
+ (!currentEntryUUID.equals(modifiedEntryUUID)))
{
/*
* The current modified entry is not the same entry as the one on
@@ -1119,15 +1146,6 @@
}
/**
- * Get the DN where the ServerState is stored.
- * @return The DN where the ServerState is stored.
- */
- public DN getServerStateDN()
- {
- return state.getServerStateDn();
- }
-
- /**
* Get the name of the changelog server to which this domain is currently
* connected.
*
@@ -1827,4 +1845,14 @@
{
return broker.getNumLostConnections();
}
+
+ /**
+ * Check if the domain solve conflicts.
+ *
+ * @return a boolean indicating if the domain should sove conflicts.
+ */
+ public boolean solveConflict()
+ {
+ return solveConflictFlag;
+ }
}
diff --git a/opends/src/server/org/opends/server/types/Schema.java b/opends/src/server/org/opends/server/types/Schema.java
index ddc5531..8eda996 100644
--- a/opends/src/server/org/opends/server/types/Schema.java
+++ b/opends/src/server/org/opends/server/types/Schema.java
@@ -188,6 +188,9 @@
// file.
private long youngestModificationTime;
+ // The Synchronization State.
+ private LinkedHashSet<AttributeValue> synchronizationState = null;
+
/**
@@ -3030,8 +3033,35 @@
dupSchema.objectClassSet.addAll(objectClassSet);
dupSchema.oldestModificationTime = oldestModificationTime;
dupSchema.youngestModificationTime = youngestModificationTime;
+ if (synchronizationState != null)
+ {
+ dupSchema.synchronizationState =
+ new LinkedHashSet<AttributeValue>(synchronizationState);
+ }
return dupSchema;
}
+
+
+ /**
+ * Retrieves the Synchronization state for this schema.
+ *
+ * @return The Synchronization state for this schema.
+ */
+ public LinkedHashSet<AttributeValue> getSynchronizationState()
+ {
+ return synchronizationState;
+ }
+
+ /**
+ * Sets the Synchronization state for this schema.
+ *
+ * @param values Synchronization state for this schema.
+ */
+ public void setSynchronizationState(
+ LinkedHashSet<AttributeValue> values)
+ {
+ synchronizationState = values;
+ }
}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/api/ConfigurableComponentTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/api/ConfigurableComponentTestCase.java
index efbbead..0aceb29 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/api/ConfigurableComponentTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/api/ConfigurableComponentTestCase.java
@@ -137,8 +137,12 @@
DN configEntryDN = c.getConfigurableComponentEntryDN();
ConfigEntry configEntry = DirectoryServer.getConfigEntry(configEntryDN);
- ArrayList<String> unacceptableReasons = new ArrayList<String>();
- assertTrue(c.hasAcceptableConfiguration(configEntry, unacceptableReasons));
+ if (configEntry != null)
+ {
+ ArrayList<String> unacceptableReasons = new ArrayList<String>();
+ assertTrue(c.hasAcceptableConfiguration(configEntry,
+ unacceptableReasons));
+ }
}
}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/SchemaSynchronizationTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/SchemaSynchronizationTest.java
new file mode 100644
index 0000000..6215ca6
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/SchemaSynchronizationTest.java
@@ -0,0 +1,237 @@
+/*
+ * 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
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * 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
+ *
+ *
+ * Portions Copyright 2007 Sun Microsystems, Inc.
+ */
+package org.opends.server.synchronization;
+
+import static org.opends.server.loggers.Error.logError;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.List;
+
+import org.opends.server.TestCaseUtils;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.core.ModifyOperation;
+import org.opends.server.core.Operation;
+import org.opends.server.protocols.internal.InternalClientConnection;
+import org.opends.server.protocols.ldap.LDAPModification;
+import org.opends.server.synchronization.common.ChangeNumber;
+import org.opends.server.synchronization.plugin.ChangelogBroker;
+import org.opends.server.synchronization.protocol.ModifyMsg;
+import org.opends.server.synchronization.protocol.SynchronizationMessage;
+import org.opends.server.types.Attribute;
+import org.opends.server.types.AttributeType;
+import org.opends.server.types.AttributeValue;
+import org.opends.server.types.DN;
+import org.opends.server.types.ErrorLogCategory;
+import org.opends.server.types.ErrorLogSeverity;
+import org.opends.server.types.Modification;
+import org.opends.server.types.ModificationType;
+import org.opends.server.types.ResultCode;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+/**
+ * Test for the schema synchronization.
+ */
+public class SchemaSynchronizationTest extends SynchronizationTestCase
+{
+
+ ArrayList<Modification> rcvdMods = null;
+
+ /**
+ * Set up the environment for performing the tests in this Class.
+ * synchronization
+ *
+ * @throws Exception
+ * If the environment could not be set up.
+ */
+ @BeforeClass
+ public void setUp() throws Exception
+ {
+ // This test suite depends on having the schema available.
+ TestCaseUtils.startServer();
+
+ // Disable schema check
+ schemaCheck = DirectoryServer.checkSchema();
+ DirectoryServer.setCheckSchema(false);
+
+ // Create an internal connection
+ connection = InternalClientConnection.getRootConnection();
+
+ // top level synchro provider
+ String synchroStringDN = "cn=Synchronization Providers,cn=config";
+
+ // Multimaster Synchro plugin
+ synchroPluginStringDN = "cn=Multimaster Synchronization, "
+ + synchroStringDN;
+ String synchroPluginLdif = "dn: "
+ + synchroPluginStringDN
+ + "\n"
+ + "objectClass: top\n"
+ + "objectClass: ds-cfg-synchronization-provider\n"
+ + "ds-cfg-synchronization-provider-enabled: true\n"
+ + "ds-cfg-synchronization-provider-class: org.opends.server.synchronization.MultimasterSynchronization\n";
+ synchroPluginEntry = TestCaseUtils.entryFromLdifString(synchroPluginLdif);
+
+ // Change log
+ String changeLogStringDN = "cn=Changelog Server, " + synchroPluginStringDN;
+ String changeLogLdif = "dn: " + changeLogStringDN + "\n"
+ + "objectClass: top\n"
+ + "objectClass: ds-cfg-synchronization-changelog-server-config\n"
+ + "cn: Changelog Server\n" + "ds-cfg-changelog-port: 8989\n"
+ + "ds-cfg-changelog-server-id: 1\n";
+ changeLogEntry = TestCaseUtils.entryFromLdifString(changeLogLdif);
+
+ // suffix synchronized
+ String synchroServerLdif = "dn: cn=example, " + synchroPluginStringDN + "\n"
+ + "objectClass: top\n"
+ + "objectClass: ds-cfg-synchronization-provider-config\n"
+ + "cn: example\n"
+ + "ds-cfg-synchronization-dn: cn=schema\n"
+ + "ds-cfg-changelog-server: localhost:8989\n"
+ + "ds-cfg-directory-server-id: 1\n";
+ synchroServerEntry = TestCaseUtils.entryFromLdifString(synchroServerLdif);
+
+ configureSynchronization();
+ }
+
+ /**
+ * Checks that changes done to the schema are pushed to the changelog
+ * clients.
+ */
+ @Test()
+ public void pushSchemaChange() throws Exception
+ {
+ logError(ErrorLogCategory.SYNCHRONIZATION,
+ ErrorLogSeverity.NOTICE,
+ "Starting synchronization test : pushSchemaChange ", 1);
+
+ final DN baseDn = DN.decode("cn=schema");
+
+ ChangelogBroker broker =
+ openChangelogSession(baseDn, (short) 2, 100, 8989, 1000, true);
+
+ try
+ {
+ // Modify the schema
+ AttributeType attrType =
+ DirectoryServer.getAttributeType("attributetypes", true);
+ LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>();
+ values.add(new AttributeValue(attrType, "( 2.5.44.77.33 NAME 'dummy' )"));
+ Attribute attr = new Attribute(attrType, "attributetypes", values);
+ List<Modification> mods = new ArrayList<Modification>();
+ Modification mod = new Modification(ModificationType.ADD, attr);
+ mods.add(mod);
+ ModifyOperation modOp = new ModifyOperation(connection,
+ InternalClientConnection.nextOperationID(), InternalClientConnection
+ .nextMessageID(), null, baseDn, mods);
+ modOp.setInternalOperation(true);
+ modOp.run();
+
+ ResultCode code = modOp.getResultCode();
+ assertTrue(code.equals(ResultCode.SUCCESS),
+ "The original operation failed");
+
+ // See if the client has received the msg
+ SynchronizationMessage msg = broker.receive();
+
+ assertTrue(msg instanceof ModifyMsg,
+ "The received synchronization message is not a MODIFY msg");
+ ModifyMsg modMsg = (ModifyMsg) msg;
+
+ Operation receivedOp = modMsg.createOperation(connection);
+ assertTrue(DN.decode(modMsg.getDn()).compareTo(baseDn) == 0,
+ "The received message is not for cn=schema");
+
+ assertTrue(receivedOp instanceof ModifyOperation,
+ "The received synchronization message is not a MODIFY msg");
+ ModifyOperation receivedModifyOperation = (ModifyOperation) receivedOp;
+
+ List<LDAPModification> rcvdRawMods =
+ receivedModifyOperation.getRawModifications();
+
+ this.rcvdMods = new ArrayList<Modification>();
+ for (LDAPModification m : rcvdRawMods)
+ {
+ this.rcvdMods.add(m.toModification());
+ }
+
+ assertTrue(this.rcvdMods.contains(mod),
+ "The received mod does not contain the original change");
+
+ /*
+ * Now cleanup the schema for the next test
+ */
+ mod = new Modification(ModificationType.DELETE, attr);
+ mods.clear();
+ mods.add(mod);
+ modOp = new ModifyOperation(connection,
+ InternalClientConnection.nextOperationID(), InternalClientConnection
+ .nextMessageID(), null, baseDn, mods);
+ modOp.setInternalOperation(true);
+ modOp.run();
+
+ code = modOp.getResultCode();
+ assertTrue(code.equals(ResultCode.SUCCESS),
+ "The original operation failed");
+ }
+ finally
+ {
+ broker.stop();
+ }
+ }
+
+ /**
+ * Checks that changes to the schema pushed to the changelog
+ * are received and correctly replayed by synchronization plugin.
+ */
+ @Test(dependsOnMethods = { "pushSchemaChange" })
+ public void replaySchemaChange() throws Exception
+ {
+ logError(ErrorLogCategory.SYNCHRONIZATION,
+ ErrorLogSeverity.NOTICE,
+ "Starting synchronization test : pushSchemaChange ", 1);
+
+ final DN baseDn = DN.decode("cn=schema");
+
+ ChangelogBroker broker =
+ openChangelogSession(baseDn, (short) 2, 100, 8989, 1000, true);
+
+ ModifyMsg modMsg = new ModifyMsg(new ChangeNumber((long) 10, 1, (short) 2),
+ baseDn, rcvdMods, "cn=schema");
+ broker.publish(modMsg);
+
+ boolean found = checkEntryHasAttribute(baseDn, "attributetypes",
+ "( 2.5.44.77.33 NAME 'dummy' )",
+ 10000, true);
+
+ if (found == false)
+ fail("The modification has not been correctly replayed.");
+ }
+}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/StressTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/StressTest.java
index 65f3eaf..1228864 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/StressTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/StressTest.java
@@ -65,8 +65,7 @@
import org.testng.annotations.Test;
/**
- * Test the contructors, encoders and decoders of the synchronization AckMsg,
- * ModifyMsg, ModifyDnMsg, AddMsg and Delete Msg
+ * Stress test for the synchronization code using the ChangelogBroker API.
*/
public class StressTest extends SynchronizationTestCase
{
@@ -109,7 +108,6 @@
final DN baseDn = DN.decode("ou=People,dc=example,dc=com");
final int TOTAL_MESSAGES = 1000;
- cleanEntries();
ChangelogBroker broker =
openChangelogSession(baseDn, (short) 18, 100, 8989, 5000, true);
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/SynchronizationTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/SynchronizationTestCase.java
index 4ad583d..3d69c5c 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/SynchronizationTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/SynchronizationTestCase.java
@@ -129,9 +129,12 @@
int port, int timeout, boolean emptyOldChanges)
throws Exception, SocketException
{
- PersistentServerState state = new PersistentServerState(baseDn);
+ ServerState state;
if (emptyOldChanges)
- state.loadState();
+ state = new PersistentServerState(baseDn);
+ else
+ state = new ServerState();
+
ChangelogBroker broker = new ChangelogBroker(
state, baseDn, serverId, 0, 0, 0, 0, window_size, 0);
ArrayList<String> servers = new ArrayList<String>(1);
@@ -188,9 +191,12 @@
boolean emptyOldChanges)
throws Exception, SocketException
{
- PersistentServerState state = new PersistentServerState(baseDn);
+ ServerState state;
if (emptyOldChanges)
- state.loadState();
+ state = new PersistentServerState(baseDn);
+ else
+ state = new ServerState();
+
ChangelogBroker broker = new ChangelogBroker(
state, baseDn, serverId, maxRcvQueue, 0,
maxSendQueue, 0, window_size, 0);
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/UpdateOperationTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/UpdateOperationTest.java
index 031de12..c80b565 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/UpdateOperationTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/UpdateOperationTest.java
@@ -123,7 +123,6 @@
entry.getUserAttributes(), entry.getOperationalAttributes());
addOp.setInternalOperation(true);
addOp.run();
- entryList.add(entry.getDN());
}
baseUUID = getEntryUUID(DN.decode("ou=People,dc=example,dc=com"));
@@ -819,6 +818,7 @@
{
return new Object[][] { { false }, {true} };
}
+
/**
* Tests done using directly the ChangelogBroker interface.
*/
@@ -839,19 +839,6 @@
ChangeNumberGenerator gen = new ChangeNumberGenerator((short) 27, 0);
/*
- * loop receiving update until there is nothing left
- * to make sure that message from previous tests have been consumed.
- */
- try
- {
- while (true)
- {
- broker.receive();
- }
- }
- catch (Exception e)
- {}
- /*
* Test that operations done on this server are sent to the
* changelog server and forwarded to our changelog broker session.
*/
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/plugin/PersistentStateTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/plugin/PersistentStateTest.java
new file mode 100644
index 0000000..cbe6672
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/plugin/PersistentStateTest.java
@@ -0,0 +1,125 @@
+/*
+ * 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
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * 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
+ *
+ *
+ * Portions Copyright 2006 Sun Microsystems, Inc.
+ */
+package org.opends.server.synchronization.plugin;
+
+import static org.testng.Assert.assertEquals;
+
+import org.opends.server.TestCaseUtils;
+import org.opends.server.core.AddOperation;
+import org.opends.server.protocols.internal.InternalClientConnection;
+import org.opends.server.synchronization.SynchronizationTestCase;
+import org.opends.server.synchronization.common.ChangeNumber;
+import org.opends.server.synchronization.common.ChangeNumberGenerator;
+import org.opends.server.types.DN;
+import org.opends.server.types.Entry;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test the PersistentServerState class.
+ */
+public class PersistentStateTest extends SynchronizationTestCase
+{
+ /**
+ * Set up the environment for performing the tests in this suite.
+ *
+ * @throws Exception
+ * If the environment could not be set up.
+ */
+ @BeforeClass
+ public void setUp() throws Exception
+ {
+ /*
+ * start the server and create the dc=exmaple,dc=xom entry if it does not
+ * exist yet.
+ */
+ TestCaseUtils.startServer();
+ String topEntry = "dn: dc=example,dc=com\n" + "objectClass: top\n"
+ + "objectClass: domain\n";
+
+ connection = InternalClientConnection.getRootConnection();
+ Entry entry = TestCaseUtils.entryFromLdifString(topEntry);
+ AddOperation addOp = new AddOperation(connection,
+ InternalClientConnection.nextOperationID(), InternalClientConnection
+ .nextMessageID(), null, entry.getDN(), entry.getObjectClasses(),
+ entry.getUserAttributes(), entry.getOperationalAttributes());
+ addOp.setInternalOperation(true);
+ addOp.run();
+ }
+
+ /**
+ * The suffix for which we want to test the PersistentServerState class.
+ */
+ @DataProvider(name = "suffix")
+ public Object[][] suffixData() {
+ return new Object[][] {
+ {"dc=example,dc=com"},
+ {"cn=schema"}
+ };
+ }
+
+ /**
+ * Test that the PersistentServerState class is able to store and
+ * retrieve ServerState to persistent storage.
+ */
+ @Test(dataProvider = "suffix")
+ public void persistenServerStateTest(String dn)
+ throws Exception
+ {
+ /*
+ * Create a new PersitentServerState,
+ * update it with 2 new ChangeNumbers with 2 different server Ids
+ * save it
+ *
+ * Then creates a new PersistentServerState and check that the
+ * 2 ChangeNumbers have been saved in this new PersistentServerState.
+ */
+ DN baseDn = DN.decode(dn);
+ PersistentServerState state = new PersistentServerState(baseDn);
+ ChangeNumberGenerator gen1 = new ChangeNumberGenerator((short) 1, state);
+ ChangeNumberGenerator gen2 = new ChangeNumberGenerator((short) 2, state);
+
+ ChangeNumber cn1 = gen1.NewChangeNumber();
+ ChangeNumber cn2 = gen2.NewChangeNumber();
+
+ state.update(cn1);
+ state.update(cn2);
+
+ state.save();
+
+ PersistentServerState stateSaved = new PersistentServerState(baseDn);
+ ChangeNumber cn1Saved = stateSaved.getMaxChangeNumber((short) 1);
+ ChangeNumber cn2Saved = stateSaved.getMaxChangeNumber((short) 2);
+
+ assertEquals(cn1Saved, cn1,
+ "cn1 has not been saved or loaded correctly for " + dn);
+ assertEquals(cn2Saved, cn2,
+ "cn2 has not been saved or loaded correctly for " + dn);
+
+ }
+}
--
Gitblit v1.10.0