From 540ea316e77eb38f09a74b07365964c2a1161d8e Mon Sep 17 00:00:00 2001
From: Yannick Lecaillez <yannick.lecaillez@forgerock.com>
Date: Tue, 31 Mar 2015 16:02:26 +0000
Subject: [PATCH] OPENDJ-1199: Reduce memory/disk usage of JE backend (variable length encoding for EntryIDSet)
---
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/State.java | 181 ++++++++++++++++++++++++++++++++++-----------
1 files changed, 136 insertions(+), 45 deletions(-)
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/State.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/State.java
index a46a9b0..caac24e 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/State.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/State.java
@@ -26,10 +26,19 @@
*/
package org.opends.server.backends.pluggable;
+import static org.forgerock.util.Reject.*;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumSet;
+
+import org.forgerock.opendj.ldap.ByteSequence;
import org.forgerock.opendj.ldap.ByteString;
import org.opends.server.backends.pluggable.spi.ReadableTransaction;
import org.opends.server.backends.pluggable.spi.StorageRuntimeException;
import org.opends.server.backends.pluggable.spi.TreeName;
+import org.opends.server.backends.pluggable.spi.UpdateFunction;
import org.opends.server.backends.pluggable.spi.WriteableTransaction;
import org.opends.server.util.StaticUtils;
@@ -39,8 +48,35 @@
*/
class State extends DatabaseContainer
{
- private static final ByteString falseBytes = ByteString.wrap(new byte[] { 0x00 });
- private static final ByteString trueBytes = ByteString.wrap(new byte[] { 0x01 });
+
+ /**
+ * Use COMPACTED serialization for new indexes.
+ * @see {@link EntryIDSet.EntryIDSetCompactCodec}
+ */
+ private static final Collection<IndexFlag> DEFAULT_FLAGS = Collections.unmodifiableCollection(Arrays
+ .asList(IndexFlag.COMPACTED));
+
+ /**
+ * Bit-field containing possible flags that an index can have
+ * When adding flags, ensure that its value fits on a single bit.
+ */
+ static enum IndexFlag
+ {
+ TRUSTED(0x01),
+
+ /**
+ * Use compact encoding for indexes' ID storage.
+ */
+ COMPACTED(0x02);
+
+ static final EnumSet<IndexFlag> ALL_FLAGS = EnumSet.allOf(IndexFlag.class);
+
+ final byte mask;
+
+ IndexFlag(int mask) {
+ this.mask=(byte) mask;
+ }
+ }
/**
* Create a new State object.
@@ -52,18 +88,102 @@
super(name);
}
+ private ByteString keyForIndex(TreeName indexTreeName) throws StorageRuntimeException
+ {
+ return ByteString.wrap(StaticUtils.getBytes(indexTreeName.toString()));
+ }
+
/**
- * Return the key associated with the index in the state database.
- *
- * @param index The index we need the key for.
- * @return the key
+ * Fetch index flags from the database.
+ * @param txn The database transaction or null if none.
+ * @param indexTreeName The tree's name of the index
+ * @return The flags of the index in the database or an empty set if no index has no flags.
+ * @throws NullPointerException if tnx or index is null
* @throws StorageRuntimeException If an error occurs in the database.
*/
- private ByteString keyForIndex(DatabaseContainer index)
- throws StorageRuntimeException
+ EnumSet<IndexFlag> getIndexFlags(ReadableTransaction txn, TreeName indexTreeName) throws StorageRuntimeException {
+ checkNotNull(txn, "txn must not be null");
+ checkNotNull(indexTreeName, "indexTreeName must not be null");
+
+ final ByteString value = txn.read(getName(), keyForIndex(indexTreeName));
+ return decodeFlagsOrGetDefault(value);
+ }
+
+ /**
+ * Ensure that the specified flags are set for the given index
+ * @param txn a non null database transaction
+ * @param index The index storing the trusted state info.
+ * @return true if the flags have been updated
+ * @throws NullPointerException if txn, index or flags is null
+ * @throws StorageRuntimeException If an error occurs in the database.
+ */
+ boolean addFlagsToIndex(WriteableTransaction txn, TreeName indexTreeName, final IndexFlag... flags)
{
- String shortName = index.getName().toString();
- return ByteString.wrap(StaticUtils.getBytes(shortName));
+ checkNotNull(txn, "txn must not be null");
+ checkNotNull(indexTreeName, "indexTreeName must not be null");
+ checkNotNull(flags, "flags must not be null");
+
+ return txn.update(getName(), keyForIndex(indexTreeName), new UpdateFunction()
+ {
+ @Override
+ public ByteSequence computeNewValue(ByteSequence oldValue)
+ {
+ final EnumSet<IndexFlag> currentFlags = decodeFlagsOrGetDefault(oldValue);
+ currentFlags.addAll(Arrays.asList(flags));
+ return encodeFlags(currentFlags);
+ }
+ });
+ }
+
+ private EnumSet<IndexFlag> decodeFlagsOrGetDefault(ByteSequence sequence) {
+ if ( sequence == null ) {
+ return EnumSet.copyOf(DEFAULT_FLAGS);
+ } else {
+ final EnumSet<IndexFlag> indexState = EnumSet.noneOf(IndexFlag.class);
+ final byte indexValue = sequence.byteAt(0);
+ for (IndexFlag state : IndexFlag.ALL_FLAGS)
+ {
+ if ((indexValue & state.mask) == state.mask)
+ {
+ indexState.add(state);
+ }
+ }
+ return indexState;
+ }
+ }
+
+ private ByteString encodeFlags(EnumSet<IndexFlag> flags) {
+ byte value = 0;
+ for(IndexFlag flag : flags) {
+ value |= flag.mask;
+ }
+ return ByteString.valueOf(new byte[] { value });
+ }
+
+
+ /**
+ * Ensure that the specified flags are not set for the given index
+ * @param txn a non null database transaction
+ * @param index The index storing the trusted state info.
+ * @return The flags of the index
+ * @throws NullPointerException if txn, index or flags is null
+ * @throws StorageRuntimeException If an error occurs in the database.
+ */
+ void removeFlagsFromIndex(WriteableTransaction txn, TreeName indexTreeName, final IndexFlag... flags) {
+ checkNotNull(txn, "txn must not be null");
+ checkNotNull(indexTreeName, "indexTreeName must not be null");
+ checkNotNull(flags, "flags must not be null");
+
+ txn.update(getName(), keyForIndex(indexTreeName), new UpdateFunction()
+ {
+ @Override
+ public ByteSequence computeNewValue(ByteSequence oldValue)
+ {
+ final EnumSet<IndexFlag> currentFlags = decodeFlagsOrGetDefault(oldValue);
+ currentFlags.removeAll(Arrays.asList(flags));
+ return encodeFlags(currentFlags);
+ }
+ });
}
/**
@@ -72,43 +192,14 @@
* @param txn a non null database transaction
* @param index The index storing the trusted state info.
* @return true if the entry was removed, false if it was not.
+ * @throws NullPointerException if txn, index is null
* @throws StorageRuntimeException If an error occurs in the database.
*/
- boolean removeIndexTrustState(WriteableTransaction txn, DatabaseContainer index) throws StorageRuntimeException
+ boolean deleteRecord(WriteableTransaction txn, TreeName indexTreeName) throws StorageRuntimeException
{
- ByteString key = keyForIndex(index);
- return txn.delete(getName(), key);
+ checkNotNull(txn, "txn must not be null");
+ checkNotNull(indexTreeName, "indexTreeName must not be null");
+
+ return txn.delete(getName(), keyForIndex(indexTreeName));
}
-
- /**
- * Fetch index state from the database.
- * @param txn a non null database transaction
- * @param index The index storing the trusted state info.
- * @return The trusted state of the index in the database.
- * @throws StorageRuntimeException If an error occurs in the database.
- */
- boolean getIndexTrustState(ReadableTransaction txn, DatabaseContainer index)
- throws StorageRuntimeException
- {
- ByteString key = keyForIndex(index);
- ByteString value = txn.read(getName(), key);
-
- return value != null && value.equals(trueBytes);
- }
-
- /**
- * Put index state to database.
- * @param txn a non null database transaction
- * @param index The index storing the trusted state info.
- * @param trusted The state value to put into the database.
- * @throws StorageRuntimeException If an error occurs in the database.
- */
- void putIndexTrustState(WriteableTransaction txn, DatabaseContainer index, boolean trusted)
- throws StorageRuntimeException
- {
- ByteString key = keyForIndex(index);
-
- txn.put(getName(), key, trusted ? trueBytes : falseBytes);
- }
-
}
--
Gitblit v1.10.0