From ccca30bbb1545643c427fc59c23329c5d49f8d4b Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Tue, 28 Jul 2020 14:39:25 +0200 Subject: [PATCH 1/1] Convert DatastoreSnapshotRestore to OSGi DS 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 --- .../datastore/DatastoreSnapshotRestore.java | 85 +--------------- .../DefaultDatastoreSnapshotRestore.java | 97 +++++++++++++++++++ .../DistributedDataStoreFactory.java | 2 +- .../blueprint/clustered-datastore.xml | 6 +- .../DatastoreSnapshotRestoreTest.java | 14 ++- 5 files changed, 110 insertions(+), 94 deletions(-) create mode 100644 opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DefaultDatastoreSnapshotRestore.java diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DatastoreSnapshotRestore.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DatastoreSnapshotRestore.java index 995401c82c..f6068dd539 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DatastoreSnapshotRestore.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DatastoreSnapshotRestore.java @@ -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 instance = new AtomicReference<>(); - - private final String restoreDirectoryPath; - private final Map 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 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 index 0000000000..5fbc7c197c --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DefaultDatastoreSnapshotRestore.java @@ -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 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 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(); + } + } +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreFactory.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreFactory.java index a765fa3efe..8da2816010 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreFactory.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreFactory.java @@ -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) { diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/resources/OSGI-INF/blueprint/clustered-datastore.xml b/opendaylight/md-sal/sal-distributed-datastore/src/main/resources/OSGI-INF/blueprint/clustered-datastore.xml index 18fcc75254..c97bfc471f 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/resources/OSGI-INF/blueprint/clustered-datastore.xml +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/resources/OSGI-INF/blueprint/clustered-datastore.xml @@ -15,15 +15,11 @@ + - - - - diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DatastoreSnapshotRestoreTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DatastoreSnapshotRestoreTest.java index 4cd7290498..5cefc8b36d 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DatastoreSnapshotRestoreTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DatastoreSnapshotRestoreTest.java @@ -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, -- 2.36.6