From 641e89ef0e15c9edde69f3b8cf82c7dd5f68687a Mon Sep 17 00:00:00 2001
From: Yannick Lecaillez <ylecaillez@forgerock.com>
Date: Wed, 30 Sep 2015 14:28:07 +0000
Subject: [PATCH] OPENDJ-2016: New on disk merge import strategy based on storage engine.
---
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/DN2ID.java | 149 ++++++++++++++++++++++++++++++++++++-------------
1 files changed, 108 insertions(+), 41 deletions(-)
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/DN2ID.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/DN2ID.java
index 4db360b..4f64dd1 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/DN2ID.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/DN2ID.java
@@ -29,10 +29,16 @@
import static org.opends.server.backends.pluggable.CursorTransformer.*;
import static org.opends.server.backends.pluggable.DnKeyFormat.*;
+import java.util.LinkedList;
+import java.util.NoSuchElementException;
+
import org.forgerock.opendj.ldap.ByteSequence;
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.ByteStringBuilder;
+import org.forgerock.opendj.ldap.Functions;
import org.forgerock.util.Function;
+import org.forgerock.util.promise.NeverThrowsException;
+import org.opends.server.backends.pluggable.OnDiskMergeImporter.SequentialCursorDecorator;
import org.opends.server.backends.pluggable.spi.Cursor;
import org.opends.server.backends.pluggable.spi.ReadableTransaction;
import org.opends.server.backends.pluggable.spi.SequentialCursor;
@@ -41,7 +47,6 @@
import org.opends.server.backends.pluggable.spi.UpdateFunction;
import org.opends.server.backends.pluggable.spi.WriteableTransaction;
import org.opends.server.types.DN;
-import org.opends.server.types.DirectoryException;
/**
* This class represents the dn2id index, which has one record
@@ -51,25 +56,18 @@
@SuppressWarnings("javadoc")
class DN2ID extends AbstractTree
{
- private static final Function<ByteString, Void, DirectoryException> TO_VOID_KEY =
- new Function<ByteString, Void, DirectoryException>()
- {
- @Override
- public Void apply(ByteString value) throws DirectoryException
- {
- return null;
- }
- };
+ private static final Function<ByteString, Void, NeverThrowsException> TO_VOID_KEY = Functions.returns(null);
- private static final CursorTransformer.ValueTransformer<ByteString, ByteString, EntryID, Exception> TO_ENTRY_ID =
- new CursorTransformer.ValueTransformer<ByteString, ByteString, EntryID, Exception>()
- {
- @Override
- public EntryID transform(ByteString key, ByteString value) throws Exception
- {
- return new EntryID(value);
- }
- };
+ private static final CursorTransformer.ValueTransformer<ByteString, ByteString, EntryID, NeverThrowsException>
+ TO_ENTRY_ID =
+ new CursorTransformer.ValueTransformer<ByteString, ByteString, EntryID, NeverThrowsException>()
+ {
+ @Override
+ public EntryID transform(ByteString key, ByteString value)
+ {
+ return new EntryID(value);
+ }
+ };
private final DN baseDN;
@@ -154,6 +152,12 @@
return value != null ? new EntryID(value) : null;
}
+ <V> SequentialCursor<ByteString, ByteString> openCursor(SequentialCursor<ByteString, ByteString> dn2IdCursor,
+ TreeVisitor<V> treeVisitor)
+ {
+ return new TreeVisitorCursor<>(dn2IdCursor, treeVisitor);
+ }
+
Cursor<Void, EntryID> openCursor(ReadableTransaction txn, DN dn)
{
return transformKeysAndValues(openCursor0(txn, dn), TO_VOID_KEY, TO_ENTRY_ID);
@@ -167,11 +171,11 @@
SequentialCursor<Void, EntryID> openChildrenCursor(ReadableTransaction txn, DN dn)
{
- return new ChildrenCursor(openCursor0(txn, dn));
+ return transformKeysAndValues(new ChildrenCursor(openCursor0(txn, dn)), TO_VOID_KEY, TO_ENTRY_ID);
}
SequentialCursor<Void, EntryID> openSubordinatesCursor(ReadableTransaction txn, DN dn) {
- return new SubtreeCursor(openCursor0(txn, dn));
+ return transformKeysAndValues(new SubtreeCursor(openCursor0(txn, dn)), TO_VOID_KEY, TO_ENTRY_ID);
}
/**
@@ -209,7 +213,9 @@
* Decorator overriding the next() behavior to iterate through children of the entry pointed by the given cursor at
* creation.
*/
- private static final class ChildrenCursor extends SequentialCursorForwarding {
+ private static final class ChildrenCursor extends
+ SequentialCursorDecorator<Cursor<ByteString, ByteString>, ByteString, ByteString>
+ {
private final ByteStringBuilder builder;
private final ByteString limit;
private boolean cursorOnParent;
@@ -236,7 +242,7 @@
return isDefined() && delegate.getKey().compareTo(limit) < 0;
}
- private ByteStringBuilder nextSibling()
+ private ByteSequence nextSibling()
{
return builder.clear().append(delegate.getKey()).append((byte) 0x1);
}
@@ -246,7 +252,9 @@
* Decorator overriding the next() behavior to iterate through subordinates of the entry pointed by the given cursor
* at creation.
*/
- private static final class SubtreeCursor extends SequentialCursorForwarding {
+ private static final class SubtreeCursor extends
+ SequentialCursorDecorator<Cursor<ByteString, ByteString>, ByteString, ByteString>
+ {
private final ByteString limit;
SubtreeCursor(Cursor<ByteString, ByteString> delegate)
@@ -262,15 +270,79 @@
}
}
- /**
- * Decorator allowing to partially overrides methods of a given cursor while keeping the default behavior for other
- * methods.
- */
- private static class SequentialCursorForwarding implements SequentialCursor<Void, EntryID> {
- final Cursor<ByteString, ByteString> delegate;
+ /** Keep track of information during the visit. */
+ private static final class ParentInfo<V>
+ {
+ private final ByteString parentDN;
+ private final V visitorData;
- SequentialCursorForwarding(Cursor<ByteString, ByteString> delegate) {
+ ParentInfo(ByteString parentDN, V visitorData)
+ {
+ this.parentDN = parentDN;
+ this.visitorData = visitorData;
+ }
+ }
+
+ /** Allows to visit dn2id tree without exposing internal encoding. */
+ static interface TreeVisitor<V>
+ {
+ V beginParent(EntryID parentID);
+
+ void onChild(V parent, EntryID childID);
+
+ void endParent(V parent);
+ }
+
+ /** Perform dn2id cursoring to expose parent and children to the {@link TreeVisitor} */
+ private static final class TreeVisitorCursor<V> implements SequentialCursor<ByteString, ByteString>
+ {
+ private final SequentialCursor<ByteString, ByteString> delegate;
+ private final LinkedList<ParentInfo<V>> parentsInfoStack;
+ private final TreeVisitor<V> visitor;
+
+ TreeVisitorCursor(SequentialCursor<ByteString, ByteString> delegate, TreeVisitor<V> visitor)
+ {
this.delegate = delegate;
+ this.parentsInfoStack = new LinkedList<>();
+ this.visitor = visitor;
+ }
+
+ @Override
+ public boolean next()
+ {
+ if (delegate.next())
+ {
+ final ByteString dn = delegate.getKey();
+ final EntryID entryID = new EntryID(delegate.getValue());
+ popCompleteParents(dn);
+ notifyChild(entryID);
+ pushNewParent(dn, entryID);
+ return true;
+ }
+ popCompleteParents(DN.NULL_DN.toNormalizedByteString());
+ return false;
+ }
+
+ private void pushNewParent(final ByteString dn, final EntryID entryID)
+ {
+ parentsInfoStack.push(new ParentInfo<>(dn, visitor.beginParent(entryID)));
+ }
+
+ private void notifyChild(final EntryID entryID)
+ {
+ if (!parentsInfoStack.isEmpty())
+ {
+ visitor.onChild(parentsInfoStack.peek().visitorData, entryID);
+ }
+ }
+
+ private void popCompleteParents(ByteString dn)
+ {
+ ParentInfo<V> currentParent;
+ while ((currentParent = parentsInfoStack.peek()) != null && !isChild(currentParent.parentDN, dn))
+ {
+ visitor.endParent(parentsInfoStack.pop().visitorData);
+ }
}
@Override
@@ -280,21 +352,15 @@
}
@Override
- public boolean next()
+ public ByteString getKey() throws NoSuchElementException
{
- return delegate.next();
+ return delegate.getKey();
}
@Override
- public Void getKey()
+ public ByteString getValue() throws NoSuchElementException
{
- return null;
- }
-
- @Override
- public EntryID getValue()
- {
- return new EntryID(delegate.getValue());
+ return delegate.getValue();
}
@Override
@@ -303,4 +369,5 @@
delegate.close();
}
}
+
}
--
Gitblit v1.10.0