]> git.basschouten.com Git - openhab-addons.git/commitdiff
[mapdb] Recreate DB when incompatible OH2 DB is used (#9299)
authorWouter Born <github@maindrain.net>
Sat, 12 Dec 2020 18:11:50 +0000 (19:11 +0100)
committerGitHub <noreply@github.com>
Sat, 12 Dec 2020 18:11:50 +0000 (19:11 +0100)
The only way to recover from an incompatible OH2 database is to create a new database.
With these changes the add-on will create a new database automatically and archive the incompatible database files in a backup directory.

Fixes #8794

Signed-off-by: Wouter Born <github@maindrain.net>
bundles/org.openhab.persistence.mapdb/src/main/java/org/openhab/persistence/mapdb/internal/MapDbPersistenceService.java

index d78381c9bef1eb529579e9ef69efbfbf25645104..7467db99cadbab8d187ab5d3a5fa50f14b822e78 100644 (file)
 package org.openhab.persistence.mapdb.internal;
 
 import java.io.File;
+import java.io.IOException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.time.Instant;
 import java.util.Date;
 import java.util.List;
 import java.util.Locale;
@@ -60,8 +65,8 @@ public class MapDbPersistenceService implements QueryablePersistenceService {
 
     private static final String SERVICE_ID = "mapdb";
     private static final String SERVICE_LABEL = "MapDB";
-    private static final String DB_FOLDER_NAME = OpenHAB.getUserDataFolder() + File.separator + "persistence"
-            + File.separator + "mapdb";
+    private static final Path DB_DIR = new File(OpenHAB.getUserDataFolder(), "persistence").toPath().resolve("mapdb");
+    private static final Path BACKUP_DIR = DB_DIR.resolve("backup");
     private static final String DB_FILE_NAME = "storage.mapdb";
 
     private final Logger logger = LoggerFactory.getLogger(MapDbPersistenceService.class);
@@ -80,18 +85,56 @@ public class MapDbPersistenceService implements QueryablePersistenceService {
     public void activate() {
         logger.debug("MapDB persistence service is being activated");
 
-        File folder = new File(DB_FOLDER_NAME);
-        if (!folder.exists()) {
-            if (!folder.mkdirs()) {
-                logger.warn("Failed to create one or more directories in the path '{}'", DB_FOLDER_NAME);
+        try {
+            Files.createDirectories(DB_DIR);
+        } catch (IOException e) {
+            logger.warn("Failed to create one or more directories in the path '{}'", DB_DIR);
+            logger.warn("MapDB persistence service activation has failed.");
+            return;
+        }
+
+        File dbFile = DB_DIR.resolve(DB_FILE_NAME).toFile();
+        try {
+            db = DBMaker.newFileDB(dbFile).closeOnJvmShutdown().make();
+            map = db.createTreeMap("itemStore").makeOrGet();
+        } catch (RuntimeException re) {
+            Throwable cause = re.getCause();
+            if (cause instanceof ClassNotFoundException) {
+                ClassNotFoundException cnf = (ClassNotFoundException) cause;
+                logger.warn(
+                        "The MapDB in {} is incompatible with openHAB {}: {}. A new and empty MapDB will be used instead.",
+                        dbFile, OpenHAB.getVersion(), cnf.getMessage());
+
+                try {
+                    Files.createDirectories(BACKUP_DIR);
+                } catch (IOException ioe) {
+                    logger.warn("Failed to create one or more directories in the path '{}'", BACKUP_DIR);
+                    logger.warn("MapDB persistence service activation has failed.");
+                    return;
+                }
+
+                try (DirectoryStream<Path> stream = Files.newDirectoryStream(DB_DIR)) {
+                    long epochMilli = Instant.now().toEpochMilli();
+                    for (Path path : stream) {
+                        if (!Files.isDirectory(path)) {
+                            Path newPath = BACKUP_DIR.resolve(epochMilli + "--" + path.getFileName());
+                            Files.move(path, newPath);
+                            logger.info("Moved incompatible MapDB file '{}' to '{}'", path, newPath);
+                        }
+                    }
+                } catch (IOException ioe) {
+                    logger.warn("Failed to read files from '{}': {}", DB_DIR, ioe.getMessage());
+                    logger.warn("MapDB persistence service activation has failed.");
+                    return;
+                }
+
+                db = DBMaker.newFileDB(dbFile).closeOnJvmShutdown().make();
+                map = db.createTreeMap("itemStore").makeOrGet();
+            } else {
+                logger.warn("Failed to create or open the MapDB: {}", re.getMessage());
                 logger.warn("MapDB persistence service activation has failed.");
-                return;
             }
         }
-
-        File dbFile = new File(DB_FOLDER_NAME, DB_FILE_NAME);
-        db = DBMaker.newFileDB(dbFile).closeOnJvmShutdown().make();
-        map = db.createTreeMap("itemStore").makeOrGet();
         logger.debug("MapDB persistence service is now activated");
     }