Committed by
Gerrit Code Review
Supporting Atomix classes for DocumentTree distributed primitive
Change-Id: I754222337401f90f976d4152b6abbdf2e1a4df8e
Showing
12 changed files
with
821 additions
and
16 deletions
| 1 | +/* | ||
| 2 | + * Copyright 2016-present Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +package org.onosproject.store.service; | ||
| 18 | + | ||
| 19 | +import java.util.Map; | ||
| 20 | +import java.util.concurrent.CompletableFuture; | ||
| 21 | + | ||
| 22 | +import javax.annotation.concurrent.NotThreadSafe; | ||
| 23 | + | ||
| 24 | +/** | ||
| 25 | + * A hierarchical <a href="https://en.wikipedia.org/wiki/Document_Object_Model">document tree</a> data structure. | ||
| 26 | + * | ||
| 27 | + * @param <V> document tree value type | ||
| 28 | + */ | ||
| 29 | +@NotThreadSafe | ||
| 30 | +public interface AsyncDocumentTree<V> extends DistributedPrimitive { | ||
| 31 | + | ||
| 32 | + /** | ||
| 33 | + * Returns the {@link DocumentPath path} to root of the tree. | ||
| 34 | + * | ||
| 35 | + * @return path to root of the tree | ||
| 36 | + */ | ||
| 37 | + DocumentPath root(); | ||
| 38 | + | ||
| 39 | + /** | ||
| 40 | + * Returns the child values for this node. | ||
| 41 | + * | ||
| 42 | + * @param path path to the node | ||
| 43 | + * @return future for mapping from a child name to its value | ||
| 44 | + * @throws NoSuchDocumentPathException if the path does not point to a valid node | ||
| 45 | + */ | ||
| 46 | + CompletableFuture<Map<String, Versioned<V>>> getChildren(DocumentPath path); | ||
| 47 | + | ||
| 48 | + /** | ||
| 49 | + * Returns a value (and version) of the tree node at specified path. | ||
| 50 | + * | ||
| 51 | + * @param path path to node | ||
| 52 | + * @return future for node value or {@code null} if path does not point to a valid node | ||
| 53 | + */ | ||
| 54 | + CompletableFuture<Versioned<V>> get(DocumentPath path); | ||
| 55 | + | ||
| 56 | + /** | ||
| 57 | + * Creates or updates a document tree node. | ||
| 58 | + * | ||
| 59 | + * @param path path for the node to create or update | ||
| 60 | + * @param value the non-null value to be associated with the key | ||
| 61 | + * @return future for the previous mapping or {@code null} if there was no previous mapping. Future will | ||
| 62 | + * be completed with a NoSuchDocumentPathException if the parent node (for the node to create/update) does not exist | ||
| 63 | + */ | ||
| 64 | + CompletableFuture<Versioned<V>> set(DocumentPath path, V value); | ||
| 65 | + | ||
| 66 | + /** | ||
| 67 | + * Creates a document tree node if one does not exist already. | ||
| 68 | + * | ||
| 69 | + * @param path path for the node to create | ||
| 70 | + * @param value the non-null value to be associated with the key | ||
| 71 | + * @return future that is completed with {@code true} if the mapping could be added | ||
| 72 | + * successfully; {@code false} otherwise. Future will be completed with a | ||
| 73 | + * IllegalDocumentModificationException if the parent node (for the node to create) does not exist | ||
| 74 | + */ | ||
| 75 | + CompletableFuture<Boolean> create(DocumentPath path, V value); | ||
| 76 | + | ||
| 77 | + /** | ||
| 78 | + * Conditionally updates a tree node if the current version matches a specified version. | ||
| 79 | + * | ||
| 80 | + * @param path path for the node to create | ||
| 81 | + * @param newValue the non-null value to be associated with the key | ||
| 82 | + * @param version current version of the value for update to occur | ||
| 83 | + * @return future that is completed with {@code true} if the update was made and the tree was | ||
| 84 | + * modified, {@code false} otherwise. | ||
| 85 | + */ | ||
| 86 | + CompletableFuture<Boolean> replace(DocumentPath path, V newValue, long version); | ||
| 87 | + | ||
| 88 | + /** | ||
| 89 | + * Conditionally updates a tree node if the current value matches a specified value. | ||
| 90 | + * | ||
| 91 | + * @param path path for the node to create | ||
| 92 | + * @param newValue the non-null value to be associated with the key | ||
| 93 | + * @param currentValue current value for update to occur | ||
| 94 | + * @return future that is completed with {@code true} if the update was made and the tree was | ||
| 95 | + * modified, {@code false} otherwise. | ||
| 96 | + */ | ||
| 97 | + CompletableFuture<Boolean> replace(DocumentPath path, V newValue, V currentValue); | ||
| 98 | + | ||
| 99 | + /** | ||
| 100 | + * Removes the node with the specified path. | ||
| 101 | + * | ||
| 102 | + * @param path path for the node to remove | ||
| 103 | + * @return future for the previous value. Future will be completed with a | ||
| 104 | + * IllegalDocumentModificationException if the node to be removed is either the root | ||
| 105 | + * node or has one or more children. Future will be completed with a | ||
| 106 | + * NoSuchDocumentPathException if the node to be removed does not exist | ||
| 107 | + */ | ||
| 108 | + CompletableFuture<Versioned<V>> removeNode(DocumentPath path); | ||
| 109 | + | ||
| 110 | + /** | ||
| 111 | + * Registers a listener to be notified when a subtree rooted at the specified path | ||
| 112 | + * is modified. | ||
| 113 | + * | ||
| 114 | + * @param path path to root of subtree to monitor for updates | ||
| 115 | + * @param listener listener to be notified | ||
| 116 | + */ | ||
| 117 | + CompletableFuture<Void> addListener(DocumentPath path, DocumentTreeListener<V> listener); | ||
| 118 | + | ||
| 119 | + /** | ||
| 120 | + * Unregisters a previously added listener. | ||
| 121 | + * | ||
| 122 | + * @param listener listener to unregister | ||
| 123 | + */ | ||
| 124 | + CompletableFuture<Void> removeListener(DocumentTreeListener<V> listener); | ||
| 125 | + | ||
| 126 | + /** | ||
| 127 | + * Registers a listener to be notified when the tree is modified. | ||
| 128 | + * | ||
| 129 | + * @param listener listener to be notified | ||
| 130 | + */ | ||
| 131 | + default CompletableFuture<Void> addListener(DocumentTreeListener<V> listener) { | ||
| 132 | + return addListener(root(), listener); | ||
| 133 | + } | ||
| 134 | +} |
| ... | @@ -72,6 +72,11 @@ public interface DistributedPrimitive { | ... | @@ -72,6 +72,11 @@ public interface DistributedPrimitive { |
| 72 | WORK_QUEUE, | 72 | WORK_QUEUE, |
| 73 | 73 | ||
| 74 | /** | 74 | /** |
| 75 | + * Document tree. | ||
| 76 | + */ | ||
| 77 | + DOCUMENT_TREE, | ||
| 78 | + | ||
| 79 | + /** | ||
| 75 | * Distributed topic. | 80 | * Distributed topic. |
| 76 | */ | 81 | */ |
| 77 | TOPIC, | 82 | TOPIC, | ... | ... |
| ... | @@ -52,6 +52,14 @@ public class DocumentTreeEvent<V> { | ... | @@ -52,6 +52,14 @@ public class DocumentTreeEvent<V> { |
| 52 | private final Optional<Versioned<V>> newValue; | 52 | private final Optional<Versioned<V>> newValue; |
| 53 | private final Optional<Versioned<V>> oldValue; | 53 | private final Optional<Versioned<V>> oldValue; |
| 54 | 54 | ||
| 55 | + @SuppressWarnings("unused") | ||
| 56 | + private DocumentTreeEvent() { | ||
| 57 | + this.path = null; | ||
| 58 | + this.type = null; | ||
| 59 | + this.newValue = null; | ||
| 60 | + this.oldValue = null; | ||
| 61 | + } | ||
| 62 | + | ||
| 55 | /** | 63 | /** |
| 56 | * Constructs a new {@code DocumentTreeEvent}. | 64 | * Constructs a new {@code DocumentTreeEvent}. |
| 57 | * | 65 | * | ... | ... |
| ... | @@ -15,12 +15,13 @@ | ... | @@ -15,12 +15,13 @@ |
| 15 | */ | 15 | */ |
| 16 | package org.onosproject.store.primitives.impl; | 16 | package org.onosproject.store.primitives.impl; |
| 17 | 17 | ||
| 18 | -import com.google.common.collect.ImmutableList; | ||
| 19 | -import com.google.common.collect.Maps; | ||
| 20 | import io.atomix.catalyst.serializer.Serializer; | 18 | import io.atomix.catalyst.serializer.Serializer; |
| 21 | import io.atomix.catalyst.serializer.TypeSerializerFactory; | 19 | import io.atomix.catalyst.serializer.TypeSerializerFactory; |
| 22 | import io.atomix.manager.util.ResourceManagerTypeResolver; | 20 | import io.atomix.manager.util.ResourceManagerTypeResolver; |
| 23 | import io.atomix.variables.internal.LongCommands; | 21 | import io.atomix.variables.internal.LongCommands; |
| 22 | + | ||
| 23 | +import java.util.Arrays; | ||
| 24 | + | ||
| 24 | import org.onlab.util.Match; | 25 | import org.onlab.util.Match; |
| 25 | import org.onosproject.cluster.Leader; | 26 | import org.onosproject.cluster.Leader; |
| 26 | import org.onosproject.cluster.Leadership; | 27 | import org.onosproject.cluster.Leadership; |
| ... | @@ -34,22 +35,28 @@ import org.onosproject.store.primitives.resources.impl.AtomixConsistentMultimapC | ... | @@ -34,22 +35,28 @@ import org.onosproject.store.primitives.resources.impl.AtomixConsistentMultimapC |
| 34 | import org.onosproject.store.primitives.resources.impl.AtomixConsistentSetMultimapFactory; | 35 | import org.onosproject.store.primitives.resources.impl.AtomixConsistentSetMultimapFactory; |
| 35 | import org.onosproject.store.primitives.resources.impl.AtomixConsistentTreeMapCommands; | 36 | import org.onosproject.store.primitives.resources.impl.AtomixConsistentTreeMapCommands; |
| 36 | import org.onosproject.store.primitives.resources.impl.AtomixConsistentTreeMapFactory; | 37 | import org.onosproject.store.primitives.resources.impl.AtomixConsistentTreeMapFactory; |
| 38 | +import org.onosproject.store.primitives.resources.impl.AtomixDocumentTreeCommands; | ||
| 39 | +import org.onosproject.store.primitives.resources.impl.AtomixDocumentTreeFactory; | ||
| 37 | import org.onosproject.store.primitives.resources.impl.AtomixLeaderElectorCommands; | 40 | import org.onosproject.store.primitives.resources.impl.AtomixLeaderElectorCommands; |
| 38 | import org.onosproject.store.primitives.resources.impl.AtomixLeaderElectorFactory; | 41 | import org.onosproject.store.primitives.resources.impl.AtomixLeaderElectorFactory; |
| 39 | import org.onosproject.store.primitives.resources.impl.AtomixWorkQueueCommands; | 42 | import org.onosproject.store.primitives.resources.impl.AtomixWorkQueueCommands; |
| 40 | import org.onosproject.store.primitives.resources.impl.AtomixWorkQueueFactory; | 43 | import org.onosproject.store.primitives.resources.impl.AtomixWorkQueueFactory; |
| 41 | import org.onosproject.store.primitives.resources.impl.CommitResult; | 44 | import org.onosproject.store.primitives.resources.impl.CommitResult; |
| 45 | +import org.onosproject.store.primitives.resources.impl.DocumentTreeUpdateResult; | ||
| 42 | import org.onosproject.store.primitives.resources.impl.MapEntryUpdateResult; | 46 | import org.onosproject.store.primitives.resources.impl.MapEntryUpdateResult; |
| 43 | import org.onosproject.store.primitives.resources.impl.PrepareResult; | 47 | import org.onosproject.store.primitives.resources.impl.PrepareResult; |
| 44 | import org.onosproject.store.primitives.resources.impl.RollbackResult; | 48 | import org.onosproject.store.primitives.resources.impl.RollbackResult; |
| 45 | import org.onosproject.store.serializers.KryoNamespaces; | 49 | import org.onosproject.store.serializers.KryoNamespaces; |
| 50 | +import org.onosproject.store.service.DocumentPath; | ||
| 51 | +import org.onosproject.store.service.DocumentTreeEvent; | ||
| 46 | import org.onosproject.store.service.MapEvent; | 52 | import org.onosproject.store.service.MapEvent; |
| 47 | import org.onosproject.store.service.MapTransaction; | 53 | import org.onosproject.store.service.MapTransaction; |
| 48 | import org.onosproject.store.service.Task; | 54 | import org.onosproject.store.service.Task; |
| 49 | import org.onosproject.store.service.Versioned; | 55 | import org.onosproject.store.service.Versioned; |
| 50 | import org.onosproject.store.service.WorkQueueStats; | 56 | import org.onosproject.store.service.WorkQueueStats; |
| 51 | 57 | ||
| 52 | -import java.util.Arrays; | 58 | +import com.google.common.collect.ImmutableList; |
| 59 | +import com.google.common.collect.Maps; | ||
| 53 | 60 | ||
| 54 | /** | 61 | /** |
| 55 | * Serializer utility for Atomix Catalyst. | 62 | * Serializer utility for Atomix Catalyst. |
| ... | @@ -69,6 +76,11 @@ public final class CatalystSerializers { | ... | @@ -69,6 +76,11 @@ public final class CatalystSerializers { |
| 69 | Transaction.State.class, | 76 | Transaction.State.class, |
| 70 | PrepareResult.class, | 77 | PrepareResult.class, |
| 71 | CommitResult.class, | 78 | CommitResult.class, |
| 79 | + DocumentPath.class, | ||
| 80 | + DocumentTreeUpdateResult.class, | ||
| 81 | + DocumentTreeUpdateResult.Status.class, | ||
| 82 | + DocumentTreeEvent.class, | ||
| 83 | + DocumentTreeEvent.Type.class, | ||
| 72 | RollbackResult.class)); | 84 | RollbackResult.class)); |
| 73 | // ONOS classes | 85 | // ONOS classes |
| 74 | serializer.register(Change.class, factory); | 86 | serializer.register(Change.class, factory); |
| ... | @@ -90,6 +102,11 @@ public final class CatalystSerializers { | ... | @@ -90,6 +102,11 @@ public final class CatalystSerializers { |
| 90 | serializer.register(MapEvent.class, factory); | 102 | serializer.register(MapEvent.class, factory); |
| 91 | serializer.register(Task.class, factory); | 103 | serializer.register(Task.class, factory); |
| 92 | serializer.register(WorkQueueStats.class, factory); | 104 | serializer.register(WorkQueueStats.class, factory); |
| 105 | + serializer.register(DocumentPath.class, factory); | ||
| 106 | + serializer.register(DocumentTreeUpdateResult.class, factory); | ||
| 107 | + serializer.register(DocumentTreeUpdateResult.Status.class, factory); | ||
| 108 | + serializer.register(DocumentTreeEvent.class, factory); | ||
| 109 | + serializer.register(DocumentTreeEvent.Type.class, factory); | ||
| 93 | serializer.register(Maps.immutableEntry("a", "b").getClass(), factory); | 110 | serializer.register(Maps.immutableEntry("a", "b").getClass(), factory); |
| 94 | serializer.register(ImmutableList.of().getClass(), factory); | 111 | serializer.register(ImmutableList.of().getClass(), factory); |
| 95 | 112 | ||
| ... | @@ -97,6 +114,7 @@ public final class CatalystSerializers { | ... | @@ -97,6 +114,7 @@ public final class CatalystSerializers { |
| 97 | serializer.resolve(new AtomixConsistentMapCommands.TypeResolver()); | 114 | serializer.resolve(new AtomixConsistentMapCommands.TypeResolver()); |
| 98 | serializer.resolve(new AtomixLeaderElectorCommands.TypeResolver()); | 115 | serializer.resolve(new AtomixLeaderElectorCommands.TypeResolver()); |
| 99 | serializer.resolve(new AtomixWorkQueueCommands.TypeResolver()); | 116 | serializer.resolve(new AtomixWorkQueueCommands.TypeResolver()); |
| 117 | + serializer.resolve(new AtomixDocumentTreeCommands.TypeResolver()); | ||
| 100 | serializer.resolve(new ResourceManagerTypeResolver()); | 118 | serializer.resolve(new ResourceManagerTypeResolver()); |
| 101 | serializer.resolve(new AtomixConsistentTreeMapCommands.TypeResolver()); | 119 | serializer.resolve(new AtomixConsistentTreeMapCommands.TypeResolver()); |
| 102 | serializer.resolve(new AtomixConsistentMultimapCommands.TypeResolver()); | 120 | serializer.resolve(new AtomixConsistentMultimapCommands.TypeResolver()); |
| ... | @@ -104,6 +122,7 @@ public final class CatalystSerializers { | ... | @@ -104,6 +122,7 @@ public final class CatalystSerializers { |
| 104 | serializer.registerClassLoader(AtomixConsistentMapFactory.class) | 122 | serializer.registerClassLoader(AtomixConsistentMapFactory.class) |
| 105 | .registerClassLoader(AtomixLeaderElectorFactory.class) | 123 | .registerClassLoader(AtomixLeaderElectorFactory.class) |
| 106 | .registerClassLoader(AtomixWorkQueueFactory.class) | 124 | .registerClassLoader(AtomixWorkQueueFactory.class) |
| 125 | + .registerClassLoader(AtomixDocumentTreeFactory.class) | ||
| 107 | .registerClassLoader(AtomixConsistentTreeMapFactory.class) | 126 | .registerClassLoader(AtomixConsistentTreeMapFactory.class) |
| 108 | .registerClassLoader(AtomixConsistentSetMultimapFactory.class); | 127 | .registerClassLoader(AtomixConsistentSetMultimapFactory.class); |
| 109 | 128 | ... | ... |
| ... | @@ -15,14 +15,15 @@ | ... | @@ -15,14 +15,15 @@ |
| 15 | */ | 15 | */ |
| 16 | package org.onosproject.store.primitives.resources.impl; | 16 | package org.onosproject.store.primitives.resources.impl; |
| 17 | 17 | ||
| 18 | +import static com.google.common.base.Preconditions.checkState; | ||
| 18 | import static org.onosproject.store.service.MapEvent.Type.INSERT; | 19 | import static org.onosproject.store.service.MapEvent.Type.INSERT; |
| 19 | import static org.onosproject.store.service.MapEvent.Type.REMOVE; | 20 | import static org.onosproject.store.service.MapEvent.Type.REMOVE; |
| 20 | import static org.onosproject.store.service.MapEvent.Type.UPDATE; | 21 | import static org.onosproject.store.service.MapEvent.Type.UPDATE; |
| 21 | import static org.slf4j.LoggerFactory.getLogger; | 22 | import static org.slf4j.LoggerFactory.getLogger; |
| 22 | -import io.atomix.copycat.server.session.ServerSession; | ||
| 23 | import io.atomix.copycat.server.Commit; | 23 | import io.atomix.copycat.server.Commit; |
| 24 | import io.atomix.copycat.server.Snapshottable; | 24 | import io.atomix.copycat.server.Snapshottable; |
| 25 | import io.atomix.copycat.server.StateMachineExecutor; | 25 | import io.atomix.copycat.server.StateMachineExecutor; |
| 26 | +import io.atomix.copycat.server.session.ServerSession; | ||
| 26 | import io.atomix.copycat.server.session.SessionListener; | 27 | import io.atomix.copycat.server.session.SessionListener; |
| 27 | import io.atomix.copycat.server.storage.snapshot.SnapshotReader; | 28 | import io.atomix.copycat.server.storage.snapshot.SnapshotReader; |
| 28 | import io.atomix.copycat.server.storage.snapshot.SnapshotWriter; | 29 | import io.atomix.copycat.server.storage.snapshot.SnapshotWriter; |
| ... | @@ -68,15 +69,13 @@ import com.google.common.collect.Lists; | ... | @@ -68,15 +69,13 @@ import com.google.common.collect.Lists; |
| 68 | import com.google.common.collect.Maps; | 69 | import com.google.common.collect.Maps; |
| 69 | import com.google.common.collect.Sets; | 70 | import com.google.common.collect.Sets; |
| 70 | 71 | ||
| 71 | -import static com.google.common.base.Preconditions.checkState; | ||
| 72 | - | ||
| 73 | /** | 72 | /** |
| 74 | * State Machine for {@link AtomixConsistentMap} resource. | 73 | * State Machine for {@link AtomixConsistentMap} resource. |
| 75 | */ | 74 | */ |
| 76 | public class AtomixConsistentMapState extends ResourceStateMachine implements SessionListener, Snapshottable { | 75 | public class AtomixConsistentMapState extends ResourceStateMachine implements SessionListener, Snapshottable { |
| 77 | 76 | ||
| 78 | private final Logger log = getLogger(getClass()); | 77 | private final Logger log = getLogger(getClass()); |
| 79 | - private final Map<Long, Commit<? extends AtomixConsistentMapCommands.Listen>> listeners = new HashMap<>(); | 78 | + private final Map<Long, Commit<? extends Listen>> listeners = new HashMap<>(); |
| 80 | private final Map<String, MapEntryValue> mapEntries = new HashMap<>(); | 79 | private final Map<String, MapEntryValue> mapEntries = new HashMap<>(); |
| 81 | private final Set<String> preparedKeys = Sets.newHashSet(); | 80 | private final Set<String> preparedKeys = Sets.newHashSet(); |
| 82 | private final Map<TransactionId, Commit<? extends TransactionPrepare>> pendingTransactions = Maps.newHashMap(); | 81 | private final Map<TransactionId, Commit<? extends TransactionPrepare>> pendingTransactions = Maps.newHashMap(); | ... | ... |
| 1 | +/* | ||
| 2 | + * Copyright 2016-present Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +package org.onosproject.store.primitives.resources.impl; | ||
| 18 | + | ||
| 19 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
| 20 | +import io.atomix.copycat.client.CopycatClient; | ||
| 21 | +import io.atomix.resource.AbstractResource; | ||
| 22 | +import io.atomix.resource.ResourceTypeInfo; | ||
| 23 | + | ||
| 24 | +import java.util.HashMap; | ||
| 25 | +import java.util.List; | ||
| 26 | +import java.util.Map; | ||
| 27 | +import java.util.Properties; | ||
| 28 | +import java.util.concurrent.CompletableFuture; | ||
| 29 | +import java.util.concurrent.Executor; | ||
| 30 | + | ||
| 31 | +import org.onlab.util.Match; | ||
| 32 | +import org.onlab.util.Tools; | ||
| 33 | +import org.onosproject.store.primitives.resources.impl.AtomixConsistentMapCommands.Unlisten; | ||
| 34 | +import org.onosproject.store.primitives.resources.impl.AtomixDocumentTreeCommands.Clear; | ||
| 35 | +import org.onosproject.store.primitives.resources.impl.AtomixDocumentTreeCommands.Get; | ||
| 36 | +import org.onosproject.store.primitives.resources.impl.AtomixDocumentTreeCommands.GetChildren; | ||
| 37 | +import org.onosproject.store.primitives.resources.impl.AtomixDocumentTreeCommands.Listen; | ||
| 38 | +import org.onosproject.store.primitives.resources.impl.AtomixDocumentTreeCommands.Update; | ||
| 39 | +import org.onosproject.store.service.AsyncDocumentTree; | ||
| 40 | +import org.onosproject.store.service.DocumentPath; | ||
| 41 | +import org.onosproject.store.service.DocumentTreeEvent; | ||
| 42 | +import org.onosproject.store.service.DocumentTreeListener; | ||
| 43 | +import org.onosproject.store.service.IllegalDocumentModificationException; | ||
| 44 | +import org.onosproject.store.service.NoSuchDocumentPathException; | ||
| 45 | +import org.onosproject.store.service.Versioned; | ||
| 46 | + | ||
| 47 | +import com.google.common.util.concurrent.MoreExecutors; | ||
| 48 | + | ||
| 49 | +/** | ||
| 50 | + * Distributed resource providing the {@link AsyncDocumentTree} primitive. | ||
| 51 | + */ | ||
| 52 | +@ResourceTypeInfo(id = -156, factory = AtomixDocumentTreeFactory.class) | ||
| 53 | +public class AtomixDocumentTree extends AbstractResource<AtomixDocumentTree> | ||
| 54 | + implements AsyncDocumentTree<byte[]> { | ||
| 55 | + | ||
| 56 | + private final Map<DocumentTreeListener<byte[]>, Executor> eventListeners = new HashMap<>(); | ||
| 57 | + public static final String CHANGE_SUBJECT = "changeEvents"; | ||
| 58 | + | ||
| 59 | + protected AtomixDocumentTree(CopycatClient client, Properties options) { | ||
| 60 | + super(client, options); | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | + @Override | ||
| 64 | + public CompletableFuture<AtomixDocumentTree> open() { | ||
| 65 | + return super.open().thenApply(result -> { | ||
| 66 | + client.onStateChange(state -> { | ||
| 67 | + if (state == CopycatClient.State.CONNECTED && isListening()) { | ||
| 68 | + client.submit(new Listen()); | ||
| 69 | + } | ||
| 70 | + }); | ||
| 71 | + client.onEvent(CHANGE_SUBJECT, this::processTreeUpdates); | ||
| 72 | + return result; | ||
| 73 | + }); | ||
| 74 | + } | ||
| 75 | + | ||
| 76 | + @Override | ||
| 77 | + public String name() { | ||
| 78 | + return null; | ||
| 79 | + } | ||
| 80 | + | ||
| 81 | + @Override | ||
| 82 | + public Type primitiveType() { | ||
| 83 | + return Type.DOCUMENT_TREE; | ||
| 84 | + } | ||
| 85 | + | ||
| 86 | + @Override | ||
| 87 | + public CompletableFuture<Void> destroy() { | ||
| 88 | + return client.submit(new Clear()); | ||
| 89 | + } | ||
| 90 | + | ||
| 91 | + @Override | ||
| 92 | + public DocumentPath root() { | ||
| 93 | + return DocumentPath.from("root"); | ||
| 94 | + } | ||
| 95 | + | ||
| 96 | + @Override | ||
| 97 | + public CompletableFuture<Map<String, Versioned<byte[]>>> getChildren(DocumentPath path) { | ||
| 98 | + return client.submit(new GetChildren(checkNotNull(path))); | ||
| 99 | + } | ||
| 100 | + | ||
| 101 | + @Override | ||
| 102 | + public CompletableFuture<Versioned<byte[]>> get(DocumentPath path) { | ||
| 103 | + return client.submit(new Get(checkNotNull(path))); | ||
| 104 | + } | ||
| 105 | + | ||
| 106 | + @Override | ||
| 107 | + public CompletableFuture<Versioned<byte[]>> set(DocumentPath path, byte[] value) { | ||
| 108 | + return client.submit(new Update(checkNotNull(path), checkNotNull(value), Match.any(), Match.any())) | ||
| 109 | + .thenCompose(result -> { | ||
| 110 | + if (result.status() == DocumentTreeUpdateResult.Status.INVALID_PATH) { | ||
| 111 | + return Tools.exceptionalFuture(new NoSuchDocumentPathException()); | ||
| 112 | + } else if (result.status() == DocumentTreeUpdateResult.Status.ILLEGAL_MODIFICATION) { | ||
| 113 | + return Tools.exceptionalFuture(new IllegalDocumentModificationException()); | ||
| 114 | + } else { | ||
| 115 | + return CompletableFuture.completedFuture(result); | ||
| 116 | + } | ||
| 117 | + }).thenApply(result -> result.oldValue()); | ||
| 118 | + } | ||
| 119 | + | ||
| 120 | + @Override | ||
| 121 | + public CompletableFuture<Boolean> create(DocumentPath path, byte[] value) { | ||
| 122 | + return client.submit(new Update(checkNotNull(path), checkNotNull(value), Match.ifNull(), Match.any())) | ||
| 123 | + .thenCompose(result -> { | ||
| 124 | + if (result.status() == DocumentTreeUpdateResult.Status.INVALID_PATH) { | ||
| 125 | + return Tools.exceptionalFuture(new NoSuchDocumentPathException()); | ||
| 126 | + } else if (result.status() == DocumentTreeUpdateResult.Status.ILLEGAL_MODIFICATION) { | ||
| 127 | + return Tools.exceptionalFuture(new IllegalDocumentModificationException()); | ||
| 128 | + } else { | ||
| 129 | + return CompletableFuture.completedFuture(result); | ||
| 130 | + } | ||
| 131 | + }).thenApply(result -> result.created()); | ||
| 132 | + } | ||
| 133 | + | ||
| 134 | + @Override | ||
| 135 | + public CompletableFuture<Boolean> replace(DocumentPath path, byte[] newValue, long version) { | ||
| 136 | + return client.submit(new Update(checkNotNull(path), newValue, Match.any(), Match.ifValue(version))) | ||
| 137 | + .thenApply(result -> result.updated()); | ||
| 138 | + } | ||
| 139 | + | ||
| 140 | + @Override | ||
| 141 | + public CompletableFuture<Boolean> replace(DocumentPath path, byte[] newValue, byte[] currentValue) { | ||
| 142 | + return client.submit(new Update(checkNotNull(path), newValue, Match.ifValue(currentValue), Match.any())) | ||
| 143 | + .thenCompose(result -> { | ||
| 144 | + if (result.status() == DocumentTreeUpdateResult.Status.INVALID_PATH) { | ||
| 145 | + return Tools.exceptionalFuture(new NoSuchDocumentPathException()); | ||
| 146 | + } else if (result.status() == DocumentTreeUpdateResult.Status.ILLEGAL_MODIFICATION) { | ||
| 147 | + return Tools.exceptionalFuture(new IllegalDocumentModificationException()); | ||
| 148 | + } else { | ||
| 149 | + return CompletableFuture.completedFuture(result); | ||
| 150 | + } | ||
| 151 | + }).thenApply(result -> result.updated()); | ||
| 152 | + } | ||
| 153 | + | ||
| 154 | + @Override | ||
| 155 | + public CompletableFuture<Versioned<byte[]>> removeNode(DocumentPath path) { | ||
| 156 | + if (path.equals(DocumentPath.from("root"))) { | ||
| 157 | + return Tools.exceptionalFuture(new IllegalDocumentModificationException()); | ||
| 158 | + } | ||
| 159 | + return client.submit(new Update(checkNotNull(path), null, Match.ifNotNull(), Match.any())) | ||
| 160 | + .thenCompose(result -> { | ||
| 161 | + if (result.status() == DocumentTreeUpdateResult.Status.INVALID_PATH) { | ||
| 162 | + return Tools.exceptionalFuture(new NoSuchDocumentPathException()); | ||
| 163 | + } else if (result.status() == DocumentTreeUpdateResult.Status.ILLEGAL_MODIFICATION) { | ||
| 164 | + return Tools.exceptionalFuture(new IllegalDocumentModificationException()); | ||
| 165 | + } else { | ||
| 166 | + return CompletableFuture.completedFuture(result); | ||
| 167 | + } | ||
| 168 | + }).thenApply(result -> result.oldValue()); | ||
| 169 | + } | ||
| 170 | + | ||
| 171 | + @Override | ||
| 172 | + public CompletableFuture<Void> addListener(DocumentPath path, DocumentTreeListener<byte[]> listener) { | ||
| 173 | + checkNotNull(path); | ||
| 174 | + checkNotNull(listener); | ||
| 175 | + // TODO: Support API that takes an executor | ||
| 176 | + if (isListening()) { | ||
| 177 | + eventListeners.putIfAbsent(listener, MoreExecutors.directExecutor()); | ||
| 178 | + return CompletableFuture.completedFuture(null); | ||
| 179 | + } else { | ||
| 180 | + return client.submit(new Listen(path)) | ||
| 181 | + .thenRun(() -> eventListeners.put(listener, MoreExecutors.directExecutor())); | ||
| 182 | + } | ||
| 183 | + } | ||
| 184 | + | ||
| 185 | + @Override | ||
| 186 | + public CompletableFuture<Void> removeListener(DocumentTreeListener<byte[]> listener) { | ||
| 187 | + checkNotNull(listener); | ||
| 188 | + if (eventListeners.remove(listener) != null && eventListeners.isEmpty()) { | ||
| 189 | + return client.submit(new Unlisten()).thenApply(v -> null); | ||
| 190 | + } | ||
| 191 | + return CompletableFuture.completedFuture(null); | ||
| 192 | + } | ||
| 193 | + | ||
| 194 | + private boolean isListening() { | ||
| 195 | + return !eventListeners.isEmpty(); | ||
| 196 | + } | ||
| 197 | + | ||
| 198 | + private void processTreeUpdates(List<DocumentTreeEvent<byte[]>> events) { | ||
| 199 | + events.forEach(event -> | ||
| 200 | + eventListeners.forEach((listener, executor) -> executor.execute(() -> listener.event(event)))); | ||
| 201 | + } | ||
| 202 | +} |
| 1 | +/* | ||
| 2 | + * Copyright 2016-present Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +package org.onosproject.store.primitives.resources.impl; | ||
| 18 | + | ||
| 19 | +import io.atomix.catalyst.buffer.BufferInput; | ||
| 20 | +import io.atomix.catalyst.buffer.BufferOutput; | ||
| 21 | +import io.atomix.catalyst.serializer.CatalystSerializable; | ||
| 22 | +import io.atomix.catalyst.serializer.SerializableTypeResolver; | ||
| 23 | +import io.atomix.catalyst.serializer.Serializer; | ||
| 24 | +import io.atomix.catalyst.serializer.SerializerRegistry; | ||
| 25 | +import io.atomix.copycat.Command; | ||
| 26 | +import io.atomix.copycat.Query; | ||
| 27 | + | ||
| 28 | +import java.util.Map; | ||
| 29 | + | ||
| 30 | +import org.onlab.util.Match; | ||
| 31 | +import org.onosproject.store.service.DocumentPath; | ||
| 32 | +import org.onosproject.store.service.Versioned; | ||
| 33 | + | ||
| 34 | +import com.google.common.base.MoreObjects; | ||
| 35 | + | ||
| 36 | +/** | ||
| 37 | + * {@link AtomixDocumentTree} resource state machine operations. | ||
| 38 | + */ | ||
| 39 | +public class AtomixDocumentTreeCommands { | ||
| 40 | + | ||
| 41 | + /** | ||
| 42 | + * Abstract DocumentTree operation. | ||
| 43 | + */ | ||
| 44 | + public abstract static class DocumentTreeOperation<V> implements CatalystSerializable { | ||
| 45 | + | ||
| 46 | + private DocumentPath path; | ||
| 47 | + | ||
| 48 | + DocumentTreeOperation(DocumentPath path) { | ||
| 49 | + this.path = path; | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | + public DocumentPath path() { | ||
| 53 | + return path; | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + @Override | ||
| 57 | + public void writeObject(BufferOutput<?> buffer, Serializer serializer) { | ||
| 58 | + serializer.writeObject(path, buffer); | ||
| 59 | + } | ||
| 60 | + | ||
| 61 | + @Override | ||
| 62 | + public void readObject(BufferInput<?> buffer, Serializer serializer) { | ||
| 63 | + path = serializer.readObject(buffer); | ||
| 64 | + } | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + /** | ||
| 68 | + * Abstract DocumentTree query. | ||
| 69 | + */ | ||
| 70 | + @SuppressWarnings("serial") | ||
| 71 | + public abstract static class DocumentTreeQuery<V> extends DocumentTreeOperation<V> implements Query<V> { | ||
| 72 | + | ||
| 73 | + DocumentTreeQuery(DocumentPath path) { | ||
| 74 | + super(path); | ||
| 75 | + } | ||
| 76 | + | ||
| 77 | + @Override | ||
| 78 | + public ConsistencyLevel consistency() { | ||
| 79 | + return ConsistencyLevel.SEQUENTIAL; | ||
| 80 | + } | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + /** | ||
| 84 | + * Abstract DocumentTree command. | ||
| 85 | + */ | ||
| 86 | + @SuppressWarnings("serial") | ||
| 87 | + public abstract static class DocumentTreeCommand<V> extends DocumentTreeOperation<V> implements Command<V> { | ||
| 88 | + | ||
| 89 | + DocumentTreeCommand(DocumentPath path) { | ||
| 90 | + super(path); | ||
| 91 | + } | ||
| 92 | + } | ||
| 93 | + | ||
| 94 | + /** | ||
| 95 | + * DocumentTree#get query. | ||
| 96 | + */ | ||
| 97 | + @SuppressWarnings("serial") | ||
| 98 | + public static class Get extends DocumentTreeQuery<Versioned<byte[]>> { | ||
| 99 | + public Get() { | ||
| 100 | + super(null); | ||
| 101 | + } | ||
| 102 | + | ||
| 103 | + public Get(DocumentPath path) { | ||
| 104 | + super(path); | ||
| 105 | + } | ||
| 106 | + | ||
| 107 | + @Override | ||
| 108 | + public String toString() { | ||
| 109 | + return MoreObjects.toStringHelper(getClass()) | ||
| 110 | + .add("path", path()) | ||
| 111 | + .toString(); | ||
| 112 | + } | ||
| 113 | + } | ||
| 114 | + | ||
| 115 | + /** | ||
| 116 | + * DocumentTree#getChildren query. | ||
| 117 | + */ | ||
| 118 | + @SuppressWarnings("serial") | ||
| 119 | + public static class GetChildren extends DocumentTreeQuery<Map<String, Versioned<byte[]>>> { | ||
| 120 | + public GetChildren() { | ||
| 121 | + super(null); | ||
| 122 | + } | ||
| 123 | + | ||
| 124 | + public GetChildren(DocumentPath path) { | ||
| 125 | + super(path); | ||
| 126 | + } | ||
| 127 | + | ||
| 128 | + @Override | ||
| 129 | + public String toString() { | ||
| 130 | + return MoreObjects.toStringHelper(getClass()) | ||
| 131 | + .add("path", path()) | ||
| 132 | + .toString(); | ||
| 133 | + } | ||
| 134 | + } | ||
| 135 | + | ||
| 136 | + /** | ||
| 137 | + * DocumentTree update command. | ||
| 138 | + */ | ||
| 139 | + @SuppressWarnings("serial") | ||
| 140 | + public static class Update extends DocumentTreeCommand<DocumentTreeUpdateResult<byte[]>> { | ||
| 141 | + | ||
| 142 | + private byte[] value; | ||
| 143 | + private Match<byte[]> valueMatch; | ||
| 144 | + private Match<Long> versionMatch; | ||
| 145 | + | ||
| 146 | + public Update() { | ||
| 147 | + super(null); | ||
| 148 | + this.value = null; | ||
| 149 | + this.valueMatch = null; | ||
| 150 | + this.versionMatch = null; | ||
| 151 | + } | ||
| 152 | + | ||
| 153 | + public Update(DocumentPath path, byte[] value, Match<byte[]> valueMatch, Match<Long> versionMatch) { | ||
| 154 | + super(path); | ||
| 155 | + this.value = value; | ||
| 156 | + this.valueMatch = valueMatch; | ||
| 157 | + this.versionMatch = versionMatch; | ||
| 158 | + } | ||
| 159 | + | ||
| 160 | + public byte[] value() { | ||
| 161 | + return value; | ||
| 162 | + } | ||
| 163 | + | ||
| 164 | + public Match<byte[]> valueMatch() { | ||
| 165 | + return valueMatch; | ||
| 166 | + } | ||
| 167 | + | ||
| 168 | + public Match<Long> versionMatch() { | ||
| 169 | + return versionMatch; | ||
| 170 | + } | ||
| 171 | + | ||
| 172 | + @Override | ||
| 173 | + public void writeObject(BufferOutput<?> buffer, Serializer serializer) { | ||
| 174 | + super.writeObject(buffer, serializer); | ||
| 175 | + serializer.writeObject(value, buffer); | ||
| 176 | + serializer.writeObject(valueMatch, buffer); | ||
| 177 | + serializer.writeObject(versionMatch, buffer); | ||
| 178 | + } | ||
| 179 | + | ||
| 180 | + @Override | ||
| 181 | + public void readObject(BufferInput<?> buffer, Serializer serializer) { | ||
| 182 | + super.readObject(buffer, serializer); | ||
| 183 | + value = serializer.readObject(buffer); | ||
| 184 | + valueMatch = serializer.readObject(buffer); | ||
| 185 | + versionMatch = serializer.readObject(buffer); | ||
| 186 | + } | ||
| 187 | + | ||
| 188 | + @Override | ||
| 189 | + public String toString() { | ||
| 190 | + return MoreObjects.toStringHelper(getClass()) | ||
| 191 | + .add("path", path()) | ||
| 192 | + .add("value", value) | ||
| 193 | + .add("valueMatch", valueMatch) | ||
| 194 | + .add("versionMatch", versionMatch) | ||
| 195 | + .toString(); | ||
| 196 | + } | ||
| 197 | + } | ||
| 198 | + | ||
| 199 | + /** | ||
| 200 | + * Clear command. | ||
| 201 | + */ | ||
| 202 | + @SuppressWarnings("serial") | ||
| 203 | + public static class Clear implements Command<Void>, CatalystSerializable { | ||
| 204 | + @Override | ||
| 205 | + public void writeObject(BufferOutput<?> buffer, Serializer serializer) { | ||
| 206 | + } | ||
| 207 | + | ||
| 208 | + @Override | ||
| 209 | + public void readObject(BufferInput<?> buffer, Serializer serializer) { | ||
| 210 | + } | ||
| 211 | + } | ||
| 212 | + | ||
| 213 | + /** | ||
| 214 | + * Change listen. | ||
| 215 | + */ | ||
| 216 | + @SuppressWarnings("serial") | ||
| 217 | + public static class Listen extends DocumentTreeCommand<Void> { | ||
| 218 | + | ||
| 219 | + public Listen() { | ||
| 220 | + this(DocumentPath.from("root")); | ||
| 221 | + } | ||
| 222 | + | ||
| 223 | + public Listen(DocumentPath path) { | ||
| 224 | + super(path); | ||
| 225 | + } | ||
| 226 | + | ||
| 227 | + @Override | ||
| 228 | + public void writeObject(BufferOutput<?> buffer, Serializer serializer) { | ||
| 229 | + } | ||
| 230 | + | ||
| 231 | + @Override | ||
| 232 | + public void readObject(BufferInput<?> buffer, Serializer serializer) { | ||
| 233 | + } | ||
| 234 | + } | ||
| 235 | + | ||
| 236 | + /** | ||
| 237 | + * Change unlisten. | ||
| 238 | + */ | ||
| 239 | + @SuppressWarnings("serial") | ||
| 240 | + public static class Unlisten extends DocumentTreeCommand<Void> { | ||
| 241 | + | ||
| 242 | + public Unlisten() { | ||
| 243 | + this(DocumentPath.from("root")); | ||
| 244 | + } | ||
| 245 | + | ||
| 246 | + public Unlisten(DocumentPath path) { | ||
| 247 | + super(path); | ||
| 248 | + } | ||
| 249 | + | ||
| 250 | + @Override | ||
| 251 | + public void writeObject(BufferOutput<?> buffer, Serializer serializer) { | ||
| 252 | + } | ||
| 253 | + | ||
| 254 | + @Override | ||
| 255 | + public void readObject(BufferInput<?> buffer, Serializer serializer) { | ||
| 256 | + } | ||
| 257 | + } | ||
| 258 | + | ||
| 259 | + /** | ||
| 260 | + * DocumentTree command type resolver. | ||
| 261 | + */ | ||
| 262 | + public static class TypeResolver implements SerializableTypeResolver { | ||
| 263 | + @Override | ||
| 264 | + public void resolve(SerializerRegistry registry) { | ||
| 265 | + registry.register(Get.class, -911); | ||
| 266 | + registry.register(GetChildren.class, -912); | ||
| 267 | + registry.register(Update.class, -913); | ||
| 268 | + registry.register(Listen.class, -914); | ||
| 269 | + registry.register(Unlisten.class, -915); | ||
| 270 | + registry.register(Clear.class, -916); | ||
| 271 | + } | ||
| 272 | + } | ||
| 273 | +} |
| 1 | +/* | ||
| 2 | + * Copyright 2016-present Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | +package org.onosproject.store.primitives.resources.impl; | ||
| 17 | + | ||
| 18 | +import io.atomix.catalyst.serializer.SerializableTypeResolver; | ||
| 19 | +import io.atomix.copycat.client.CopycatClient; | ||
| 20 | +import io.atomix.resource.ResourceFactory; | ||
| 21 | +import io.atomix.resource.ResourceStateMachine; | ||
| 22 | + | ||
| 23 | +import java.util.Properties; | ||
| 24 | + | ||
| 25 | +/** | ||
| 26 | + * {@link AtomixDocumentTree} resource factory. | ||
| 27 | + * | ||
| 28 | + */ | ||
| 29 | +public class AtomixDocumentTreeFactory implements ResourceFactory<AtomixDocumentTree> { | ||
| 30 | + | ||
| 31 | + @Override | ||
| 32 | + public SerializableTypeResolver createSerializableTypeResolver() { | ||
| 33 | + return new AtomixDocumentTreeCommands.TypeResolver(); | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | + @Override | ||
| 37 | + public ResourceStateMachine createStateMachine(Properties config) { | ||
| 38 | + return new AtomixDocumentTreeState(config); | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + @Override | ||
| 42 | + public AtomixDocumentTree createInstance(CopycatClient client, Properties options) { | ||
| 43 | + return new AtomixDocumentTree(client, options); | ||
| 44 | + } | ||
| 45 | + } | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
This diff is collapsed. Click to expand it.
| ... | @@ -19,7 +19,7 @@ package org.onosproject.store.primitives.resources.impl; | ... | @@ -19,7 +19,7 @@ package org.onosproject.store.primitives.resources.impl; |
| 19 | import java.util.Iterator; | 19 | import java.util.Iterator; |
| 20 | import java.util.Map; | 20 | import java.util.Map; |
| 21 | import java.util.Objects; | 21 | import java.util.Objects; |
| 22 | -import java.util.concurrent.atomic.AtomicInteger; | 22 | +import java.util.concurrent.atomic.AtomicLong; |
| 23 | 23 | ||
| 24 | import org.onosproject.store.service.DocumentPath; | 24 | import org.onosproject.store.service.DocumentPath; |
| 25 | import org.onosproject.store.service.DocumentTree; | 25 | import org.onosproject.store.service.DocumentTree; |
| ... | @@ -30,6 +30,7 @@ import org.onosproject.store.service.NoSuchDocumentPathException; | ... | @@ -30,6 +30,7 @@ import org.onosproject.store.service.NoSuchDocumentPathException; |
| 30 | import org.onosproject.store.service.Versioned; | 30 | import org.onosproject.store.service.Versioned; |
| 31 | 31 | ||
| 32 | import com.google.common.base.Preconditions; | 32 | import com.google.common.base.Preconditions; |
| 33 | +import com.google.common.base.Supplier; | ||
| 33 | import com.google.common.collect.Maps; | 34 | import com.google.common.collect.Maps; |
| 34 | 35 | ||
| 35 | /** | 36 | /** |
| ... | @@ -41,10 +42,17 @@ public class DefaultDocumentTree<V> implements DocumentTree<V> { | ... | @@ -41,10 +42,17 @@ public class DefaultDocumentTree<V> implements DocumentTree<V> { |
| 41 | 42 | ||
| 42 | private static final DocumentPath ROOT_PATH = DocumentPath.from("root"); | 43 | private static final DocumentPath ROOT_PATH = DocumentPath.from("root"); |
| 43 | private final DefaultDocumentTreeNode<V> root; | 44 | private final DefaultDocumentTreeNode<V> root; |
| 44 | - private final AtomicInteger versionCounter = new AtomicInteger(0); | 45 | + private final Supplier<Long> versionSupplier; |
| 45 | 46 | ||
| 46 | public DefaultDocumentTree() { | 47 | public DefaultDocumentTree() { |
| 47 | - root = new DefaultDocumentTreeNode<V>(ROOT_PATH, null, nextVersion(), null); | 48 | + AtomicLong versionCounter = new AtomicLong(0); |
| 49 | + versionSupplier = versionCounter::incrementAndGet; | ||
| 50 | + root = new DefaultDocumentTreeNode<V>(ROOT_PATH, null, versionSupplier.get(), null); | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + public DefaultDocumentTree(Supplier<Long> versionSupplier) { | ||
| 54 | + root = new DefaultDocumentTreeNode<V>(ROOT_PATH, null, versionSupplier.get(), null); | ||
| 55 | + this.versionSupplier = versionSupplier; | ||
| 48 | } | 56 | } |
| 49 | 57 | ||
| 50 | @Override | 58 | @Override |
| ... | @@ -74,7 +82,7 @@ public class DefaultDocumentTree<V> implements DocumentTree<V> { | ... | @@ -74,7 +82,7 @@ public class DefaultDocumentTree<V> implements DocumentTree<V> { |
| 74 | checkRootModification(path); | 82 | checkRootModification(path); |
| 75 | DefaultDocumentTreeNode<V> node = getNode(path); | 83 | DefaultDocumentTreeNode<V> node = getNode(path); |
| 76 | if (node != null) { | 84 | if (node != null) { |
| 77 | - return node.update(value, nextVersion()); | 85 | + return node.update(value, versionSupplier.get()); |
| 78 | } else { | 86 | } else { |
| 79 | create(path, value); | 87 | create(path, value); |
| 80 | return null; | 88 | return null; |
| ... | @@ -93,7 +101,7 @@ public class DefaultDocumentTree<V> implements DocumentTree<V> { | ... | @@ -93,7 +101,7 @@ public class DefaultDocumentTree<V> implements DocumentTree<V> { |
| 93 | if (parentNode == null) { | 101 | if (parentNode == null) { |
| 94 | throw new IllegalDocumentModificationException(); | 102 | throw new IllegalDocumentModificationException(); |
| 95 | } | 103 | } |
| 96 | - parentNode.addChild(simpleName(path), value, nextVersion()); | 104 | + parentNode.addChild(simpleName(path), value, versionSupplier.get()); |
| 97 | return true; | 105 | return true; |
| 98 | } | 106 | } |
| 99 | 107 | ||
| ... | @@ -159,10 +167,6 @@ public class DefaultDocumentTree<V> implements DocumentTree<V> { | ... | @@ -159,10 +167,6 @@ public class DefaultDocumentTree<V> implements DocumentTree<V> { |
| 159 | return currentNode; | 167 | return currentNode; |
| 160 | } | 168 | } |
| 161 | 169 | ||
| 162 | - private long nextVersion() { | ||
| 163 | - return versionCounter.incrementAndGet(); | ||
| 164 | - } | ||
| 165 | - | ||
| 166 | private String simpleName(DocumentPath path) { | 170 | private String simpleName(DocumentPath path) { |
| 167 | return path.pathElements().get(path.pathElements().size() - 1); | 171 | return path.pathElements().get(path.pathElements().size() - 1); |
| 168 | } | 172 | } | ... | ... |
| 1 | +/* | ||
| 2 | + * Copyright 2016-present Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +package org.onosproject.store.primitives.resources.impl; | ||
| 18 | + | ||
| 19 | +import org.onosproject.store.service.DocumentPath; | ||
| 20 | +import org.onosproject.store.service.Versioned; | ||
| 21 | + | ||
| 22 | +import com.google.common.base.MoreObjects; | ||
| 23 | + | ||
| 24 | +/** | ||
| 25 | + * Result of a document tree node update operation. | ||
| 26 | + * <p> | ||
| 27 | + * Both old and new values are accessible along with a status of update. | ||
| 28 | + * | ||
| 29 | + * @param <V> value type | ||
| 30 | + */ | ||
| 31 | +public class DocumentTreeUpdateResult<V> { | ||
| 32 | + | ||
| 33 | + public enum Status { | ||
| 34 | + /** | ||
| 35 | + * Indicates a successful update. | ||
| 36 | + */ | ||
| 37 | + OK, | ||
| 38 | + | ||
| 39 | + /** | ||
| 40 | + * Indicates a noop i.e. existing and new value are both same. | ||
| 41 | + */ | ||
| 42 | + NOOP, | ||
| 43 | + | ||
| 44 | + /** | ||
| 45 | + * Indicates a failed update due to a write lock. | ||
| 46 | + */ | ||
| 47 | + WRITE_LOCK, | ||
| 48 | + | ||
| 49 | + /** | ||
| 50 | + * Indicates a failed update due to a invalid path. | ||
| 51 | + */ | ||
| 52 | + INVALID_PATH, | ||
| 53 | + | ||
| 54 | + /** | ||
| 55 | + * Indicates a failed update due to a illegal modification attempt. | ||
| 56 | + */ | ||
| 57 | + ILLEGAL_MODIFICATION, | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + private final DocumentPath path; | ||
| 61 | + private final Status status; | ||
| 62 | + private final Versioned<V> oldValue; | ||
| 63 | + private final Versioned<V> newValue; | ||
| 64 | + | ||
| 65 | + public DocumentTreeUpdateResult(DocumentPath path, | ||
| 66 | + Status status, | ||
| 67 | + Versioned<V> newValue, | ||
| 68 | + Versioned<V> oldValue) { | ||
| 69 | + this.status = status; | ||
| 70 | + this.path = path; | ||
| 71 | + this.newValue = newValue; | ||
| 72 | + this.oldValue = oldValue; | ||
| 73 | + } | ||
| 74 | + | ||
| 75 | + public static <V> DocumentTreeUpdateResult<V> invalidPath(DocumentPath path) { | ||
| 76 | + return new DocumentTreeUpdateResult<>(path, Status.INVALID_PATH, null, null); | ||
| 77 | + } | ||
| 78 | + | ||
| 79 | + public static <V> DocumentTreeUpdateResult<V> illegalModification(DocumentPath path) { | ||
| 80 | + return new DocumentTreeUpdateResult<>(path, Status.ILLEGAL_MODIFICATION, null, null); | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + public Status status() { | ||
| 84 | + return status; | ||
| 85 | + } | ||
| 86 | + | ||
| 87 | + public DocumentPath path() { | ||
| 88 | + return path; | ||
| 89 | + } | ||
| 90 | + | ||
| 91 | + public Versioned<V> oldValue() { | ||
| 92 | + return oldValue; | ||
| 93 | + } | ||
| 94 | + | ||
| 95 | + public Versioned<V> newValue() { | ||
| 96 | + return this.newValue; | ||
| 97 | + } | ||
| 98 | + | ||
| 99 | + public boolean updated() { | ||
| 100 | + return status == Status.OK; | ||
| 101 | + } | ||
| 102 | + | ||
| 103 | + public boolean created() { | ||
| 104 | + return updated() && oldValue == null; | ||
| 105 | + } | ||
| 106 | + | ||
| 107 | + @Override | ||
| 108 | + public String toString() { | ||
| 109 | + return MoreObjects.toStringHelper(getClass()) | ||
| 110 | + .add("path", path) | ||
| 111 | + .add("status", status) | ||
| 112 | + .add("newValue", newValue) | ||
| 113 | + .add("oldValue", oldValue) | ||
| 114 | + .toString(); | ||
| 115 | + } | ||
| 116 | +} |
This diff is collapsed. Click to expand it.
-
Please register or login to post a comment