From f4fc21a222c514860b5232cce2d9f890639f5b5a Mon Sep 17 00:00:00 2001
From: Fabio Pistolesi <fabio.pistolesi@forgerock.com>
Date: Mon, 27 Jul 2015 09:38:19 +0000
Subject: [PATCH] OPENDJ-2159 CR-7527 PDB Storage is read-only when using verify-index tool on Windows.

---
 opendj-server-legacy/src/main/java/org/opends/server/backends/pdb/PDBStorage.java |   58 +++++++++++++++++++++++++++++++++++++++++++++-------------
 1 files changed, 45 insertions(+), 13 deletions(-)

diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/pdb/PDBStorage.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/pdb/PDBStorage.java
index cf2eb2d..61ab41f 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/pdb/PDBStorage.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/backends/pdb/PDBStorage.java
@@ -64,6 +64,7 @@
 import org.opends.server.admin.std.server.PDBBackendCfg;
 import org.opends.server.api.Backupable;
 import org.opends.server.api.DiskSpaceMonitorHandler;
+import org.opends.server.backends.pluggable.spi.AccessMode;
 import org.opends.server.backends.pluggable.spi.Cursor;
 import org.opends.server.backends.pluggable.spi.Importer;
 import org.opends.server.backends.pluggable.spi.ReadOnlyStorageException;
@@ -365,12 +366,14 @@
 
   /** Common interface for internal WriteableTransaction implementations. */
   private interface StorageImpl extends WriteableTransaction, Closeable {
+
   }
 
   /** PersistIt implementation of the {@link WriteableTransaction} interface. */
   private final class WriteableStorageImpl implements StorageImpl
   {
     private final Map<TreeName, Exchange> exchanges = new HashMap<>();
+    private final String DUMMY_RECORD = "_DUMMY_RECORD_";
 
     @Override
     public void put(final TreeName treeName, final ByteSequence key, final ByteSequence value)
@@ -462,20 +465,22 @@
     }
 
     @Override
-    public void openTree(final TreeName treeName)
+    public void openTree(final TreeName treeName, boolean createOnDemand)
     {
-      Exchange ex = null;
-      try
+      if (createOnDemand)
       {
-        ex = getNewExchange(treeName, true);
+        openCreateTree(treeName);
       }
-      catch (final PersistitException e)
+      else
       {
-        throw new StorageRuntimeException(e);
-      }
-      finally
-      {
-        db.releaseExchange(ex);
+        try
+        {
+          getExchangeFromCache(treeName);
+        }
+        catch (final PersistitException e)
+        {
+          throw new StorageRuntimeException(e);
+        }
       }
     }
 
@@ -532,6 +537,28 @@
       }
     }
 
+    private void openCreateTree(final TreeName treeName)
+    {
+      Exchange ex = null;
+      try
+      {
+        ex = getNewExchange(treeName, true);
+        // Work around a problem with forced shutdown right after tree creation.
+        // Tree operations are not part of the journal, so force a couple operations to be able to recover.
+        ByteString dummyKey = ByteString.valueOf(DUMMY_RECORD);
+        put(treeName, dummyKey, ByteString.empty());
+        delete(treeName, dummyKey);
+      }
+      catch (final PersistitException e)
+      {
+        throw new StorageRuntimeException(e);
+      }
+      finally
+      {
+        db.releaseExchange(ex);
+      }
+    }
+
     private Exchange getExchangeFromCache(final TreeName treeName) throws PersistitException
     {
       Exchange exchange = exchanges.get(treeName);
@@ -583,8 +610,12 @@
     }
 
     @Override
-    public void openTree(TreeName treeName)
+    public void openTree(TreeName treeName, boolean createOnDemand)
     {
+      if (createOnDemand)
+      {
+        throw new ReadOnlyStorageException();
+      }
       Exchange ex = null;
       try
       {
@@ -592,7 +623,7 @@
       }
       catch (final TreeNotFoundException e)
       {
-        throw new ReadOnlyStorageException();
+        // ignore missing trees.
       }
       catch (final PersistitException e)
       {
@@ -648,7 +679,7 @@
 
   private StorageImpl newStorageImpl() {
     final WriteableStorageImpl writeableStorage = new WriteableStorageImpl();
-    return accessMode.equals(AccessMode.READ_ONLY) ? new ReadOnlyStorageImpl(writeableStorage) : writeableStorage;
+    return accessMode.isWriteable() ? writeableStorage : new ReadOnlyStorageImpl(writeableStorage);
   }
 
   private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
@@ -689,6 +720,7 @@
     dbCfg.setLogFile(new File(backendDirectory, VOLUME_NAME + ".log").getPath());
     dbCfg.setJournalPath(new File(backendDirectory, JOURNAL_NAME).getPath());
     dbCfg.setCheckpointInterval(config.getDBCheckpointerWakeupInterval());
+    // Volume is opened read write because recovery will fail if opened read-only
     dbCfg.setVolumeList(asList(new VolumeSpecification(new File(backendDirectory, VOLUME_NAME).getPath(), null,
         BUFFER_SIZE, 4096, Long.MAX_VALUE / BUFFER_SIZE, 2048, true, false, false)));
     final BufferPoolConfiguration bufferPoolCfg = getBufferPoolCfg(dbCfg);

--
Gitblit v1.10.0