Fixup checkstyle
[controller.git] / opendaylight / md-sal / sal-distributed-datastore / src / main / java / org / opendaylight / controller / cluster / datastore / OSGiDistributedDataStore.java
1 /*
2  * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.controller.cluster.datastore;
9
10 import static java.util.Objects.requireNonNull;
11
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.Map;
16 import org.checkerframework.checker.lock.qual.GuardedBy;
17 import org.opendaylight.controller.cluster.ActorSystemProvider;
18 import org.opendaylight.controller.cluster.datastore.config.Configuration;
19 import org.opendaylight.controller.cluster.datastore.config.ConfigurationImpl;
20 import org.opendaylight.controller.cluster.datastore.config.ModuleShardConfigProvider;
21 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
22 import org.opendaylight.mdsal.dom.api.DOMSchemaService;
23 import org.osgi.framework.FrameworkUtil;
24 import org.osgi.service.component.ComponentFactory;
25 import org.osgi.service.component.ComponentInstance;
26 import org.osgi.service.component.annotations.Activate;
27 import org.osgi.service.component.annotations.Component;
28 import org.osgi.service.component.annotations.Deactivate;
29 import org.osgi.service.component.annotations.Modified;
30 import org.osgi.service.component.annotations.Reference;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34 /**
35  * Global bootstrap component. It is responsible to start all distributed datastore instances and activate
36  * {@link OSGiDOMStore} as appropriate. It also provides routing of datastore proprerties towards AbstractDataStore.
37  */
38 @Beta
39 @Component(immediate = true, configurationPid = "org.opendaylight.controller.cluster.datastore")
40 public final class OSGiDistributedDataStore {
41     /**
42      * Internal state associated with a particular datastore. An instance is created for each datastore and once the
43      * datastore settles, we create a new component configuration of {@link OSGiDOMStore}. This indirection is needed
44      * to not block Service Component Runtime from activating other components while we are waiting for the datastore
45      * to settle (which can take a long time).
46      */
47     private final class DatastoreState implements FutureCallback<Object> {
48         private final DatastoreContextIntrospector introspector;
49         private final LogicalDatastoreType datastoreType;
50         private final AbstractDataStore datastore;
51         private final String serviceType;
52
53         @GuardedBy("this")
54         private ComponentInstance<OSGiDOMStore> component;
55         @GuardedBy("this")
56         private boolean stopped;
57
58         DatastoreState(final DatastoreContextIntrospector introspector, final LogicalDatastoreType datastoreType,
59                 final AbstractDataStore datastore, final String serviceType) {
60             this.introspector = requireNonNull(introspector);
61             this.datastoreType = requireNonNull(datastoreType);
62             this.datastore = requireNonNull(datastore);
63             this.serviceType = requireNonNull(serviceType);
64         }
65
66         synchronized void updateProperties(final Map<String, Object> properties) {
67             if (introspector.update(properties)) {
68                 LOG.info("Distributed Datastore type {} updating context", datastoreType);
69                 datastore.onDatastoreContextUpdated(introspector.newContextFactory());
70             }
71         }
72
73         void stop() {
74             LOG.info("Distributed Datastore type {} stopping", datastoreType);
75
76             synchronized (this) {
77                 stopped = true;
78                 if (component != null) {
79                     component.dispose();
80                     component = null;
81                 }
82                 datastore.close();
83                 LOG.info("Distributed Datastore type {} stopped", datastoreType);
84             }
85         }
86
87         @Override
88         public void onSuccess(final Object result) {
89             LOG.debug("Distributed Datastore type {} reached initial settle", datastoreType);
90
91             synchronized (this) {
92                 if (!stopped) {
93                     component = datastoreFactory.newInstance(FrameworkUtil.asDictionary(Map.of(
94                         OSGiDOMStore.DATASTORE_TYPE_PROP, datastoreType,
95                         OSGiDOMStore.DATASTORE_INST_PROP, datastore,
96                         "type", serviceType)));
97                     LOG.info("Distributed Datastore type {} started", datastoreType);
98                 }
99             }
100         }
101
102         @Override
103         public synchronized void onFailure(final Throwable cause) {
104             LOG.error("Distributed Datastore type {} failed to settle", datastoreType, cause);
105         }
106     }
107
108     private static final Logger LOG = LoggerFactory.getLogger(OSGiDistributedDataStore.class);
109
110     private final ComponentFactory<OSGiDOMStore> datastoreFactory;
111     private DatastoreState configDatastore;
112     private DatastoreState operDatastore;
113
114     @Activate
115     public OSGiDistributedDataStore(@Reference final DOMSchemaService schemaService,
116             @Reference final ActorSystemProvider actorSystemProvider,
117             @Reference final DatastoreContextIntrospectorFactory introspectorFactory,
118             @Reference final DatastoreSnapshotRestore snapshotRestore,
119             @Reference final ModuleShardConfigProvider configProvider,
120             @Reference(target = "(component.factory=" + OSGiDOMStore.FACTORY_NAME + ")")
121             final ComponentFactory<OSGiDOMStore> datastoreFactory, final Map<String, Object> properties) {
122         this.datastoreFactory = requireNonNull(datastoreFactory);
123         configDatastore = createDatastore(schemaService, actorSystemProvider, snapshotRestore, introspectorFactory,
124             LogicalDatastoreType.CONFIGURATION, "distributed-config", properties, null);
125         operDatastore = createDatastore(schemaService, actorSystemProvider, snapshotRestore, introspectorFactory,
126             LogicalDatastoreType.OPERATIONAL, "distributed-operational", properties,
127             new ConfigurationImpl(configProvider));
128     }
129
130     @Modified
131     void modified(final Map<String, Object> properties) {
132         LOG.debug("Overlaying settings: {}", properties);
133         configDatastore.updateProperties(properties);
134         operDatastore.updateProperties(properties);
135     }
136
137     @Deactivate
138     void deactivate() {
139         operDatastore.stop();
140         operDatastore = null;
141         configDatastore.stop();
142         configDatastore = null;
143     }
144
145     private DatastoreState createDatastore(final DOMSchemaService schemaService,
146             final ActorSystemProvider actorSystemProvider, final DatastoreSnapshotRestore snapshotRestore,
147             final DatastoreContextIntrospectorFactory introspectorFactory, final LogicalDatastoreType datastoreType,
148             final String serviceType, final Map<String, Object> properties,final Configuration config) {
149         LOG.info("Distributed Datastore type {} starting", datastoreType);
150         final var introspector = introspectorFactory.newInstance(datastoreType, properties);
151         final var datastore = DistributedDataStoreFactory.createInstance(actorSystemProvider,
152             introspector.getContext(), introspector, snapshotRestore, config);
153         datastore.setCloseable(schemaService.registerSchemaContextListener(datastore::onModelContextUpdated));
154         final var state = new DatastoreState(introspector, datastoreType, datastore, serviceType);
155
156         Futures.addCallback(datastore.initialSettleFuture(), state,
157             // Note we are invoked from shard manager and therefore could block it, hence the round-trip to executor
158             datastore.getActorUtils().getClientDispatcher()::execute);
159         return state;
160     }
161 }