2 * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.controller.cluster.datastore;
10 import static java.util.Objects.requireNonNull;
12 import com.google.common.annotations.Beta;
13 import com.google.common.util.concurrent.FutureCallback;
14 import com.google.common.util.concurrent.Futures;
15 import java.util.Dictionary;
16 import java.util.Hashtable;
18 import org.checkerframework.checker.lock.qual.GuardedBy;
19 import org.gaul.modernizer_maven_annotations.SuppressModernizer;
20 import org.opendaylight.controller.cluster.ActorSystemProvider;
21 import org.opendaylight.controller.cluster.datastore.config.Configuration;
22 import org.opendaylight.controller.cluster.datastore.config.ConfigurationImpl;
23 import org.opendaylight.controller.cluster.datastore.config.ModuleShardConfigProvider;
24 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
25 import org.opendaylight.mdsal.dom.api.DOMSchemaService;
26 import org.osgi.service.component.ComponentFactory;
27 import org.osgi.service.component.ComponentInstance;
28 import org.osgi.service.component.annotations.Activate;
29 import org.osgi.service.component.annotations.Component;
30 import org.osgi.service.component.annotations.Deactivate;
31 import org.osgi.service.component.annotations.Modified;
32 import org.osgi.service.component.annotations.Reference;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
37 * Global bootstrap component. It is responsible to start all distributed datastore instances and activate
38 * {@link OSGiDOMStore} as appropriate. It also provides routing of datastore proprerties towards AbstractDataStore.
41 @Component(immediate = true, configurationPid = "org.opendaylight.controller.cluster.datastore")
42 public final class OSGiDistributedDataStore {
44 * Internal state associated with a particular datastore. An instance is created for each datastore and once the
45 * datastore settles, we create a new component configuration of {@link OSGiDOMStore}. This indirection is needed
46 * to not block Service Component Runtime from activating other components while we are waiting for the datastore
47 * to settle (which can take a long time).
49 private final class DatastoreState implements FutureCallback<Object> {
50 private final DatastoreContextIntrospector introspector;
51 private final LogicalDatastoreType datastoreType;
52 private final AbstractDataStore datastore;
53 private final String serviceType;
56 private ComponentInstance component;
58 private boolean stopped;
60 DatastoreState(final DatastoreContextIntrospector introspector, final LogicalDatastoreType datastoreType,
61 final AbstractDataStore datastore, final String serviceType) {
62 this.introspector = requireNonNull(introspector);
63 this.datastoreType = requireNonNull(datastoreType);
64 this.datastore = requireNonNull(datastore);
65 this.serviceType = requireNonNull(serviceType);
68 synchronized void updateProperties(final Map<String, Object> properties) {
69 if (introspector.update(properties)) {
70 LOG.info("Distributed Datastore type {} updating context", datastoreType);
71 datastore.onDatastoreContextUpdated(introspector.newContextFactory());
76 LOG.info("Distributed Datastore type {} stopping", datastoreType);
80 if (component != null) {
85 LOG.info("Distributed Datastore type {} stopped", datastoreType);
91 public void onSuccess(final Object result) {
92 LOG.debug("Distributed Datastore type {} reached initial settle", datastoreType);
96 final Dictionary<String, Object> dict = new Hashtable<>();
97 dict.put(OSGiDOMStore.DATASTORE_TYPE_PROP, datastoreType);
98 dict.put(OSGiDOMStore.DATASTORE_INST_PROP, datastore);
99 dict.put("type", serviceType);
100 component = datastoreFactory.newInstance(dict);
101 LOG.info("Distributed Datastore type {} started", datastoreType);
107 public synchronized void onFailure(final Throwable cause) {
108 LOG.error("Distributed Datastore type {} failed to settle", datastoreType, cause);
112 private static final Logger LOG = LoggerFactory.getLogger(OSGiDistributedDataStore.class);
115 DOMSchemaService schemaService = null;
117 ActorSystemProvider actorSystemProvider = null;
119 DatastoreContextIntrospectorFactory introspectorFactory = null;
121 DatastoreSnapshotRestore snapshotRestore = null;
123 ModuleShardConfigProvider configProvider = null;
124 @Reference(target = "(component.factory=" + OSGiDOMStore.FACTORY_NAME + ")")
125 ComponentFactory datastoreFactory = null;
127 private DatastoreState configDatastore;
128 private DatastoreState operDatastore;
131 void activate(final Map<String, Object> properties) {
132 configDatastore = createDatastore(LogicalDatastoreType.CONFIGURATION, "distributed-config", properties, null);
133 operDatastore = createDatastore(LogicalDatastoreType.OPERATIONAL, "distributed-operational", properties,
134 new ConfigurationImpl(configProvider));
138 void modified(final Map<String, Object> properties) {
139 LOG.debug("Overlaying settings: {}", properties);
140 configDatastore.updateProperties(properties);
141 operDatastore.updateProperties(properties);
146 operDatastore.stop();
147 operDatastore = null;
148 configDatastore.stop();
149 configDatastore = null;
152 private DatastoreState createDatastore(final LogicalDatastoreType datastoreType, final String serviceType,
153 final Map<String, Object> properties, final Configuration config) {
154 LOG.info("Distributed Datastore type {} starting", datastoreType);
155 final DatastoreContextIntrospector introspector = introspectorFactory.newInstance(datastoreType, properties);
156 final AbstractDataStore datastore = DistributedDataStoreFactory.createInstance(actorSystemProvider,
157 introspector.getContext(), introspector, snapshotRestore, config);
158 datastore.setCloseable(schemaService.registerSchemaContextListener(datastore));
159 final DatastoreState state = new DatastoreState(introspector, datastoreType, datastore, serviceType);
161 Futures.addCallback(datastore.initialSettleFuture(), state,
162 // Note we are invoked from shard manager and therefore could block it, hence the round-trip to executor
163 datastore.getActorUtils().getClientDispatcher()::execute);