From b88a555f5a584c355442ee8db6d218c9fe95fa36 Mon Sep 17 00:00:00 2001
From: Yannick Lecaillez <ylecaillez@forgerock.com>
Date: Tue, 17 Nov 2015 10:16:04 +0000
Subject: [PATCH] OPENDJ-2393: Possible index corruption

---
 opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/VLVIndex.java |   35 +++++++++++++++++++++++------------
 1 files changed, 23 insertions(+), 12 deletions(-)

diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/VLVIndex.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/VLVIndex.java
index f133792..a1ff2a7 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/VLVIndex.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/VLVIndex.java
@@ -37,7 +37,6 @@
 import java.util.LinkedList;
 import java.util.List;
 import java.util.TreeSet;
-import java.util.concurrent.atomic.AtomicInteger;
 
 import org.forgerock.i18n.LocalizableMessage;
 import org.forgerock.i18n.slf4j.LocalizedLogger;
@@ -86,16 +85,17 @@
  * "tie-breaker" and ensures that keys correspond to one and only one entry. This ensures that all
  * tree updates can be performed using lock-free operations.
  */
-@SuppressWarnings("javadoc")
 class VLVIndex extends AbstractTree implements ConfigurationChangeListener<BackendVLVIndexCfg>, Closeable
 {
+  private static final ByteString COUNT_KEY = ByteString.valueOfUtf8("nbRecords");
+
   private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
 
   /** The VLV vlvIndex configuration. */
   private BackendVLVIndexCfg config;
 
-  /** The cached count of entries in this index. */
-  private final AtomicInteger count = new AtomicInteger(0);
+  /** The count of entries in this index. */
+  private final ShardedCounter counter;
 
   private DN baseDN;
   private SearchScope scope;
@@ -116,7 +116,7 @@
       ConfigException
   {
     super(new TreeName(entryContainer.getTreePrefix(), "vlv." + config.getName()));
-
+    this.counter = new ShardedCounter(new TreeName(entryContainer.getTreePrefix(), "counter.vlv." + config.getName()));
     this.config = config;
     this.baseDN = config.getBaseDN();
     this.scope = convertScope(config.getScope());
@@ -163,9 +163,15 @@
   }
 
   @Override
-  void open0(final WriteableTransaction txn) throws StorageRuntimeException
+  void afterOpen(final WriteableTransaction txn) throws StorageRuntimeException
   {
-    count.set((int) txn.getRecordCount(getName()));
+    counter.open(txn, true);
+  }
+
+  @Override
+  void beforeDelete(WriteableTransaction txn) throws StorageRuntimeException
+  {
+    counter.delete(txn);
   }
 
   @Override
@@ -438,13 +444,13 @@
       {
         txn.put(getName(), nextAddedKey, toValue());
         nextAddedKey = nextOrNull(ai);
-        count.incrementAndGet();
+        counter.addCount(txn, COUNT_KEY, 1);
       }
       else
       {
         txn.delete(getName(), nextDeletedKey);
         nextDeletedKey = nextOrNull(di);
-        count.decrementAndGet();
+        counter.addCount(txn, COUNT_KEY, -1);
       }
     }
   }
@@ -494,11 +500,16 @@
   {
     try (Cursor<ByteString, ByteString> cursor = txn.openCursor(getName()))
     {
-      final long[] selectedIDs = readRange(cursor, count.get(), debugBuilder);
+      final long[] selectedIDs = readRange(cursor, getEntryCount(txn), debugBuilder);
       return newDefinedSet(selectedIDs);
     }
   }
 
+  private int getEntryCount(final ReadableTransaction txn)
+  {
+    return (int) counter.getCount(txn, COUNT_KEY);
+  }
+
   /**
    * Reads a page of entries from the VLV which includes the nearest entry corresponding to the VLV
    * assertion, {@code beforeCount} entries leading up to the nearest entry, and {@code afterCount}
@@ -508,7 +519,7 @@
       final SearchOperation searchOperation, final VLVRequestControl vlvRequest)
       throws DirectoryException
   {
-    final int currentCount = count.get();
+    final int currentCount = getEntryCount(txn);
     final int beforeCount = vlvRequest.getBeforeCount();
     final int afterCount = vlvRequest.getAfterCount();
     final ByteString assertion = vlvRequest.getGreaterThanOrEqualAssertion();
@@ -611,7 +622,7 @@
   private EntryIDSet evaluateVLVRequestByOffset(final ReadableTransaction txn, final SearchOperation searchOperation,
       final VLVRequestControl vlvRequest, final StringBuilder debugBuilder) throws DirectoryException
   {
-    final int currentCount = count.get();
+    final int currentCount = getEntryCount(txn);
     int beforeCount = vlvRequest.getBeforeCount();
     int afterCount = vlvRequest.getAfterCount();
     int targetOffset = vlvRequest.getOffset();

--
Gitblit v1.10.0