From 1c126204d9add5e14c4ce3d60c9c89b1a5260133 Mon Sep 17 00:00:00 2001
From: pgamba <pgamba@localhost>
Date: Thu, 10 Dec 2009 16:57:24 +0000
Subject: [PATCH] Fix #4395 ECL cookie older than server changelog db trim is not detected
---
opends/src/server/org/opends/server/replication/server/ECLServerHandler.java | 87 ++++++++++++++++++++++++++++++++++++-------
1 files changed, 72 insertions(+), 15 deletions(-)
diff --git a/opends/src/server/org/opends/server/replication/server/ECLServerHandler.java b/opends/src/server/org/opends/server/replication/server/ECLServerHandler.java
index 08d80ed..d6635ea 100644
--- a/opends/src/server/org/opends/server/replication/server/ECLServerHandler.java
+++ b/opends/src/server/org/opends/server/replication/server/ECLServerHandler.java
@@ -686,24 +686,24 @@
boolean allowUnknownDomains)
throws DirectoryException
{
- HashMap<String,ServerState> startStates = new HashMap<String,ServerState>();
+ HashMap<String,ServerState> startStatesFromProvidedCookie =
+ new HashMap<String,ServerState>();
ReplicationServer rs = this.replicationServer;
// Parse the provided cookie and overwrite startState from it.
if ((providedCookie != null) && (providedCookie.length()!=0))
- startStates =
+ startStatesFromProvidedCookie =
MultiDomainServerState.splitGenStateToServerStates(providedCookie);
try
{
- // Now traverse all domains and build all the initial contexts :
- // - the global one : dumpState()
- // - the domain by domain ones : domainCtxts
Iterator<ReplicationServerDomain> rsdi = rs.getDomainIterator();
- // Creates the table that will contain the real-time info by domain.
+ // Creates the table that will contain the real-time info for each
+ // and every domain.
HashSet<DomainContext> tmpSet = new HashSet<DomainContext>();
+ String missingDomains = "";
int i =0;
if (rsdi != null)
{
@@ -738,18 +738,45 @@
}
else
{
- newDomainCtxt.startState = startStates.remove(rsd.getBaseDn());
+ // let's take the start state for this domain from the provided
+ // cookie
+ newDomainCtxt.startState =
+ startStatesFromProvidedCookie.remove(rsd.getBaseDn());
+
if ((providedCookie==null)||(providedCookie.length()==0)
||allowUnknownDomains)
{
+ // when there is no cookie provided in the request,
+ // let's start traversing this domain from the beginning of
+ // what we have in the replication changelog
if (newDomainCtxt.startState == null)
newDomainCtxt.startState = new ServerState();
}
else
+ {
+ // when there is a cookie provided in the request,
if (newDomainCtxt.startState == null)
- throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM,
- ERR_INVALID_COOKIE_FULL_RESYNC_REQUIRED.get(
- "missing " + rsd.getBaseDn()));
+ {
+ missingDomains += (rsd.getBaseDn() + ":;");
+ continue;
+ }
+ else if (!newDomainCtxt.startState.isEmpty())
+ {
+ // when the provided startState is older than the replication
+ // changelogdb start state, it means that the replication
+ // changelog db has been trimed and the cookie is not valid
+ // anymore.
+ if (newDomainCtxt.startState.cover(rsd.getStartState())==false)
+ {
+ // the provided start
+ throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM,
+ ERR_RESYNC_REQUIRED_TOO_OLD_DOMAIN_IN_PROVIDED_COOKIE.get(
+ newDomainCtxt.rsd.getBaseDn()));
+ }
+ }
+ }
+
+ // Set the stop state for the domain from the eligibleCN
newDomainCtxt.stopState = rsd.getEligibleState(eligibleCN);
}
newDomainCtxt.currentState = new ServerState();
@@ -774,18 +801,34 @@
i++;
}
}
- if (!startStates.isEmpty())
+
+ if (missingDomains.length()>0)
{
+ // If there are domain missing in the provided cookie,
+ // the request is rejected and a full resync is required.
throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM,
- ERR_INVALID_COOKIE_FULL_RESYNC_REQUIRED.get(
- "unknown " + startStates.toString()));
+ ERR_RESYNC_REQUIRED_MISSING_DOMAIN_IN_PROVIDED_COOKIE.get(
+ missingDomains + " .Possible cookie:" +
+ (providedCookie + missingDomains)));
+ }
+
+ if (!startStatesFromProvidedCookie.isEmpty())
+ {
+ // After reading all the knows domains from the provided cookie, there
+ // is one (or several) domain that are not currently configured.
+ // This domain has probably been removed or replication disabled on it.
+ // The request is rejected and full resync is required.
+ throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM,
+ ERR_RESYNC_REQUIRED_UNKNOWN_DOMAIN_IN_PROVIDED_COOKIE.get(
+ startStatesFromProvidedCookie.toString()));
}
domainCtxts = tmpSet.toArray(new DomainContext[0]);
// the next record from the DraftCNdb should be the one
startCookie = providedCookie;
- // Initializes all domain with the next(first) elligible message
+ // Initializes each and every domain with the next(first) eligible message
+ // from the domain.
for (int j=0; j<domainCtxts.length; j++)
{
domainCtxts[j].getNextEligibleMessageForDomain(operationId);
@@ -794,6 +837,10 @@
domainCtxts[j].active = false;
}
}
+ catch(DirectoryException de)
+ {
+ throw de;
+ }
catch(Exception e)
{
TRACER.debugCaught(DebugLogLevel.ERROR, e);
@@ -939,8 +986,18 @@
isPersistent = startECLSessionMsg.isPersistent();
lastDraftCN = startECLSessionMsg.getLastDraftChangeNumber();
searchPhase = INIT_PHASE;
- previousCookie = new MultiDomainServerState(
+ try
+ {
+ previousCookie = new MultiDomainServerState(
startECLSessionMsg.getCrossDomainServerState());
+ }
+ catch(Exception e)
+ {
+ TRACER.debugCaught(DebugLogLevel.ERROR, e);
+ throw new DirectoryException(
+ ResultCode.UNWILLING_TO_PERFORM,
+ ERR_INVALID_COOKIE_SYNTAX.get());
+ }
excludedServiceIDs = startECLSessionMsg.getExcludedServiceIDs();
replicationServer.disableEligibility(excludedServiceIDs);
eligibleCN = replicationServer.getEligibleCN();
--
Gitblit v1.10.0