From 00226e83ae4599836caaaf50e50c264905f12ab4 Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Tue, 22 Feb 2011 14:46:38 +0000
Subject: [PATCH] Fixed issue OPENDJ-50: ECL base object search operations on cn=changelog take a long time if the change log is big https://bugster.forgerock.org/jira/browse/OPENDJ-50
---
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/ExternalChangeLogTest.java | 116 ++++++++------
opends/src/server/org/opends/server/workflowelement/externalchangelog/ECLSearchOperation.java | 357 ++++++++++++++++++++++++-------------------
2 files changed, 262 insertions(+), 211 deletions(-)
diff --git a/opends/src/server/org/opends/server/workflowelement/externalchangelog/ECLSearchOperation.java b/opends/src/server/org/opends/server/workflowelement/externalchangelog/ECLSearchOperation.java
index e2fb03f..5f70266 100644
--- a/opends/src/server/org/opends/server/workflowelement/externalchangelog/ECLSearchOperation.java
+++ b/opends/src/server/org/opends/server/workflowelement/externalchangelog/ECLSearchOperation.java
@@ -87,27 +87,7 @@
import org.opends.server.replication.protocol.StartECLSessionMsg;
import org.opends.server.replication.protocol.UpdateMsg;
import org.opends.server.replication.server.ReplicationServer;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeBuilder;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.Attributes;
-import org.opends.server.types.CancelRequest;
-import org.opends.server.types.CancelResult;
-import org.opends.server.types.CanceledOperationException;
-import org.opends.server.types.Control;
-import org.opends.server.types.DN;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.Entry;
-import org.opends.server.types.FilterType;
-import org.opends.server.types.Modification;
-import org.opends.server.types.ObjectClass;
-import org.opends.server.types.Privilege;
-import org.opends.server.types.RawAttribute;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.SearchFilter;
-import org.opends.server.types.SearchScope;
+import org.opends.server.types.*;
import org.opends.server.types.operation.PostOperationSearchOperation;
import org.opends.server.types.operation.PreOperationSearchOperation;
import org.opends.server.types.operation.SearchEntrySearchOperation;
@@ -137,11 +117,60 @@
*/
private StartECLSessionMsg startECLSessionMsg;
+ //The set of supported controls for this WE
+ private static final HashSet<String> CHANGELOG_SUPPORTED_CONTROLS;
+ static
+ {
+ CHANGELOG_SUPPORTED_CONTROLS = new HashSet<String>(0);
+ CHANGELOG_SUPPORTED_CONTROLS
+ .add(ServerConstants.OID_SERVER_SIDE_SORT_REQUEST_CONTROL);
+ CHANGELOG_SUPPORTED_CONTROLS.add(ServerConstants.OID_VLV_REQUEST_CONTROL);
+ }
+
+
+ // The set of objectclasses that will be used in ECL root entry.
+ private static final HashMap<ObjectClass, String>
+ CHANGELOG_ROOT_OBJECT_CLASSES;
+ static
+ {
+ CHANGELOG_ROOT_OBJECT_CLASSES = new LinkedHashMap<ObjectClass, String>(2);
+
+ ObjectClass topOC = DirectoryServer.getObjectClass(OC_TOP, true);
+ CHANGELOG_ROOT_OBJECT_CLASSES.put(topOC, OC_TOP);
+
+ ObjectClass containerOC = DirectoryServer.getObjectClass("container", true);
+ CHANGELOG_ROOT_OBJECT_CLASSES.put(containerOC, "container");
+ }
+
// The set of objectclasses that will be used in ECL entries.
- private static HashMap<ObjectClass,String> eclObjectClasses;
+ private static final HashMap<ObjectClass, String>
+ CHANGELOG_ENTRY_OBJECT_CLASSES;
+ static
+ {
+ CHANGELOG_ENTRY_OBJECT_CLASSES = new LinkedHashMap<ObjectClass, String>(2);
+
+ ObjectClass topOC = DirectoryServer.getObjectClass(OC_TOP, true);
+ CHANGELOG_ENTRY_OBJECT_CLASSES.put(topOC, OC_TOP);
+
+ ObjectClass eclEntryOC = DirectoryServer.getObjectClass(OC_CHANGELOG_ENTRY,
+ true);
+ CHANGELOG_ENTRY_OBJECT_CLASSES.put(eclEntryOC, OC_CHANGELOG_ENTRY);
+ }
// The associated DN.
- private DN rootBaseDN;
+ private static final DN CHANGELOG_ROOT_DN;
+ static
+ {
+ try
+ {
+ CHANGELOG_ROOT_DN = DN
+ .decode(ServerConstants.DN_EXTERNAL_CHANGELOG_ROOT);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
/**
* The replication server in which the search on ECL is to be performed.
@@ -170,9 +199,6 @@
private ExternalChangeLogSession eclSession;
- // The set of supported controls for this WE
- private HashSet<String> supportedControls;
-
/**
* Creates a new operation that may be used to search for entries in a local
* backend of the Directory Server.
@@ -183,27 +209,6 @@
{
super(search);
- try
- {
- rootBaseDN = DN.decode(ServerConstants.DN_EXTERNAL_CHANGELOG_ROOT);
- }
- catch (Exception e){}
-
- // Construct the set of objectclasses to include in the base monitor entry.
- eclObjectClasses = new LinkedHashMap<ObjectClass,String>(2);
- ObjectClass topOC = DirectoryServer.getObjectClass(OC_TOP, true);
- eclObjectClasses.put(topOC, OC_TOP);
- ObjectClass eclEntryOC = DirectoryServer.getObjectClass(OC_CHANGELOG_ENTRY,
- true);
- eclObjectClasses.put(eclEntryOC, OC_CHANGELOG_ENTRY);
-
-
- // Define an empty sets for the supported controls and features.
- // FIXME:ECL Decide if ServerSideControl and VLV are supported
- supportedControls = new HashSet<String>(0);
- supportedControls.add(ServerConstants.OID_SERVER_SIDE_SORT_REQUEST_CONTROL);
- supportedControls.add(ServerConstants.OID_VLV_REQUEST_CONTROL);
-
ECLWorkflowElement.attachLocalOperation(search, this);
}
@@ -251,15 +256,6 @@
excludedDomains.add(ServerConstants.DN_EXTERNAL_CHANGELOG_ROOT);
startECLSessionMsg.setExcludedDNs(excludedDomains);
- // Test existence of the RS - normally should always be here
- if (replicationServer == null)
- {
- setResultCode(ResultCode.OPERATIONS_ERROR);
- appendErrorMessage(ERR_SEARCH_BASE_DOESNT_EXIST.get(
- String.valueOf(baseDN)));
- break searchProcessing;
- }
-
// Process the search base and filter to convert them from their raw forms
// as provided by the client to the forms required for the rest of the
// search processing.
@@ -269,6 +265,15 @@
break searchProcessing;
}
+ // Test existence of the RS - normally should always be here
+ if (replicationServer == null)
+ {
+ setResultCode(ResultCode.OPERATIONS_ERROR);
+ appendErrorMessage(ERR_SEARCH_BASE_DOESNT_EXIST.get(
+ String.valueOf(baseDN)));
+ break searchProcessing;
+ }
+
// Analyse controls - including the cookie control
try
{
@@ -282,10 +287,10 @@
break searchProcessing;
}
- // Process filter - extract draft change number (seqnum) conditions
+ // Process search parameters to optimize session query.
try
{
- evaluateFilter(startECLSessionMsg, this.getFilter());
+ evaluateSearchParameters(startECLSessionMsg, baseDN, filter);
}
catch (DirectoryException de)
{
@@ -437,6 +442,7 @@
Entry entry;
try
{
+ // FIXME: this is broken (recursive)?
entry = DirectoryServer.getEntry(baseDN);
}
catch (DirectoryException de)
@@ -608,10 +614,10 @@
ECLUpdateMsg update = eclSession.getNextUpdate();
// Return root entry if requested.
- if (!getScope().equals(SearchScope.SINGLE_LEVEL))
+ if (CHANGELOG_ROOT_DN.matchesBaseAndScope(baseDN, getScope()))
{
- Entry entry = createRootEntry(update != null);
- if (matchFilter(entry))
+ final Entry entry = createRootEntry(update != null);
+ if (filter.matchesEntry(entry))
{
if (!returnEntry(entry, null))
{
@@ -622,22 +628,28 @@
}
}
- if (!getScope().equals(SearchScope.BASE_OBJECT))
+ if (baseDN.equals(CHANGELOG_ROOT_DN) && getScope().equals(
+ SearchScope.BASE_OBJECT))
{
- while (update != null)
+ // Only the change log root entry was requested. There is no need to
+ // process other entries.
+ return;
+ }
+
+ // Process change log entries.
+ while (update != null)
+ {
+ // Check for a request to cancel this operation.
+ checkIfCanceled(false);
+
+ if (!buildAndReturnEntry(update))
{
- // Check for a request to cancel this operation.
- checkIfCanceled(false);
-
- if (!buildAndReturnEntry(update))
- {
- // Abandon, Size limit reached.
- abortECLSession = true;
- return;
- }
-
- update = eclSession.getNextUpdate();
+ // Abandon, Size limit reached.
+ abortECLSession = true;
+ return;
}
+
+ update = eclSession.getNextUpdate();
}
}
catch (CanceledOperationException e)
@@ -661,8 +673,7 @@
private boolean supportsControl(String oid)
{
- return ((supportedControls != null) &&
- supportedControls.contains(oid));
+ return CHANGELOG_SUPPORTED_CONTROLS.contains(oid);
}
/**
@@ -675,37 +686,42 @@
* @throws DirectoryException When an errors occurs.
*/
private boolean buildAndReturnEntry(ECLUpdateMsg eclmsg)
- throws DirectoryException
+ throws DirectoryException
{
- Entry entry = null;
-
- // build and filter
- entry = createEntryFromMsg(eclmsg);
- if (matchFilter(entry))
+ final Entry entry = createEntryFromMsg(eclmsg);
+ if (matchScopeAndFilter(entry))
{
- List<Control> controls = new ArrayList<Control>(0);
-
- EntryChangelogNotificationControl clrc
- = new EntryChangelogNotificationControl(
- true,eclmsg.getCookie().toString());
+ List<Control> controls = new ArrayList<Control>(1);
+ EntryChangelogNotificationControl clrc =
+ new EntryChangelogNotificationControl(
+ true, eclmsg.getCookie().toString());
controls.add(clrc);
return returnEntry(entry, controls);
}
return true;
}
+
+
/**
* Test if the provided entry matches the filter, base and scope.
- * @param entry The provided entry
+ *
+ * @param entry
+ * The provided entry
* @return whether the entry matches.
- * @throws DirectoryException When a problem occurs.
+ * @throws DirectoryException
+ * When a problem occurs.
*/
- private boolean matchFilter(Entry entry)
- throws DirectoryException
+ private boolean matchScopeAndFilter(Entry entry) throws DirectoryException
{
- boolean baseScopeMatch = entry.matchesBaseAndScope(getBaseDN(), getScope());
- boolean filterMatch = getFilter().matchesEntry(entry);
- return (baseScopeMatch && filterMatch);
+ if (entry.matchesBaseAndScope(getBaseDN(), getScope()))
+ {
+ return getFilter().matchesEntry(entry);
+ }
+ else
+ {
+ return false;
+ }
}
/**
@@ -720,7 +736,7 @@
{
Entry clEntry = null;
- // Get the meat fro the ecl msg
+ // Get the meat from the ecl msg
UpdateMsg msg = eclmsg.getUpdateMsg();
if (msg instanceof AddMsg)
@@ -857,18 +873,6 @@
*/
private Entry createRootEntry(boolean hasSubordinates)
{
- HashMap<ObjectClass,String> oclasses =
- new LinkedHashMap<ObjectClass,String>(3);
-
- // Objectclass
- HashMap<ObjectClass,String> rootObjectClasses =
- new LinkedHashMap<ObjectClass,String>(2);
- ObjectClass topOC = DirectoryServer.getObjectClass(OC_TOP, true);
- rootObjectClasses.put(topOC, OC_TOP);
- ObjectClass containerOC = DirectoryServer.getObjectClass("container", true);
- rootObjectClasses.put(containerOC, "container");
- oclasses.putAll(rootObjectClasses);
-
// Attributes.
HashMap<AttributeType,List<Attribute>> userAttrs =
new LinkedHashMap<AttributeType,List<Attribute>>();
@@ -897,31 +901,28 @@
// TODO:numSubordinates
// hasSubordinates
- if (hasSubordinates)
- {
- aType = DirectoryServer.getAttributeType("hassubordinates");
- if (aType == null)
- aType = DirectoryServer.getDefaultAttributeType("hasSubordinates");
- a = Attributes.create("hasSubordinates", "true");
- attrList = Collections.singletonList(a);
- if (aType.isOperational())
- operationalAttrs.put(aType, attrList);
- else
- userAttrs.put(aType, attrList);
- }
+ aType = DirectoryServer.getAttributeType("hassubordinates");
+ if (aType == null)
+ aType = DirectoryServer.getDefaultAttributeType("hasSubordinates");
+ a = Attributes.create("hasSubordinates", Boolean.toString(hasSubordinates));
+ attrList = Collections.singletonList(a);
+ if (aType.isOperational())
+ operationalAttrs.put(aType, attrList);
+ else userAttrs.put(aType, attrList);
// entryDN
aType = DirectoryServer.getAttributeType("entrydn");
if (aType == null)
aType = DirectoryServer.getDefaultAttributeType("entryDN");
- a = Attributes.create("entryDN", rootBaseDN.toNormalizedString());
+ a = Attributes.create("entryDN", CHANGELOG_ROOT_DN.toNormalizedString());
attrList = Collections.singletonList(a);
if (aType.isOperational())
operationalAttrs.put(aType, attrList);
else
userAttrs.put(aType, attrList);
- Entry e = new Entry(this.rootBaseDN, oclasses, userAttrs, operationalAttrs);
+ Entry e = new Entry(CHANGELOG_ROOT_DN, CHANGELOG_ROOT_OBJECT_CLASSES,
+ userAttrs, operationalAttrs);
return e;
}
@@ -965,25 +966,17 @@
if (draftChangenumber == 0)
{
// Draft uncompat mode
- dnString = "replicationcsn="+ changeNumber +"," + serviceID
- + "," + ServerConstants.DN_EXTERNAL_CHANGELOG_ROOT;
+ dnString = "replicationCSN=" + changeNumber + "," + serviceID + ","
+ + ServerConstants.DN_EXTERNAL_CHANGELOG_ROOT;
}
else
{
// Draft compat mode
- dnString = "changenumber="+ draftChangenumber + "," +
- ServerConstants.DN_EXTERNAL_CHANGELOG_ROOT;
+ dnString = "changeNumber=" + draftChangenumber + ","
+ + ServerConstants.DN_EXTERNAL_CHANGELOG_ROOT;
}
// Objectclass
- HashMap<ObjectClass,String> oClasses =
- new LinkedHashMap<ObjectClass,String>(3);
- oClasses.putAll(eclObjectClasses);
-
- ObjectClass extensibleObjectOC =
- DirectoryServer.getObjectClass(OC_EXTENSIBLE_OBJECT_LC, true);
- oClasses.put(extensibleObjectOC, OC_EXTENSIBLE_OBJECT);
-
HashMap<AttributeType,List<Attribute>> uAttrs =
new LinkedHashMap<AttributeType,List<Attribute>>();
@@ -995,8 +988,9 @@
// subSchemaSubentry
aType = DirectoryServer.getAttributeType(ATTR_SUBSCHEMA_SUBENTRY_LC);
if (aType == null)
- aType = DirectoryServer.getDefaultAttributeType(ATTR_SUBSCHEMA_SUBENTRY_LC);
- Attribute a = Attributes.create(ATTR_SUBSCHEMA_SUBENTRY_LC,
+ aType = DirectoryServer
+ .getDefaultAttributeType(ATTR_SUBSCHEMA_SUBENTRY_LC);
+ Attribute a = Attributes.create(aType,
ConfigConstants.DN_DEFAULT_SCHEMA_ROOT);
List<Attribute> attrList = Collections.singletonList(a);
if (aType.isOperational())
@@ -1008,7 +1002,7 @@
aType = DirectoryServer.getAttributeType("numsubordinates");
if (aType == null)
aType = DirectoryServer.getDefaultAttributeType("numSubordinates");
- a = Attributes.create("numSubordinates", "0");
+ a = Attributes.create(aType, "0");
attrList = Collections.singletonList(a);
if (aType.isOperational())
operationalAttrs.put(aType, attrList);
@@ -1019,7 +1013,7 @@
aType = DirectoryServer.getAttributeType("hassubordinates");
if (aType == null)
aType = DirectoryServer.getDefaultAttributeType("hasSubordinates");
- a = Attributes.create("hasSubordinates", "false");
+ a = Attributes.create(aType, "false");
attrList = Collections.singletonList(a);
if (aType.isOperational())
operationalAttrs.put(aType, attrList);
@@ -1030,7 +1024,7 @@
aType = DirectoryServer.getAttributeType("entrydn");
if (aType == null)
aType = DirectoryServer.getDefaultAttributeType("entryDN");
- a = Attributes.create("entryDN", dnString);
+ a = Attributes.create(aType, dnString);
attrList = Collections.singletonList(a);
if (aType.isOperational())
operationalAttrs.put(aType, attrList);
@@ -1041,8 +1035,8 @@
// ECL Changelog draft change number
if((aType = DirectoryServer.getAttributeType("changenumber")) == null)
- aType = DirectoryServer.getDefaultAttributeType("changenumber");
- a = Attributes.create("changenumber", String.valueOf(draftChangenumber));
+ aType = DirectoryServer.getDefaultAttributeType("changeNumber");
+ a = Attributes.create(aType, String.valueOf(draftChangenumber));
attrList = new ArrayList<Attribute>(1);
attrList.add(a);
if(aType.isOperational())
@@ -1052,7 +1046,7 @@
//
if((aType = DirectoryServer.getAttributeType("changetime")) == null)
- aType = DirectoryServer.getDefaultAttributeType("changetime");
+ aType = DirectoryServer.getDefaultAttributeType("changeTime");
SimpleDateFormat dateFormat;
dateFormat = new SimpleDateFormat(DATE_FORMAT_GMT_TIME);
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); // ??
@@ -1075,7 +1069,7 @@
//
if((aType = DirectoryServer.getAttributeType("changetype")) == null)
- aType = DirectoryServer.getDefaultAttributeType("changetype");
+ aType = DirectoryServer.getDefaultAttributeType("changeType");
a = Attributes.create(aType, changetype);
attrList = new ArrayList<Attribute>(1);
attrList.add(a);
@@ -1086,7 +1080,7 @@
//
if((aType = DirectoryServer.getAttributeType("targetdn")) == null)
- aType = DirectoryServer.getDefaultAttributeType("targetdn");
+ aType = DirectoryServer.getDefaultAttributeType("targetDN");
a = Attributes.create(aType, targetDN.toNormalizedString());
attrList = new ArrayList<Attribute>(1);
attrList.add(a);
@@ -1098,7 +1092,7 @@
// NON REQUESTED attributes
if((aType = DirectoryServer.getAttributeType("replicationcsn")) == null)
- aType = DirectoryServer.getDefaultAttributeType("replicationcsn");
+ aType = DirectoryServer.getDefaultAttributeType("replicationCSN");
a = Attributes.create(aType, changeNumber.toString());
attrList = new ArrayList<Attribute>(1);
attrList.add(a);
@@ -1109,7 +1103,7 @@
//
if((aType = DirectoryServer.getAttributeType("replicaidentifier")) == null)
- aType = DirectoryServer.getDefaultAttributeType("replicaidentifier");
+ aType = DirectoryServer.getDefaultAttributeType("replicaIdentifier");
a = Attributes.create(aType, Integer.toString(changeNumber.getServerId()));
attrList = new ArrayList<Attribute>(1);
attrList.add(a);
@@ -1146,7 +1140,7 @@
clearLDIFchanges.substring(start_val_cr+2, end_val_cr);
if((aType =
- DirectoryServer.getAttributeType("changeInitiatorsName")) == null)
+ DirectoryServer.getAttributeType("changeinitiatorsname")) == null)
aType =
DirectoryServer.getDefaultAttributeType("changeInitiatorsName");
a = Attributes.create(aType, creatorsName);
@@ -1196,7 +1190,7 @@
clearLDIFchanges.substring(start_val_cr, end_val_cr);
if((aType =
- DirectoryServer.getAttributeType("changeInitiatorsName")) == null)
+ DirectoryServer.getAttributeType("changeinitiatorsname")) == null)
aType =
DirectoryServer.getDefaultAttributeType("changeInitiatorsName");
a = Attributes.create(aType, modifiersName);
@@ -1221,7 +1215,7 @@
if (changetype.equals("delete") && (delInitiatorsName!=null))
{
- if((aType = DirectoryServer.getAttributeType("changeInitiatorsName"))
+ if((aType = DirectoryServer.getAttributeType("changeinitiatorsname"))
== null)
aType = DirectoryServer.getDefaultAttributeType("changeInitiatorsName");
a = Attributes.create(aType, delInitiatorsName);
@@ -1236,7 +1230,7 @@
if (targetUUID != null)
{
if((aType = DirectoryServer.getAttributeType("targetentryuuid")) == null)
- aType = DirectoryServer.getDefaultAttributeType("targetentryuuid");
+ aType = DirectoryServer.getDefaultAttributeType("targetEntryUUID");
a = Attributes.create(aType, targetUUID);
attrList = new ArrayList<Attribute>(1);
attrList.add(a);
@@ -1249,7 +1243,7 @@
{
// compat mode
if((aType = DirectoryServer.getAttributeType("targetuniqueid")) == null)
- aType = DirectoryServer.getDefaultAttributeType("targetuniqueid");
+ aType = DirectoryServer.getDefaultAttributeType("targetUniqueID");
String dseeValue = null;
try
{
@@ -1283,7 +1277,7 @@
}
if((aType = DirectoryServer.getAttributeType("changelogcookie")) == null)
- aType = DirectoryServer.getDefaultAttributeType("changelogcookie");
+ aType = DirectoryServer.getDefaultAttributeType("changeLogCookie");
a = Attributes.create(aType, cookie);
attrList = new ArrayList<Attribute>(1);
attrList.add(a);
@@ -1319,7 +1313,7 @@
// at the end build the CL entry to be returned
Entry cle = new Entry(
DN.decode(dnString),
- eclObjectClasses,
+ CHANGELOG_ENTRY_OBJECT_CLASSES,
uAttrs,
operationalAttrs);
@@ -1592,20 +1586,65 @@
* on attributes that can be optimized in the ECL.
* When found, populate the provided StartECLSessionMsg.
* @param startCLmsg the startCLMsg to be populated.
+ * @param baseDN the provided search baseDN.
* @param sf the provided search filter.
* @throws DirectoryException when an exception occurs.
*/
- public static void evaluateFilter(StartECLSessionMsg startCLmsg,
- SearchFilter sf)
- throws DirectoryException
+ public static void evaluateSearchParameters(StartECLSessionMsg startCLmsg,
+ DN baseDN, SearchFilter sf) throws DirectoryException
{
- StartECLSessionMsg msg = evaluateFilter2(sf);
+ // Select whether to use the DN or the filter.
+ switch (baseDN.getNumComponents())
+ {
+ case 1:
+ // cn=changelog - use user provided search filter.
+ break;
+ case 2:
+ // changeNumber=xxx,cn=changelog - draft ECL - use faked up equality
+ // filter.
+
+ // The DN could also be a new ECL <service-id>,cn=changelog so be sure it
+ // is draft ECL.
+ RDN rdn = baseDN.getRDN();
+
+ AttributeType at = DirectoryServer.getAttributeType("changenumber");
+ if (at == null)
+ {
+ at = DirectoryServer.getDefaultAttributeType("changeNumber");
+ }
+
+ AttributeValue av = rdn.getAttributeValue(at);
+ if (av != null)
+ {
+ sf = SearchFilter.createEqualityFilter(at, av);
+ }
+ break;
+ default:
+ // replicationCSN=xxx,<service-id>,cn=changelog - new ECL - use faked up
+ // equality filter.
+ rdn = baseDN.getRDN();
+
+ at = DirectoryServer.getAttributeType("replicationcsn");
+ if (at == null)
+ {
+ at = DirectoryServer.getDefaultAttributeType("replicationCSN");
+ }
+
+ av = rdn.getAttributeValue(at);
+ if (av != null)
+ {
+ sf = SearchFilter.createEqualityFilter(at, av);
+ }
+ break;
+ }
+
+ StartECLSessionMsg msg = evaluateSearchParameters2(sf);
startCLmsg.setFirstDraftChangeNumber(msg.getFirstDraftChangeNumber());
startCLmsg.setLastDraftChangeNumber(msg.getLastDraftChangeNumber());
startCLmsg.setChangeNumber(msg.getChangeNumber());
}
- private static StartECLSessionMsg evaluateFilter2(SearchFilter sf)
+ private static StartECLSessionMsg evaluateSearchParameters2(SearchFilter sf)
throws DirectoryException
{
StartECLSessionMsg startCLmsg = new StartECLSessionMsg();
@@ -1665,8 +1704,8 @@
// Here is the only binary operation we know how to optimize
Collection<SearchFilter> comps = sf.getFilterComponents();
SearchFilter sfs[] = comps.toArray(new SearchFilter[0]);
- StartECLSessionMsg m1 = evaluateFilter2(sfs[0]);
- StartECLSessionMsg m2 = evaluateFilter2(sfs[1]);
+ StartECLSessionMsg m1 = evaluateSearchParameters2(sfs[0]);
+ StartECLSessionMsg m2 = evaluateSearchParameters2(sfs[1]);
int l1 = m1.getLastDraftChangeNumber();
int l2 = m2.getLastDraftChangeNumber();
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/ExternalChangeLogTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/ExternalChangeLogTest.java
index bb3b792..ea2ed87 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/ExternalChangeLogTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/ExternalChangeLogTest.java
@@ -23,6 +23,7 @@
*
*
* Copyright 2006-2010 Sun Microsystems, Inc.
+ * Portions copyright 2011 ForgeRock AS
*/
package org.opends.server.replication;
@@ -58,10 +59,6 @@
import java.util.SortedSet;
import java.util.TreeSet;
-import static org.opends.server.loggers.ErrorLogger.logError;
-import org.opends.messages.Category;
-import org.opends.messages.Message;
-import org.opends.messages.Severity;
import org.opends.server.TestCaseUtils;
import org.opends.server.api.Backend;
import org.opends.server.api.ConnectionHandler;
@@ -179,7 +176,7 @@
List<Control> NO_CONTROL = null;
private int brokerSessionTimeout = 5000;
-
+
private int maxWindow = 100;
/**
* Set up the environment for performing the tests in this Class.
@@ -223,12 +220,12 @@
@Test(enabled=true)
public void ECLReplicationServerTest()
{
- // No RSDomain created yet => RS only case => ECL is not a supported
+ // No RSDomain created yet => RS only case => ECL is not a supported
ECLIsNotASupportedSuffix();
// Following test does not create RSDomain (only broker) but want to test
// ECL .. so let's enable ECl manually
- // Now that we tested that ECl is not available
+ // Now that we tested that ECl is not available
try
{
ECLWorkflowElement wfe = (ECLWorkflowElement)
@@ -243,7 +240,7 @@
+ stackTraceToSingleLineString(de));
}
- // Test all types of ops.
+ // Test all types of ops.
ECLAllOps(); // Do not clean the db for the next test
// First and last should be ok whenever a request has been done or not
@@ -676,10 +673,10 @@
DN baseDn2 = DN.decode(TEST_ROOT_DN_STRING2);
SortedSet<String> replServers = new TreeSet<String>();
replServers.add("localhost:"+replicationServerPort);
-
+
DomainFakeCfg domainConf =
new DomainFakeCfg(baseDn2, 1602, replServers);
- ExternalChangelogDomainFakeCfg eclCfg =
+ ExternalChangelogDomainFakeCfg eclCfg =
new ExternalChangelogDomainFakeCfg(true, null);
domainConf.setExternalChangelogDomain(eclCfg);
LDAPReplicationDomain domain2 =
@@ -739,7 +736,7 @@
}
}
- eclCfg =
+ eclCfg =
new ExternalChangelogDomainFakeCfg(false, null);
domainConf.setExternalChangelogDomain(eclCfg);
domain2.applyConfigurationChange(domainConf);
@@ -1127,15 +1124,15 @@
attributes,
controls,
null);
-
+
waitOpResult(searchOp, ResultCode.UNWILLING_TO_PERFORM);
assertEquals(searchOp.getSearchEntries().size(), 0);
assertTrue(searchOp.getErrorMessage().toString().equals(
ERR_INVALID_COOKIE_SYNTAX.get().toString()),
searchOp.getErrorMessage().toString());
-
+
// Test unknown domain in provided cookie
- // This case seems to be very hard to obtain in the real life
+ // This case seems to be very hard to obtain in the real life
// (how to remove a domain from a RS topology ?)
// let's do a very quick test here.
String newCookie = lastCookie + "o=test6:";
@@ -1157,7 +1154,7 @@
attributes,
controls,
null);
-
+
waitOpResult(searchOp, ResultCode.UNWILLING_TO_PERFORM);
assertEquals(searchOp.getSearchEntries().size(), 0);
assertTrue(searchOp.getErrorMessage().toString().startsWith(
@@ -1184,7 +1181,7 @@
attributes,
controls,
null);
-
+
waitOpResult(searchOp, ResultCode.UNWILLING_TO_PERFORM);
assertEquals(searchOp.getSearchEntries().size(), 0);
String expectedError = ERR_RESYNC_REQUIRED_MISSING_DOMAIN_IN_PROVIDED_COOKIE
@@ -1254,7 +1251,7 @@
// Sleep longer than this delay - the changelog will be trimmed
Thread.sleep(1000);
-
+
// ---
// 2. Now set up a very short purge delay on the replication changelogs
// so that this test can play with a trimmed changelog.
@@ -1336,9 +1333,9 @@
// Assert ECL is empty since replication changelog has been trimmed
assertEquals(searchOp.getSearchEntries().size(), 0);
-
+
// ---
- // 5. Assert that a request with an "old" cookie - one that refers to
+ // 5. Assert that a request with an "old" cookie - one that refers to
// changes that have been removed by the replication changelog trimming
// returns the appropriate error.
@@ -1381,7 +1378,7 @@
// And reset changelog purge delay for the other tests.
d1.setPurgeDelay(15 * 1000);
d2.setPurgeDelay(15 * 1000);
-
+
}
catch(Exception e)
{
@@ -3262,7 +3259,7 @@
NO_CONTROL,
null);
waitOpResult(searchOp, ResultCode.SUCCESS);
- assertEquals(searchOp.getSearchEntries().size(),
+ assertEquals(searchOp.getSearchEntries().size(),
lastDraftChangeNumber-firstDraftChangeNumber+1);
if (searchOp.getSearchEntries() != null)
{
@@ -3394,29 +3391,31 @@
{
StartECLSessionMsg startCLmsg = new StartECLSessionMsg();
+ DN baseDN = DN.decode("cn=changelog");
+
//
- ECLSearchOperation.evaluateFilter(startCLmsg,
- SearchFilter.createFilterFromString("(objectclass=*)"));
+ ECLSearchOperation.evaluateSearchParameters(startCLmsg,
+ baseDN, SearchFilter.createFilterFromString("(objectclass=*)"));
assertEquals(startCLmsg.getFirstDraftChangeNumber(),-1);
assertEquals(startCLmsg.getLastDraftChangeNumber(),-1);
//
- ECLSearchOperation.evaluateFilter(startCLmsg,
- SearchFilter.createFilterFromString("(changenumber>=2)"));
+ ECLSearchOperation.evaluateSearchParameters(startCLmsg,
+ baseDN, SearchFilter.createFilterFromString("(changenumber>=2)"));
assertEquals(startCLmsg.getFirstDraftChangeNumber(),2);
assertEquals(startCLmsg.getLastDraftChangeNumber(),-1);
//
- ECLSearchOperation.evaluateFilter(startCLmsg,
- SearchFilter.createFilterFromString("(&(changenumber>=2)(changenumber<=5))"));
+ ECLSearchOperation.evaluateSearchParameters(startCLmsg,
+ baseDN, SearchFilter.createFilterFromString("(&(changenumber>=2)(changenumber<=5))"));
assertEquals(startCLmsg.getFirstDraftChangeNumber(),2);
assertEquals(startCLmsg.getLastDraftChangeNumber(),5);
//
try
{
- ECLSearchOperation.evaluateFilter(startCLmsg,
- SearchFilter.createFilterFromString("(&(changenumber>=2)(changenumber<+5))"));
+ ECLSearchOperation.evaluateSearchParameters(startCLmsg,
+ baseDN, SearchFilter.createFilterFromString("(&(changenumber>=2)(changenumber<+5))"));
assertTrue((startCLmsg.getFirstDraftChangeNumber()==1));
}
catch(DirectoryException de)
@@ -3425,38 +3424,51 @@
}
//
- ECLSearchOperation.evaluateFilter(startCLmsg,
- SearchFilter.createFilterFromString("(&(dc=x)(&(changenumber>=2)(changenumber<=5)))"));
+ ECLSearchOperation.evaluateSearchParameters(startCLmsg,
+ baseDN, SearchFilter.createFilterFromString("(&(dc=x)(&(changenumber>=2)(changenumber<=5)))"));
assertEquals(startCLmsg.getFirstDraftChangeNumber(),2);
assertEquals(startCLmsg.getLastDraftChangeNumber(),5);
- ECLSearchOperation.evaluateFilter(startCLmsg,
- SearchFilter.createFilterFromString("(&(&(changenumber>=3)(changenumber<=4))(&(|(dc=y)(dc=x))(&(changenumber>=2)(changenumber<=5))))"));
+ ECLSearchOperation.evaluateSearchParameters(startCLmsg,
+ baseDN, SearchFilter.createFilterFromString("(&(&(changenumber>=3)(changenumber<=4))(&(|(dc=y)(dc=x))(&(changenumber>=2)(changenumber<=5))))"));
assertEquals(startCLmsg.getFirstDraftChangeNumber(),3);
assertEquals(startCLmsg.getLastDraftChangeNumber(),4);
//
- ECLSearchOperation.evaluateFilter(startCLmsg,
- SearchFilter.createFilterFromString("(|(objectclass=*)(&(changenumber>=2)(changenumber<=5)))"));
+ ECLSearchOperation.evaluateSearchParameters(startCLmsg,
+ baseDN, SearchFilter.createFilterFromString("(|(objectclass=*)(&(changenumber>=2)(changenumber<=5)))"));
assertEquals(startCLmsg.getFirstDraftChangeNumber(),-1);
assertEquals(startCLmsg.getLastDraftChangeNumber(),-1);
//
- ECLSearchOperation.evaluateFilter(startCLmsg,
- SearchFilter.createFilterFromString("(changenumber=8)"));
+ ECLSearchOperation.evaluateSearchParameters(startCLmsg,
+ baseDN, SearchFilter.createFilterFromString("(changenumber=8)"));
assertEquals(startCLmsg.getFirstDraftChangeNumber(),8);
assertEquals(startCLmsg.getLastDraftChangeNumber(),8);
//
ChangeNumberGenerator gen = new ChangeNumberGenerator( 1, 0);
ChangeNumber changeNumber1 = gen.newChangeNumber();
- ECLSearchOperation.evaluateFilter(startCLmsg,
- SearchFilter.createFilterFromString("(replicationcsn="+changeNumber1+")"));
+ ECLSearchOperation.evaluateSearchParameters(startCLmsg,
+ baseDN, SearchFilter.createFilterFromString("(replicationcsn="+changeNumber1+")"));
assertEquals(startCLmsg.getFirstDraftChangeNumber(),-1);
assertEquals(startCLmsg.getLastDraftChangeNumber(),-1);
assertEquals(startCLmsg.getChangeNumber(), changeNumber1);
+ // Use change number as base object.
+ baseDN = DN.decode("changeNumber=8,cn=changelog");
+ //
+ ECLSearchOperation.evaluateSearchParameters(startCLmsg,
+ baseDN, SearchFilter.createFilterFromString("(objectclass=*)"));
+ assertEquals(startCLmsg.getFirstDraftChangeNumber(),8);
+ assertEquals(startCLmsg.getLastDraftChangeNumber(),8);
+
+ // The base DN should take preference.
+ ECLSearchOperation.evaluateSearchParameters(startCLmsg,
+ baseDN, SearchFilter.createFilterFromString("(changenumber>=2)"));
+ assertEquals(startCLmsg.getFirstDraftChangeNumber(),8);
+ assertEquals(startCLmsg.getLastDraftChangeNumber(),8);
}
catch(Exception e)
{
@@ -3563,7 +3575,7 @@
null);
assertEquals(getAttributeValue(resultEntry, "lastExternalChangelogCookie"),
null);
-
+
}
}
}
@@ -3673,7 +3685,7 @@
ServerState ss = new ServerState();
ss.update(cn1);
-
+
// From state/cn1(exclusive) to cn1 (inclusive) : 0 change
count = rsdtest.getEligibleCount(ss, cn1);
assertEquals(count, 0);
@@ -3708,7 +3720,7 @@
boolean perfs=false;
if (perfs)
{
-
+
// number of msgs used by the test
int maxMsg = 999999;
@@ -3722,7 +3734,7 @@
delMsg =
new DeleteMsg("uid="+tn+i+"," + TEST_ROOT_DN_STRING, cnx,
user1entryUUID);
- server01.publish(delMsg);
+ server01.publish(delMsg);
}
sleep(1000);
debugInfo(tn, "Perfs test in compat - search lastChangeNumber");
@@ -3742,7 +3754,7 @@
assertEquals(limitss[1], maxMsg);
long t2 = TimeThread.getTime();
debugInfo(tn, "Perfs - " + maxMsg + " counted in (ms):" + (t2 - t1));
-
+
try
{
// search on 'cn=changelog'
@@ -3866,7 +3878,7 @@
SortedSet<AttributeType> eclInclude = new TreeSet<AttributeType>();
eclInclude.add(DirectoryServer.getAttributeType("sn"));
eclInclude.add(DirectoryServer.getAttributeType("roomnumber"));
- ExternalChangelogDomainFakeCfg eclCfg =
+ ExternalChangelogDomainFakeCfg eclCfg =
new ExternalChangelogDomainFakeCfg(true, eclInclude);
domainConf.setExternalChangelogDomain(eclCfg);
// Set a Changetime heartbeat interval low enough (less than default
@@ -3885,7 +3897,7 @@
// on o=test3,sid=1703 include attrs set to : 'objectclass'
eclInclude = new TreeSet<AttributeType>();
eclInclude.add(DirectoryServer.getAttributeType("objectclass"));
- eclCfg =
+ eclCfg =
new ExternalChangelogDomainFakeCfg(true, eclInclude);
domainConf.setExternalChangelogDomain(eclCfg);
// Set a Changetime heartbeat interval low enough (less than default
@@ -3900,7 +3912,7 @@
new DomainFakeCfg(baseDn2, 1704, replServers);
eclInclude = new TreeSet<AttributeType>();
eclInclude.add(DirectoryServer.getAttributeType("cn"));
- eclCfg =
+ eclCfg =
new ExternalChangelogDomainFakeCfg(true, eclInclude);
domainConf.setExternalChangelogDomain(eclCfg);
// Set a Changetime heartbeat interval low enough (less than default
@@ -3957,7 +3969,7 @@
modOpBasis.run();
waitOpResult(modOpBasis, ResultCode.SUCCESS);
- // mod 'telephonenumber' of robert (o=test3)
+ // mod 'telephonenumber' of robert (o=test3)
builder = new AttributeBuilder("telephonenumber");
builder.add("555555");
mod =
@@ -4086,14 +4098,14 @@
if (domain3 != null)
MultimasterReplication.deleteDomain(baseDn3);
- removeTestBackend2(backend3);
+ removeTestBackend2(backend3);
}
catch(Exception e) {}
}
debugInfo(tn, "Ending test with success");
}
-
+
private void waitOpResult(AbstractOperation operation,
ResultCode expectedResult)
{
@@ -4104,8 +4116,8 @@
sleep(50);
ii++;
if (ii>10)
- assertEquals(operation.getResultCode(), expectedResult,
- operation.getErrorMessage().toString());
+ assertEquals(operation.getResultCode(), expectedResult,
+ operation.getErrorMessage().toString());
}
}
}
--
Gitblit v1.10.0