8edfddedf49be40e3a51e584ab9cd905d03fb3ca
[controller.git] / opendaylight / md-sal / sal-distributed-datastore / src / main / java / org / opendaylight / controller / cluster / sharding / DistributedShardFrontend.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. 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
9 package org.opendaylight.controller.cluster.sharding;
10
11 import com.google.common.base.Preconditions;
12 import java.util.ArrayList;
13 import java.util.Collection;
14 import java.util.HashMap;
15 import java.util.List;
16 import java.util.Map;
17 import javax.annotation.Nonnull;
18 import javax.annotation.concurrent.GuardedBy;
19 import org.opendaylight.controller.cluster.databroker.actors.dds.DataStoreClient;
20 import org.opendaylight.controller.cluster.datastore.DistributedDataStore;
21 import org.opendaylight.mdsal.dom.api.DOMDataTreeChangeListener;
22 import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
23 import org.opendaylight.mdsal.dom.api.DOMDataTreeShard;
24 import org.opendaylight.mdsal.dom.spi.shard.ChildShardContext;
25 import org.opendaylight.mdsal.dom.spi.shard.DOMDataTreeShardProducer;
26 import org.opendaylight.mdsal.dom.spi.shard.ForeignShardModificationContext;
27 import org.opendaylight.mdsal.dom.spi.shard.ReadableWriteableDOMDataTreeShard;
28 import org.opendaylight.mdsal.dom.spi.shard.SubshardProducerSpecification;
29 import org.opendaylight.mdsal.dom.spi.shard.WriteableDOMDataTreeShard;
30 import org.opendaylight.yangtools.concepts.ListenerRegistration;
31 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35 /**
36  * Proxy implementation of a shard that creates forwarding producers to the backend shard.
37  */
38 class DistributedShardFrontend implements ReadableWriteableDOMDataTreeShard {
39
40     private static final Logger LOG = LoggerFactory.getLogger(DistributedShardFrontend.class);
41
42     private final DataStoreClient client;
43     private final DOMDataTreeIdentifier shardRoot;
44     @GuardedBy("this")
45     private final Map<DOMDataTreeIdentifier, ChildShardContext> childShards = new HashMap<>();
46     @GuardedBy("this")
47     private final List<ShardProxyProducer> producers = new ArrayList<>();
48     private final DistributedDataStore distributedDataStore;
49
50     DistributedShardFrontend(final DistributedDataStore distributedDataStore,
51                              final DataStoreClient client,
52                              final DOMDataTreeIdentifier shardRoot) {
53         this.distributedDataStore = Preconditions.checkNotNull(distributedDataStore);
54         this.client = Preconditions.checkNotNull(client);
55         this.shardRoot = Preconditions.checkNotNull(shardRoot);
56     }
57
58     @Override
59     public synchronized DOMDataTreeShardProducer createProducer(final Collection<DOMDataTreeIdentifier> paths) {
60         for (final DOMDataTreeIdentifier prodPrefix : paths) {
61             Preconditions.checkArgument(paths.contains(prodPrefix), "Prefix %s is not contained under shard root",
62                     prodPrefix, paths);
63         }
64
65         final ShardProxyProducer ret =
66                 new ShardProxyProducer(shardRoot, paths, client, createModificationFactory(paths));
67         producers.add(ret);
68         return ret;
69     }
70
71     @Override
72     public synchronized void onChildAttached(final DOMDataTreeIdentifier prefix, final DOMDataTreeShard child) {
73         LOG.debug("{} : Child shard attached at {}", shardRoot, prefix);
74         Preconditions.checkArgument(child != this, "Attempted to attach child %s onto self", this);
75         addChildShard(prefix, child);
76         updateProducers();
77     }
78
79     @Override
80     public synchronized void onChildDetached(final DOMDataTreeIdentifier prefix, final DOMDataTreeShard child) {
81         LOG.debug("{} : Child shard detached at {}", shardRoot, prefix);
82         childShards.remove(prefix);
83         updateProducers();
84         // TODO we should grab the dataTreeSnapshot that's in the shard and apply it to this shard
85     }
86
87     private void addChildShard(final DOMDataTreeIdentifier prefix, final DOMDataTreeShard child) {
88         Preconditions.checkArgument(child instanceof WriteableDOMDataTreeShard);
89         childShards.put(prefix, new ChildShardContext(prefix, (WriteableDOMDataTreeShard) child));
90     }
91
92     DistributedShardModificationFactory createModificationFactory(final Collection<DOMDataTreeIdentifier> prefixes) {
93         // TODO this could be abstract
94         final Map<DOMDataTreeIdentifier, SubshardProducerSpecification> affectedSubshards = new HashMap<>();
95
96         for (final DOMDataTreeIdentifier producerPrefix : prefixes) {
97             for (final ChildShardContext maybeAffected : childShards.values()) {
98                 final DOMDataTreeIdentifier bindPath;
99                 if (producerPrefix.contains(maybeAffected.getPrefix())) {
100                     bindPath = maybeAffected.getPrefix();
101                 } else if (maybeAffected.getPrefix().contains(producerPrefix)) {
102                     // Bound path is inside subshard
103                     bindPath = producerPrefix;
104                 } else {
105                     continue;
106                 }
107
108                 SubshardProducerSpecification spec = affectedSubshards.get(maybeAffected.getPrefix());
109                 if (spec == null) {
110                     spec = new SubshardProducerSpecification(maybeAffected);
111                     affectedSubshards.put(maybeAffected.getPrefix(), spec);
112                 }
113                 spec.addPrefix(bindPath);
114             }
115         }
116
117         final DistributedShardModificationFactoryBuilder builder =
118                 new DistributedShardModificationFactoryBuilder(shardRoot);
119         for (final SubshardProducerSpecification spec : affectedSubshards.values()) {
120             final ForeignShardModificationContext foreignContext =
121                     new ForeignShardModificationContext(spec.getPrefix(), spec.createProducer());
122             builder.addSubshard(foreignContext);
123             builder.addSubshard(spec.getPrefix(), foreignContext);
124         }
125
126         return builder.build();
127     }
128
129     private void updateProducers() {
130         for (final ShardProxyProducer producer : producers) {
131             producer.setModificationFactory(createModificationFactory(producer.getPrefixes()));
132         }
133     }
134
135     @Nonnull
136     @Override
137     public <L extends DOMDataTreeChangeListener> ListenerRegistration<L> registerTreeChangeListener(
138             final YangInstanceIdentifier treeId, final L listener) {
139         throw new UnsupportedOperationException("Listener registration not supported");
140     }
141
142 }