X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=dom%2Fmdsal-dom-broker%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fmdsal%2Fdom%2Fbroker%2FShardedDOMDataTreeProducer.java;h=029721b1a3caed8e036450e5923342bd19a958f8;hb=c37d38386002ed12b279938051813f99a4de70ff;hp=53a39774489dd84780e6f593f31977d62e2a9b1d;hpb=6a192f0eeedc302ae0b506d04f9d79b34406aef5;p=mdsal.git diff --git a/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/ShardedDOMDataTreeProducer.java b/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/ShardedDOMDataTreeProducer.java index 53a3977448..029721b1a3 100644 --- a/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/ShardedDOMDataTreeProducer.java +++ b/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/ShardedDOMDataTreeProducer.java @@ -7,111 +7,112 @@ */ package org.opendaylight.mdsal.dom.broker; -import org.opendaylight.mdsal.dom.spi.store.DOMStore; -import org.opendaylight.mdsal.dom.spi.store.DOMStoreTransactionChain; -import org.opendaylight.mdsal.dom.spi.store.DOMStoreWriteTransaction; - -import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier; -import org.opendaylight.mdsal.dom.api.DOMDataTreeProducer; -import org.opendaylight.mdsal.dom.api.DOMDataTreeProducerBusyException; -import org.opendaylight.mdsal.dom.api.DOMDataTreeProducerException; -import org.opendaylight.mdsal.dom.api.DOMDataTreeShard; -import org.opendaylight.mdsal.dom.api.DOMDataWriteTransaction; import com.google.common.base.Preconditions; +import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.BiMap; import com.google.common.collect.ImmutableBiMap; import com.google.common.collect.ImmutableBiMap.Builder; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Multimap; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedList; import java.util.Map; import java.util.Map.Entry; -import java.util.Queue; import java.util.Set; import javax.annotation.concurrent.GuardedBy; +import org.opendaylight.mdsal.dom.api.DOMDataTreeCursorAwareTransaction; +import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier; +import org.opendaylight.mdsal.dom.api.DOMDataTreeProducer; +import org.opendaylight.mdsal.dom.api.DOMDataTreeProducerBusyException; +import org.opendaylight.mdsal.dom.api.DOMDataTreeProducerException; +import org.opendaylight.mdsal.dom.api.DOMDataTreeShard; +import org.opendaylight.mdsal.dom.store.inmemory.DOMDataTreeShardProducer; +import org.opendaylight.mdsal.dom.store.inmemory.WriteableDOMDataTreeShard; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -final class ShardedDOMDataTreeProducer implements DOMDataTreeProducer { +class ShardedDOMDataTreeProducer implements DOMDataTreeProducer { private static final Logger LOG = LoggerFactory.getLogger(ShardedDOMDataTreeProducer.class); - private final BiMap shardToChain; - private final Map idToShard; + private final Set subtrees; private final ShardedDOMDataTree dataTree; + private BiMap idToProducer = ImmutableBiMap.of(); + private Map idToShard; + @GuardedBy("this") - private Map children = Collections.emptyMap(); + private DOMDataTreeCursorAwareTransaction openTx; @GuardedBy("this") - private DOMDataWriteTransaction openTx; + private Map children = Collections.emptyMap(); @GuardedBy("this") private boolean closed; - ShardedDOMDataTreeProducer(final ShardedDOMDataTree dataTree, final Map shardMap, final Set shards) { + @GuardedBy("this") + private ShardedDOMDataTreeListenerContext attachedListener; + + ShardedDOMDataTreeProducer(final ShardedDOMDataTree dataTree, + final Collection subtrees, + final Map shardMap, + final Multimap shardToId) { this.dataTree = Preconditions.checkNotNull(dataTree); + if (!shardToId.isEmpty()) { + this.idToProducer = mapIdsToProducer(shardToId); + } + idToShard = ImmutableMap.copyOf(shardMap); + this.subtrees = ImmutableSet.copyOf(subtrees); + } - // Create shard -> chain map - final Builder cb = ImmutableBiMap.builder(); - final Queue es = new LinkedList<>(); - - for (final DOMDataTreeShard s : shards) { - if (s instanceof DOMStore) { - try { - final DOMStoreTransactionChain c = ((DOMStore)s).createTransactionChain(); - LOG.trace("Using DOMStore chain {} to access shard {}", c, s); - cb.put(s, c); - } catch (final Exception e) { - LOG.error("Failed to instantiate chain for shard {}", s, e); - es.add(e); - } - } else { - LOG.error("Unhandled shard instance type {}", s.getClass()); - } + static DOMDataTreeProducer create(final ShardedDOMDataTree dataTree, + final Collection subtrees, + final Map shardMap) { + final Multimap shardToIdentifiers = ArrayListMultimap.create(); + // map which identifier belongs to which shard + for (final Entry entry : shardMap.entrySet()) { + shardToIdentifiers.put(entry.getValue(), entry.getKey()); } - this.shardToChain = cb.build(); - - // An error was encountered, close chains and report the error - if (shardToChain.size() != shards.size()) { - for (final DOMStoreTransactionChain c : shardToChain.values()) { - try { - c.close(); - } catch (final Exception e) { - LOG.warn("Exception raised while closing chain {}", c, e); - } - } - final IllegalStateException e = new IllegalStateException("Failed to completely allocate contexts", es.poll()); - while (!es.isEmpty()) { - e.addSuppressed(es.poll()); - } + return new ShardedDOMDataTreeProducer(dataTree, subtrees, shardMap, shardToIdentifiers); + } - throw e; + void subshardAdded(final Map shardMap) { + Preconditions.checkState(openTx == null, "Transaction %s is still open", openTx); + final Multimap shardToIdentifiers = ArrayListMultimap.create(); + // map which identifier belongs to which shard + for (final Entry entry : shardMap.entrySet()) { + shardToIdentifiers.put(entry.getValue(), entry.getKey()); } - + this.idToProducer = mapIdsToProducer(shardToIdentifiers); idToShard = ImmutableMap.copyOf(shardMap); } + private BiMap mapIdsToProducer(final Multimap shardToId) { + final Builder idToProducerBuilder = ImmutableBiMap.builder(); + for (final Entry> entry : shardToId.asMap().entrySet()) { + if (entry.getKey() instanceof WriteableDOMDataTreeShard) { + //create a single producer for all prefixes in a single shard + final DOMDataTreeShardProducer producer = ((WriteableDOMDataTreeShard) entry.getKey()) + .createProducer(entry.getValue()); + // id mapped to producers + for (final DOMDataTreeIdentifier id : entry.getValue()) { + idToProducerBuilder.put(id, producer); + } + } else { + LOG.error("Unable to create a producer for shard that's not a WriteableDOMDataTreeShard"); + } + } + + return idToProducerBuilder.build(); + } + @Override - public synchronized DOMDataWriteTransaction createTransaction(final boolean isolated) { + public synchronized DOMDataTreeCursorAwareTransaction createTransaction(final boolean isolated) { Preconditions.checkState(!closed, "Producer is already closed"); Preconditions.checkState(openTx == null, "Transaction %s is still open", openTx); - // Allocate backing transactions - final Map shardToTx = new HashMap<>(); - for (final Entry e : shardToChain.entrySet()) { - shardToTx.put(e.getKey(), e.getValue().newWriteOnlyTransaction()); - } - - // Create the ID->transaction map - final ImmutableMap.Builder b = ImmutableMap.builder(); - for (final Entry e : idToShard.entrySet()) { - b.put(e.getKey(), shardToTx.get(e.getValue())); - } + this.openTx = new ShardedDOMDataTreeWriteTransaction(this, idToProducer, children); - final ShardedDOMDataWriteTransaction ret = new ShardedDOMDataWriteTransaction(this, b.build()); - openTx = ret; - return ret; + return openTx; } @GuardedBy("this") @@ -126,9 +127,9 @@ final class ShardedDOMDataTreeProducer implements DOMDataTreeProducer { } @GuardedBy("this") - private DOMDataTreeProducer lookupChild(final DOMDataTreeIdentifier s) { + private DOMDataTreeProducer lookupChild(final DOMDataTreeIdentifier domDataTreeIdentifier) { for (final Entry e : children.entrySet()) { - if (e.getKey().contains(s)) { + if (e.getKey().contains(domDataTreeIdentifier)) { return e.getValue(); } } @@ -143,10 +144,7 @@ final class ShardedDOMDataTreeProducer implements DOMDataTreeProducer { for (final DOMDataTreeIdentifier s : subtrees) { // Check if the subtree was visible at any time - if (!haveSubtree(s)) { - throw new IllegalArgumentException(String.format("Subtree %s was never available in producer %s", s, this)); - } - + Preconditions.checkArgument(haveSubtree(s), "Subtree %s was never available in producer %s", s, this); // Check if the subtree has not been delegated to a child final DOMDataTreeProducer child = lookupChild(s); Preconditions.checkArgument(child == null, "Subtree %s is delegated to child producer %s", s, child); @@ -154,7 +152,8 @@ final class ShardedDOMDataTreeProducer implements DOMDataTreeProducer { // Check if part of the requested subtree is not delegated to a child. for (final DOMDataTreeIdentifier c : children.keySet()) { if (s.contains(c)) { - throw new IllegalArgumentException(String.format("Subtree %s cannot be delegated as it is superset of already-delegated %s", s, c)); + throw new IllegalArgumentException(String.format("Subtree %s cannot be delegated as it is" + + " superset of already-delegated %s", s, c)); } } } @@ -170,6 +169,16 @@ final class ShardedDOMDataTreeProducer implements DOMDataTreeProducer { return ret; } + boolean isDelegatedToChild(final DOMDataTreeIdentifier path) { + for (final DOMDataTreeIdentifier c : children.keySet()) { + if (c.contains(path)) { + return true; + } + } + return false; + } + + @Override public synchronized void close() throws DOMDataTreeProducerException { if (!closed) { @@ -182,24 +191,11 @@ final class ShardedDOMDataTreeProducer implements DOMDataTreeProducer { } } - static DOMDataTreeProducer create(final ShardedDOMDataTree dataTree, final Map shardMap) { - /* - * FIXME: we do not allow multiple multiple shards in a producer because we do not implement the - * synchronization primitives yet - */ - final Set shards = ImmutableSet.copyOf(shardMap.values()); - if (shards.size() > 1) { - throw new UnsupportedOperationException("Cross-shard producers are not supported yet"); - } - - return new ShardedDOMDataTreeProducer(dataTree, shardMap, shards); - } - - Set getSubtrees() { - return idToShard.keySet(); + protected Set getSubtrees() { + return subtrees; } - synchronized void cancelTransaction(final ShardedDOMDataWriteTransaction transaction) { + synchronized void cancelTransaction(final ShardedDOMDataTreeWriteTransaction transaction) { if (!openTx.equals(transaction)) { LOG.warn("Transaction {} is not open in producer {}", transaction, this); return; @@ -208,4 +204,17 @@ final class ShardedDOMDataTreeProducer implements DOMDataTreeProducer { LOG.debug("Transaction {} cancelled", transaction); openTx = null; } + + synchronized void transactionSubmitted(final ShardedDOMDataTreeWriteTransaction transaction) { + Preconditions.checkState(openTx.equals(transaction)); + openTx = null; + } + + synchronized void boundToListener(final ShardedDOMDataTreeListenerContext listener) { + // FIXME: Add option to dettach + Preconditions.checkState(this.attachedListener == null, + "Producer %s is already attached to other listener.", + listener.getListener()); + this.attachedListener = listener; + } }