Mechanical code cleanup (sal-dom-spi)
[controller.git] / opendaylight / md-sal / sal-dom-broker / src / main / java / org / opendaylight / controller / md / sal / dom / broker / impl / ShardedDOMDataTree.java
1 /*
2  * Copyright (c) 2015 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 package org.opendaylight.controller.md.sal.dom.broker.impl;
9
10 import com.google.common.base.Preconditions;
11 import java.util.Collection;
12 import java.util.EnumMap;
13 import java.util.HashMap;
14 import java.util.Map;
15 import java.util.Map.Entry;
16 import java.util.TreeMap;
17 import javax.annotation.concurrent.GuardedBy;
18 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
19 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeIdentifier;
20 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeListener;
21 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeProducer;
22 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeService;
23 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeShard;
24 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeShardingConflictException;
25 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeShardingService;
26 import org.opendaylight.yangtools.concepts.ListenerRegistration;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29
30 public final class ShardedDOMDataTree implements DOMDataTreeService, DOMDataTreeShardingService {
31     private static final Logger LOG = LoggerFactory.getLogger(ShardedDOMDataTree.class);
32     private final Map<LogicalDatastoreType, ShardingTableEntry> shardingTables = new EnumMap<>(LogicalDatastoreType.class);
33     @GuardedBy("this")
34     private final Map<DOMDataTreeIdentifier, DOMDataTreeProducer> idToProducer = new TreeMap<>();
35
36     @GuardedBy("this")
37     private ShardingTableEntry lookupShard(final DOMDataTreeIdentifier prefix) {
38         final ShardingTableEntry t = shardingTables.get(prefix.getDatastoreType());
39         if (t == null) {
40             return null;
41         }
42
43         return t.lookup(prefix.getRootIdentifier());
44     }
45
46     @GuardedBy("this")
47     private void storeShard(final DOMDataTreeIdentifier prefix, final ShardRegistration<?> reg) {
48         ShardingTableEntry t = shardingTables.get(prefix.getDatastoreType());
49         if (t == null) {
50             t = new ShardingTableEntry();
51             shardingTables.put(prefix.getDatastoreType(), t);
52         }
53
54         t.store(prefix.getRootIdentifier(), reg);
55     }
56
57     void removeShard(final ShardRegistration<?> reg) {
58         final DOMDataTreeIdentifier prefix = reg.getPrefix();
59         final ShardRegistration<?> parentReg;
60
61         synchronized (this) {
62             final ShardingTableEntry t = shardingTables.get(prefix.getDatastoreType());
63             if (t == null) {
64                 LOG.warn("Shard registration {} points to non-existent table", reg);
65                 return;
66             }
67
68             t.remove(prefix.getRootIdentifier());
69             parentReg = lookupShard(prefix).getRegistration();
70
71             /*
72              * FIXME: adjust all producers. This is tricky, as we need different locking strategy,
73              *        simply because we risk AB/BA deadlock with a producer being split off from
74              *        a producer.
75              *
76              */
77         }
78
79         if (parentReg != null) {
80             parentReg.getInstance().onChildDetached(prefix, reg.getInstance());
81         }
82     }
83
84     @Override
85     public <T extends DOMDataTreeShard> ListenerRegistration<T> registerDataTreeShard(final DOMDataTreeIdentifier prefix, final T shard) throws DOMDataTreeShardingConflictException {
86         final ShardRegistration<T> reg;
87         final ShardRegistration<?> parentReg;
88
89         synchronized (this) {
90             /*
91              * Lookup the parent shard (e.g. the one which currently matches the prefix),
92              * and if it exists, check if its registration prefix does not collide with
93              * this registration.
94              */
95             final ShardingTableEntry parent = lookupShard(prefix);
96             parentReg = parent.getRegistration();
97             if (parentReg != null && prefix.equals(parentReg.getPrefix())) {
98                 throw new DOMDataTreeShardingConflictException(String.format("Prefix %s is already occupied by shard %s", prefix, parentReg.getInstance()));
99             }
100
101             // FIXME: wrap the shard in a proper adaptor based on implemented interface
102
103             reg = new ShardRegistration<T>(this, prefix, shard);
104
105             storeShard(prefix, reg);
106
107             // FIXME: update any producers/registrations
108         }
109
110         // Notify the parent shard
111         if (parentReg != null) {
112             parentReg.getInstance().onChildAttached(prefix, shard);
113         }
114
115         return reg;
116     }
117
118     @GuardedBy("this")
119     private DOMDataTreeProducer findProducer(final DOMDataTreeIdentifier subtree) {
120         for (final Entry<DOMDataTreeIdentifier, DOMDataTreeProducer> e : idToProducer.entrySet()) {
121             if (e.getKey().contains(subtree)) {
122                 return e.getValue();
123             }
124         }
125
126         return null;
127     }
128
129     synchronized void destroyProducer(final ShardedDOMDataTreeProducer producer) {
130         for (final DOMDataTreeIdentifier s : producer.getSubtrees()) {
131             final DOMDataTreeProducer r = idToProducer.remove(s);
132             if (!producer.equals(r)) {
133                 LOG.error("Removed producer {} on subtree {} while removing {}", r, s, producer);
134             }
135         }
136     }
137
138     @GuardedBy("this")
139     private DOMDataTreeProducer createProducer(final Map<DOMDataTreeIdentifier, DOMDataTreeShard> shardMap) {
140         // Record the producer's attachment points
141         final DOMDataTreeProducer ret = ShardedDOMDataTreeProducer.create(this, shardMap);
142         for (DOMDataTreeIdentifier s : shardMap.keySet()) {
143             idToProducer.put(s, ret);
144         }
145
146         return ret;
147     }
148
149     @Override
150     public synchronized DOMDataTreeProducer createProducer(final Collection<DOMDataTreeIdentifier> subtrees) {
151         Preconditions.checkArgument(!subtrees.isEmpty(), "Subtrees may not be empty");
152
153         final Map<DOMDataTreeIdentifier, DOMDataTreeShard> shardMap = new HashMap<>();
154         for (final DOMDataTreeIdentifier s : subtrees) {
155             // Attempting to create a disconnected producer -- all subtrees have to be unclaimed
156             final DOMDataTreeProducer producer = findProducer(s);
157             Preconditions.checkArgument(producer == null, "Subtree %s is attached to producer %s", s, producer);
158
159             shardMap.put(s, lookupShard(s).getRegistration().getInstance());
160         }
161
162         return createProducer(shardMap);
163     }
164
165     synchronized DOMDataTreeProducer createProducer(final ShardedDOMDataTreeProducer parent, final Collection<DOMDataTreeIdentifier> subtrees) {
166         Preconditions.checkNotNull(parent);
167
168         final Map<DOMDataTreeIdentifier, DOMDataTreeShard> shardMap = new HashMap<>();
169         for (final DOMDataTreeIdentifier s : subtrees) {
170             shardMap.put(s, lookupShard(s).getRegistration().getInstance());
171         }
172
173         return createProducer(shardMap);
174     }
175
176     @Override
177     public synchronized <T extends DOMDataTreeListener> ListenerRegistration<T> registerListener(final T listener, final Collection<DOMDataTreeIdentifier> subtrees, final boolean allowRxMerges, final Collection<DOMDataTreeProducer> producers) {
178         // FIXME Implement this.
179         throw new UnsupportedOperationException("Not implemented yet.");
180     }
181 }