Convert DatastoreSnapshotRestore to OSGi DS 23/91723/6
authorRobert Varga <robert.varga@pantheon.tech>
Tue, 28 Jul 2020 12:39:25 +0000 (14:39 +0200)
committerRobert Varga <robert.varga@pantheon.tech>
Thu, 30 Jul 2020 10:19:01 +0000 (12:19 +0200)
This is a simple holder used extract restoration code, split it out
of manual blueprint.

JIRA: CONTROLLER-1882
Change-Id: Ic7f97fa1a2b0302c7f1ccc14a9a79fe7fce57412
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DatastoreSnapshotRestore.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DefaultDatastoreSnapshotRestore.java [new file with mode: 0644]
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreFactory.java
opendaylight/md-sal/sal-distributed-datastore/src/main/resources/OSGI-INF/blueprint/clustered-datastore.xml
opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DatastoreSnapshotRestoreTest.java

index 995401c82c681d9e184c22ee3b45277963da0ed0..f6068dd539a0490bc3f74ae9a21ecc4e47bcd571 100644 (file)
@@ -7,20 +7,9 @@
  */
 package org.opendaylight.controller.cluster.datastore;
 
-import static java.util.Objects.requireNonNull;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.ObjectInputStream;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.atomic.AtomicReference;
+import com.google.common.annotations.Beta;
+import java.util.Optional;
 import org.opendaylight.controller.cluster.datastore.persisted.DatastoreSnapshot;
-import org.opendaylight.controller.cluster.datastore.persisted.DatastoreSnapshotList;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /**
  * This class looks for a previously saved data store backup file in a directory and, if found, de-serializes
@@ -28,72 +17,8 @@ import org.slf4j.LoggerFactory;
  *
  * @author Thomas Pantelis
  */
