From fa817e5a12f1b0ee574272fe711ed1a96f2b3595 Mon Sep 17 00:00:00 2001
From: Fabio Pistolesi <fabio.pistolesi@forgerock.com>
Date: Fri, 06 Feb 2015 14:51:35 +0000
Subject: [PATCH] OPENDJ-1750 CR-5916 Backup of a Persistit backend generates empty backup set  Fixes the "Empty backup" problem when creating a backup of a pluggable backend. Uses CR-5915 preparatory work to propagate storage information to the backupConfig, to correctly decide which files should belong to a backup. Thanks JN!

---
 opendj3-server-dev/src/server/org/opends/server/backends/persistit/PersistItStorage.java |   16 +++++
 opendj3-server-dev/src/server/org/opends/server/backends/pluggable/BackupManager.java    |   43 ++++++--------
 opendj3-server-dev/src/server/org/opends/server/types/BackupConfig.java                  |   65 +++++++++++++++++----
 opendj3-server-dev/src/server/org/opends/server/backends/pluggable/spi/Storage.java      |    7 ++
 opendj3-server-dev/src/server/org/opends/server/backends/pluggable/BackendImpl.java      |    4 
 5 files changed, 94 insertions(+), 41 deletions(-)

diff --git a/opendj3-server-dev/src/server/org/opends/server/backends/persistit/PersistItStorage.java b/opendj3-server-dev/src/server/org/opends/server/backends/persistit/PersistItStorage.java
index bee6283..7ab9291 100644
--- a/opendj3-server-dev/src/server/org/opends/server/backends/persistit/PersistItStorage.java
+++ b/opendj3-server-dev/src/server/org/opends/server/backends/persistit/PersistItStorage.java
@@ -27,11 +27,11 @@
 
 import static com.persistit.Transaction.CommitPolicy.*;
 import static java.util.Arrays.*;
-
 import static org.opends.messages.JebMessages.*;
 import static org.opends.server.util.StaticUtils.*;
 
 import java.io.File;
+import java.io.FilenameFilter;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -686,6 +686,20 @@
     }
   }
 
+  /** {@inheritDoc} */
+  @Override
+  public FilenameFilter getFilesToBackupFilter()
+  {
+    return new FilenameFilter()
+    {
+      @Override
+      public boolean accept(File d, String name)
+      {
+        return name.startsWith(VOLUME_NAME) && !name.endsWith(".lck");
+      }
+    };
+  }
+
   /*
    * TODO: it would be nice to use the low-level key/value APIs. They seem quite
    * inefficient at the moment for simple byte arrays.
diff --git a/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/BackendImpl.java b/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/BackendImpl.java
index 82af2ca..1c6a0cf 100644
--- a/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/BackendImpl.java
+++ b/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/BackendImpl.java
@@ -759,8 +759,8 @@
     BackupManager backupManager = new BackupManager(getBackendID());
     File parentDir = getFileForPath(cfg.getDBDirectory());
     File backendDir = new File(parentDir, cfg.getBackendId());
-    // Storage storage = newStorageInstance();
-    // backupConfig.setFilesToBackupFilter(storage.getFilesToBackupFilter());
+    Storage storage = newStorageInstance();
+    backupConfig.setFilesToBackupFilter(storage.getFilesToBackupFilter());
     backupManager.createBackup(backendDir, backupConfig);
   }
 
diff --git a/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/BackupManager.java b/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/BackupManager.java
index 3c079e5..16411d1 100644
--- a/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/BackupManager.java
+++ b/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/BackupManager.java
@@ -61,7 +61,7 @@
 import org.opends.server.util.StaticUtils;
 
 /**
- * A backup manager for JE backends.
+ * A backup manager for backends.
  */
 public class BackupManager
 {
@@ -106,7 +106,7 @@
 
 
   /**
-   * Construct a backup manager for a JE backend.
+   * Construct a backup manager for a backend.
    * @param backendID The ID of the backend instance for which a backup
    * manager is required.
    */
@@ -116,11 +116,11 @@
   }
 
   /**
-   * Create a backup of the JE backend.  The backup is stored in a single zip
+   * Create a backup of the backend.  The backup is stored in a single zip
    * file in the backup directory.  If the backup is incremental, then the
-   * first entry in the zip is a text file containing a list of all the JE
+   * first entry in the zip is a text file containing a list of all the
    * log files that are unchanged since the previous backup.  The remaining
-   * zip entries are the JE log files themselves, which, for an incremental,
+   * zip entries are the log files themselves, which, for an incremental,
    * only include those files that have changed.
    * @param backendDir The directory of the backend instance for
    * which the backup is required.
@@ -139,6 +139,7 @@
     boolean         encrypt         = backupConfig.encryptData();
     boolean         hash            = backupConfig.hashData();
     boolean         signHash        = backupConfig.signHash();
+    FilenameFilter  filenameFilter  = backupConfig.getFilesToBackupFilter();
 
 
     HashMap<String,String> backupProperties = new HashMap<String,String>();
@@ -321,17 +322,8 @@
       zipStream.setLevel(Deflater.NO_COMPRESSION);
     }
 
-    // Get a list of all the log files comprising the database.
-    FilenameFilter filenameFilter = new FilenameFilter()
-    {
-      @Override
-      public boolean accept(File d, String name)
-      {
-        return name.endsWith(".jdb");
-      }
-    };
-
     File[] logFiles;
+
     try
     {
       logFiles = backendDir.listFiles(filenameFilter);
@@ -367,7 +359,7 @@
 
     // Sort the log files from oldest to youngest since this is the order
     // in which they must be copied.
-    // This is easy since the files are created in alphabetical order by JE.
+    // This is easy since the files are created in alphabetical order.
     Arrays.sort(logFiles);
 
     try
@@ -464,8 +456,7 @@
           been written to new log files, so we must include those new files.
           */
           final String latest = logFiles[logFiles.length-1].getName();
