From b360a0579e5fcdb487ed7b5dc8fff6a9b1dceb0f Mon Sep 17 00:00:00 2001
From: Ludovic Poitou <ludovic.poitou@forgerock.com>
Date: Fri, 09 Sep 2011 13:24:02 +0000
Subject: [PATCH] Fix for OPENDJ-274. Added detection of modifications with identical ChangeNumber to a Single-Value Attribute. Unit tests added for all cases that were identified as not resulting in the same value in the attribute after replication.
---
opendj-sdk/opends/src/server/org/opends/server/replication/plugin/AttrHistoricalSingle.java | 86 +++++++++++++++++++++++++++++++++++-------
1 files changed, 71 insertions(+), 15 deletions(-)
diff --git a/opendj-sdk/opends/src/server/org/opends/server/replication/plugin/AttrHistoricalSingle.java b/opendj-sdk/opends/src/server/org/opends/server/replication/plugin/AttrHistoricalSingle.java
index c61c6e9..826bacc 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/replication/plugin/AttrHistoricalSingle.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/replication/plugin/AttrHistoricalSingle.java
@@ -23,6 +23,7 @@
*
*
* Copyright 2008-2010 Sun Microsystems, Inc.
+ * Portions Copyright 2011 ForgeRock AS
*/
package org.opends.server.replication.plugin;
@@ -52,6 +53,10 @@
private ChangeNumber addTime = null; // last time when a value was added
private AttributeValue value = null; // last added value
+ // last operation applied. This is only used for multiple mods on the same
+ // single valued attribute in the same modification.
+ private HistAttrModificationKey lastMod = null;
+
/**
* {@inheritDoc}
*/
@@ -99,11 +104,13 @@
case DELETE:
this.deleteTime = changeNumber;
this.value = newValue;
+ lastMod = HistAttrModificationKey.DEL;
break;
case ADD:
this.addTime = changeNumber;
this.value = newValue;
+ lastMod = HistAttrModificationKey.ADD;
break;
case REPLACE:
@@ -111,10 +118,12 @@
{
// REPLACE with null value is actually a DELETE
this.deleteTime = changeNumber;
+ lastMod = HistAttrModificationKey.DEL;
}
else
{
this.deleteTime = addTime = changeNumber;
+ lastMod = HistAttrModificationKey.REPL;
}
this.value = newValue;
break;
@@ -144,21 +153,51 @@
switch (mod.getModificationType())
{
case DELETE:
- if ((changeNumber.newer(addTime)) &&
- ((newValue == null) ||
- ((newValue != null) && (newValue.equals(value))) ||
- (value == null)))
+ if (changeNumber.newer(addTime))
{
- if (changeNumber.newer(deleteTime))
- deleteTime = changeNumber;
- AttributeType type = modAttr.getAttributeType();
- if (!modifiedEntry.hasAttribute(type))
+ if ((newValue == null) ||
+ ((newValue != null) && (newValue.equals(value))) ||
+ (value == null))
+ {
+ if (changeNumber.newer(deleteTime))
+ {
+ deleteTime = changeNumber;
+ }
+ AttributeType type = modAttr.getAttributeType();
+ if (!modifiedEntry.hasAttribute(type))
+ {
+ conflict = true;
+ modsIterator.remove();
+ }
+ else if ((newValue != null) &&
+ (!modifiedEntry.hasValue(type, modAttr.getOptions(), newValue)))
+ {
+ conflict = true;
+ modsIterator.remove();
+ }
+ else
+ {
+ lastMod = HistAttrModificationKey.DEL;
+ }
+ }
+ else
{
conflict = true;
modsIterator.remove();
}
- else if ((newValue != null) &&
- (!modifiedEntry.hasValue(type, modAttr.getOptions(), newValue)))
+ }
+ else if (changeNumber.equals(addTime))
+ {
+ if ((lastMod == HistAttrModificationKey.ADD)
+ || (lastMod == HistAttrModificationKey.REPL))
+ {
+ if (changeNumber.newer(deleteTime))
+ {
+ deleteTime = changeNumber;
+ }
+ lastMod = HistAttrModificationKey.DEL;
+ }
+ else
{
conflict = true;
modsIterator.remove();
@@ -166,8 +205,8 @@
}
else
{
- conflict = true;
- modsIterator.remove();
+ conflict = true;
+ modsIterator.remove();
}
break;
@@ -178,6 +217,7 @@
mod.setModificationType(ModificationType.REPLACE);
addTime = changeNumber;
value = newValue;
+ lastMod = HistAttrModificationKey.REPL;
}
else
{
@@ -187,18 +227,32 @@
// no conflict : don't do anything beside setting the addTime
addTime = changeNumber;
value = newValue;
+ lastMod = HistAttrModificationKey.ADD;
}
else
{
- conflict = true;
- modsIterator.remove();
+ // Case where changeNumber = addTime = deleteTime
+ if (changeNumber.equals(deleteTime)
+ && changeNumber.equals(addTime)
+ && (lastMod == HistAttrModificationKey.DEL))
+ {
+ // No conflict, record the new value.
+ value = newValue;
+ lastMod = HistAttrModificationKey.ADD;
+ }
+ else
+ {
+ conflict = true;
+ modsIterator.remove();
+ }
}
}
break;
case REPLACE:
- if ((changeNumber.older(deleteTime)) && (changeNumber.older(deleteTime)))
+ if ((changeNumber.older(deleteTime))
+ && ((addTime == null) || (changeNumber.older(addTime))))
{
conflict = true;
modsIterator.remove();
@@ -209,12 +263,14 @@
{
value = newValue;
deleteTime = changeNumber;
+ lastMod = HistAttrModificationKey.DEL;
}
else
{
addTime = changeNumber;
value = newValue;
deleteTime = changeNumber;
+ lastMod = HistAttrModificationKey.REPL;
}
}
break;
--
Gitblit v1.10.0