-public final class DatastoreSnapshotRestore {
-    private static final Logger LOG = LoggerFactory.getLogger(DatastoreSnapshotRestore.class);
-
-    private static AtomicReference<DatastoreSnapshotRestore> instance = new AtomicReference<>();
-
-    private final String restoreDirectoryPath;
-    private final Map<String, DatastoreSnapshot> datastoreSnapshots = new ConcurrentHashMap<>();
-
-    public static DatastoreSnapshotRestore instance(final String restoreDirectoryPath) {
-        instance.compareAndSet(null, new DatastoreSnapshotRestore(restoreDirectoryPath));
-        return instance.get();
-    }
-
-    private DatastoreSnapshotRestore(final String restoreDirectoryPath) {
-        this.restoreDirectoryPath = requireNonNull(restoreDirectoryPath);
-    }
-
-    // synchronize this method so that, in case of concurrent access to getAndRemove(),
-    // no one ends up with partially initialized data
-    @SuppressWarnings("checkstyle:IllegalCatch")
-    private synchronized void initialize() {
-
-        File restoreDirectoryFile = new File(restoreDirectoryPath);
-
-        String[] files = restoreDirectoryFile.list();
-        if (files == null || files.length == 0) {
-            LOG.debug("Restore directory {} does not exist or is empty", restoreDirectoryFile);
-            return;
-        }
-
-        if (files.length > 1) {
-            LOG.error(
-                "Found {} files in clustered datastore restore directory {} - expected 1. No restore will be attempted",
-                files.length, restoreDirectoryFile);
-            return;
-        }
-
-        File restoreFile = new File(restoreDirectoryFile, files[0]);
-
-        LOG.info("Clustered datastore will be restored from file {}", restoreFile);
-
-        try (FileInputStream fis = new FileInputStream(restoreFile)) {
-            DatastoreSnapshotList snapshots = deserialize(fis);
-            LOG.debug("Deserialized {} snapshots", snapshots.size());
-
-            for (DatastoreSnapshot snapshot: snapshots) {
-                datastoreSnapshots.put(snapshot.getType(), snapshot);
-            }
-        } catch (ClassNotFoundException | IOException e) {
-            LOG.error("Error reading clustered datastore restore file {}", restoreFile, e);
-        } finally {
-            if (!restoreFile.delete()) {
-                LOG.error("Could not delete clustered datastore restore file {}", restoreFile);
-            }
-        }
-    }
-
-    private static DatastoreSnapshotList deserialize(final InputStream inputStream)
-            throws IOException, ClassNotFoundException {
-        try (ObjectInputStream ois = new ObjectInputStream(inputStream)) {
-            return (DatastoreSnapshotList) ois.readObject();
-        }
-    }
+@Beta
+public interface DatastoreSnapshotRestore {
 
-    public DatastoreSnapshot getAndRemove(final String datastoreType) {
-        initialize();
-        return datastoreSnapshots.remove(datastoreType);
-    }
+    Optional<DatastoreSnapshot> getAndRemove(String datastoreType);
 }
diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DefaultDatastoreSnapshotRestore.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DefaultDatastoreSnapshotRestore.java
new file mode 100644 (file)
index 0000000..5fbc7c1
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.cluster.datastore;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.annotations.Beta;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+import org.opendaylight.controller.cluster.datastore.persisted.DatastoreSnapshot;
+import org.opendaylight.controller.cluster.datastore.persisted.DatastoreSnapshotList;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class looks for a previously saved data store backup file in a directory and, if found, de-serializes
+ * the DatastoreSnapshot instances. This class has a static singleton that is created on bundle activation.
+ *
+ * @author Thomas Pantelis
+ */
+@Beta
+@Component(immediate = true)
+public final class DefaultDatastoreSnapshotRestore implements DatastoreSnapshotRestore {
+    private static final Logger LOG = LoggerFactory.getLogger(DefaultDatastoreSnapshotRestore.class);
+
+    private final Map<String, DatastoreSnapshot> datastoreSnapshots = new ConcurrentHashMap<>();
+    private final String restoreDirectoryPath;
+
+    public DefaultDatastoreSnapshotRestore() {
+        this("./clustered-datastore-restore");
+    }
+
+    public DefaultDatastoreSnapshotRestore(final String restoreDirectoryPath) {
+        this.restoreDirectoryPath = requireNonNull(restoreDirectoryPath);
+    }
+
+    @Override
+    public Optional<DatastoreSnapshot> getAndRemove(final String datastoreType) {
+        return Optional.ofNullable(datastoreSnapshots.remove(datastoreType));
+    }
+
+    @Activate
+    @SuppressWarnings("checkstyle:IllegalCatch")
+    void activate() {
+        final File restoreDirectoryFile = new File(restoreDirectoryPath);
+        final String[] files = restoreDirectoryFile.list();
+        if (files == null || files.length == 0) {
+            LOG.debug("Restore directory {} does not exist or is empty", restoreDirectoryFile);
+            return;
+        }
+
+        if (files.length > 1) {
+            LOG.error(
+                "Found {} files in clustered datastore restore directory {} - expected 1. No restore will be attempted",
+                files.length, restoreDirectoryFile);
+            return;
+        }
+
+        final File restoreFile = new File(restoreDirectoryFile, files[0]);
+        LOG.info("Clustered datastore will be restored from file {}", restoreFile);
+
+        try (FileInputStream fis = new FileInputStream(restoreFile)) {
+            DatastoreSnapshotList snapshots = deserialize(fis);
+            LOG.debug("Deserialized {} snapshots", snapshots.size());
+
+            for (DatastoreSnapshot snapshot: snapshots) {
+                datastoreSnapshots.put(snapshot.getType(), snapshot);
+            }
+        } catch (ClassNotFoundException | IOException e) {
+            LOG.error("Error reading clustered datastore restore file {}", restoreFile, e);
+        } finally {
+            if (!restoreFile.delete()) {
+                LOG.error("Could not delete clustered datastore restore file {}", restoreFile);
+            }
+        }
+    }
+
+    private static DatastoreSnapshotList deserialize(final InputStream inputStream)
+            throws IOException, ClassNotFoundException {
+        try (ObjectInputStream ois = new ObjectInputStream(inputStream)) {
+            return (DatastoreSnapshotList) ois.readObject();
+        }
+    }
+}
index a765fa3efe072b994adff57d1d71ae222aa55a10..8da2816010a1a3fe2d754bf1afa6657278a59563 100644 (file)
@@ -44,7 +44,7 @@ public final class DistributedDataStoreFactory {
         LOG.info("Create data store instance of type : {}", datastoreName);
 
         final ActorSystem actorSystem = actorSystemProvider.getActorSystem();
-        final DatastoreSnapshot restoreFromSnapshot = datastoreSnapshotRestore.getAndRemove(datastoreName);
+        final DatastoreSnapshot restoreFromSnapshot = datastoreSnapshotRestore.getAndRemove(datastoreName).orElse(null);
 
         Configuration config;
         if (orgConfig == null) {
index 18fcc75254073cf423e03755ee1cc54a5c2dec16..c97bfc471fa5373e37b5edf02bf06e04ed6cf780 100644 (file)
   <!-- Datastore properties -->
   <reference id="actorSystemProvider" interface="org.opendaylight.controller.cluster.ActorSystemProvider"/>
   <reference id="introspectorFactory" interface="org.opendaylight.controller.cluster.datastore.DatastoreContextIntrospectorFactory"/>
+  <reference id="datastoreSnapshotRestore" interface="org.opendaylight.controller.cluster.datastore.DatastoreSnapshotRestore"/>
 
   <cm:cm-properties id="datastoreProps" persistent-id="org.opendaylight.controller.cluster.datastore"/>
 
   <!-- Distributed Config Datastore -->
-  <bean id="datastoreSnapshotRestore" class="org.opendaylight.controller.cluster.datastore.DatastoreSnapshotRestore"
-          factory-method="instance">
-    <argument value="./clustered-datastore-restore"/>
-  </bean>
-
   <bean id="introspectorConfig" factory-ref="introspectorFactory" factory-method="newInstance">
     <argument type="org.opendaylight.mdsal.common.api.LogicalDatastoreType" value="CONFIGURATION"/>
   </bean>
index 4cd7290498eeefc7d4a1123162f0120056129d09..5cefc8b36d76b91dc4c3731cda8be398374ddfa5 100644 (file)
@@ -17,6 +17,7 @@ import java.io.File;
 import java.io.FileOutputStream;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.Optional;
 import org.apache.commons.lang3.SerializationUtils;
 import org.junit.After;
 import org.junit.Test;
@@ -77,18 +78,15 @@ public class DatastoreSnapshotRestoreTest {
             SerializationUtils.serialize(snapshotList, fos);
         }
 
-        DatastoreSnapshotRestore instance = DatastoreSnapshotRestore.instance(restoreDirectoryPath);
+        DefaultDatastoreSnapshotRestore instance = new DefaultDatastoreSnapshotRestore(restoreDirectoryPath);
+        instance.activate();
 
-        assertDatastoreSnapshotEquals(configSnapshot, instance.getAndRemove("config"));
-        assertDatastoreSnapshotEquals(operSnapshot, instance.getAndRemove("oper"));
+        assertDatastoreSnapshotEquals(configSnapshot, instance.getAndRemove("config").orElse(null));
+        assertDatastoreSnapshotEquals(operSnapshot, instance.getAndRemove("oper").orElse(null));
 
-        assertNull("DatastoreSnapshot was not removed", instance.getAndRemove("config"));
+        assertEquals("DatastoreSnapshot was not removed", Optional.empty(), instance.getAndRemove("config"));
 
         assertFalse(backupFile + " was not deleted", backupFile.exists());
-
-        instance = DatastoreSnapshotRestore.instance(restoreDirectoryPath);
-        assertNull("Expected null DatastoreSnapshot", instance.getAndRemove("config"));
-        assertNull("Expected null DatastoreSnapshot", instance.getAndRemove("oper"));
     }
 
     private static void assertDatastoreSnapshotEquals(final DatastoreSnapshot expected,