-          FilenameFilter filter = new JELatestFileFilter(latest,
-              latestFileSize);
+          FilenameFilter filter = new DBLatestFileFilter(latest, latestFileSize, filenameFilter);
 
           try
           {
@@ -581,7 +572,7 @@
 
 
   /**
-   * Restore a JE backend from backup, or verify the backup.
+   * Restore a backend from backup, or verify the backup.
    * @param backendDir The configuration of the backend instance to be
    * restored.
    * @param  restoreConfig The configuration to use when performing the restore.
@@ -1236,22 +1227,26 @@
   }
 
   /**
-   * This class implements a FilenameFilter to detect the last file
-   * from a JE database.
+   * This class implements a FilenameFilter to detect the last file from a database.
    */
-  private static class JELatestFileFilter implements FilenameFilter {
+  private static class DBLatestFileFilter implements FilenameFilter {
     private final String latest;
     private final long latestSize;
+    private FilenameFilter filenameFilter;
 
-    public JELatestFileFilter(String latest, long latestSize) {
+    public DBLatestFileFilter(String latest, long latestSize, FilenameFilter filenameFilter) {
       this.latest = latest;
       this.latestSize = latestSize;
+      this.filenameFilter = filenameFilter;
     }
 
     @Override
     public boolean accept(File d, String name)
     {
-      if (!name.endsWith(".jdb")) return false;
+      if (!filenameFilter.accept(d, name))
+      {
+        return false;
+      }
       int compareTo = name.compareTo(latest);
       return compareTo > 0 || compareTo == 0 && d.length() > latestSize;
     }
diff --git a/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/spi/Storage.java b/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/spi/Storage.java
index c31844e..2d82a69 100644
--- a/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/spi/Storage.java
+++ b/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/spi/Storage.java
@@ -26,6 +26,7 @@
 package org.opends.server.backends.pluggable.spi;
 
 import java.io.Closeable;
+import java.io.FilenameFilter;
 
 import org.opends.server.admin.std.server.PluggableBackendCfg;
 
@@ -105,6 +106,12 @@
    */
   boolean isValid();
 
+  /**
+   * Returns a filename filter which selects the files to be included in a backup.
+   * @return a filename filter which selects the files to be included in a backup
+   */
+  FilenameFilter getFilesToBackupFilter();
+
   /** {@inheritDoc} */
   @Override
   void close();
diff --git a/opendj3-server-dev/src/server/org/opends/server/types/BackupConfig.java b/opendj3-server-dev/src/server/org/opends/server/types/BackupConfig.java
index 14daba3..533c659 100644
--- a/opendj3-server-dev/src/server/org/opends/server/types/BackupConfig.java
+++ b/opendj3-server-dev/src/server/org/opends/server/types/BackupConfig.java
@@ -22,9 +22,11 @@
  *
  *
  *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Portions Copyright 2015 Forgerock AS
  */
 package org.opends.server.types;
 
+import java.io.FilenameFilter;
 
 /**
  * This class defines a data structure for holding configuration
@@ -50,36 +52,51 @@
      mayInvoke=true)
 public final class BackupConfig extends OperationConfig
 {
-  // The path to the directory in which the backup file(s) should be
-  // created.
+  /**
+   * The path to the directory in which the backup file(s) should be
+   * created.
+   */
   private BackupDirectory backupDirectory;
 
-  // Indicates whether the data should be compressed as it is written.
+  /** Indicates whether the data should be compressed as it is written. */
   private boolean compressData;
 
-  // Indicates whether the data should be encrypted as it is written.
+  /** Indicates whether the data should be encrypted as it is written. */
   private boolean encryptData;
 
-  // Indicates whether to generate a cryptographic hash of the data as
-  // it is written.
+  /**
+   * Indicates whether to generate a cryptographic hash of the data as
+   * it is written.
+   */
   private boolean hashData;
 
-  // Indicates whether to attempt an incremental backup.
+  /** Indicates whether to attempt an incremental backup. */
   private boolean isIncremental;
 
-  // Indicates whether to digitally sign the hash when the backup is
-  // complete.
+  /**
+   * Indicates whether to digitally sign the hash when the backup is
+   * complete.
+   */
   private boolean signHash;
 
-  // The unique identifier assigned to this backup operation (which
-  // may be used to indicate which version to restore if multiple
-  // backups are in the same directory).
+  /**
+   * The unique identifier assigned to this backup operation (which
+   * may be used to indicate which version to restore if multiple
+   * backups are in the same directory).
+   */
   private String backupID;
 
-  // The unique ID for the existing full or incremental backup against
-  // which the incremental backup should be based.
+  /**
+   * The unique ID for the existing full or incremental backup against
+   * which the incremental backup should be based.
+   */
   private String incrementalBaseID;
 
+  /**
+   * The filename filter to decide which files should be included as defined
+   * by the storage.
+   */
+  private FilenameFilter filesToBackupFilter;
 
 
   /**
@@ -298,5 +315,25 @@
   {
     this.signHash = signHash;
   }
+
+  /**
+   * Returns the storage-defined filename filter deciding which files should go into a backup.
+   *
+   * @return the storage-defined filename filter deciding which files should go into a backup
+   */
+  public FilenameFilter getFilesToBackupFilter()
+  {
+    return filesToBackupFilter;
+  }
+
+  /**
+   * Sets the storage-defined filter for files belonging to the backend.
+   *
+   * @param filenameFilter the filenameFilter to set
+   */
+  public void setFilesToBackupFilter(FilenameFilter filenameFilter)
+  {
+    this.filesToBackupFilter = filenameFilter;
+  }
 }
 

--
Gitblit v1.10.0