Committed by
Brian O'Connor
Support for a distributed queue primitive.
Change-Id: I13abb93ec1703105ff0137e137738483a5b6a143
Showing
13 changed files
with
547 additions
and
4 deletions
| 1 | +/* | ||
| 2 | + * Copyright 2015 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.service; | ||
| 17 | + | ||
| 18 | +import java.util.concurrent.CompletableFuture; | ||
| 19 | + | ||
| 20 | +/** | ||
| 21 | + * A distributed collection designed for holding elements prior to processing. | ||
| 22 | + * A queue provides insertion, extraction and inspection operations. The extraction operation | ||
| 23 | + * is designed to be non-blocking. | ||
| 24 | + * | ||
| 25 | + * @param <E> queue entry type | ||
| 26 | + */ | ||
| 27 | +public interface DistributedQueue<E> { | ||
| 28 | + | ||
| 29 | + /** | ||
| 30 | + * Returns total number of entries in the queue. | ||
| 31 | + * @return queue size | ||
| 32 | + */ | ||
| 33 | + long size(); | ||
| 34 | + | ||
| 35 | + /** | ||
| 36 | + * Returns true if queue has elements in it. | ||
| 37 | + * @return true is queue has elements, false otherwise | ||
| 38 | + */ | ||
| 39 | + default boolean isEmpty() { | ||
| 40 | + return size() == 0; | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + /** | ||
| 44 | + * Inserts an entry into the queue. | ||
| 45 | + * @param entry entry to insert | ||
| 46 | + */ | ||
| 47 | + void push(E entry); | ||
| 48 | + | ||
| 49 | + /** | ||
| 50 | + * If the queue is non-empty, an entry will be removed from the queue and the returned future | ||
| 51 | + * will be immediately completed with it. If queue is empty when this call is made, the returned | ||
| 52 | + * future will be eventually completed when an entry is added to the queue. | ||
| 53 | + * @return queue entry | ||
| 54 | + */ | ||
| 55 | + CompletableFuture<E> pop(); | ||
| 56 | + | ||
| 57 | + /** | ||
| 58 | + * Returns an entry from the queue without removing it. If the queue is empty returns null. | ||
| 59 | + * @return queue entry or null if queue is empty | ||
| 60 | + */ | ||
| 61 | + E peek(); | ||
| 62 | +} | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| 1 | +/* | ||
| 2 | + * Copyright 2015 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.service; | ||
| 17 | + | ||
| 18 | +/** | ||
| 19 | + * Builder for distributed queue. | ||
| 20 | + * | ||
| 21 | + * @param <E> type queue elements. | ||
| 22 | + */ | ||
| 23 | +public interface DistributedQueueBuilder<E> { | ||
| 24 | + | ||
| 25 | + /** | ||
| 26 | + * Sets the name of the queue. | ||
| 27 | + * <p> | ||
| 28 | + * Each queue is identified by a unique name. | ||
| 29 | + * </p> | ||
| 30 | + * <p> | ||
| 31 | + * Note: This is a mandatory parameter. | ||
| 32 | + * </p> | ||
| 33 | + * | ||
| 34 | + * @param name name of the queue | ||
| 35 | + * @return this DistributedQueueBuilder for method chaining | ||
| 36 | + */ | ||
| 37 | + DistributedQueueBuilder<E> withName(String name); | ||
| 38 | + | ||
| 39 | + /** | ||
| 40 | + * Sets a serializer that can be used to serialize | ||
| 41 | + * the elements pushed into the queue. The serializer | ||
| 42 | + * builder should be pre-populated with any classes that will be | ||
| 43 | + * put into the queue. | ||
| 44 | + * <p> | ||
| 45 | + * Note: This is a mandatory parameter. | ||
| 46 | + * </p> | ||
| 47 | + * | ||
| 48 | + * @param serializer serializer | ||
| 49 | + * @return this DistributedQueueBuilder for method chaining | ||
| 50 | + */ | ||
| 51 | + DistributedQueueBuilder<E> withSerializer(Serializer serializer); | ||
| 52 | + | ||
| 53 | + /** | ||
| 54 | + * Disables persistence of queues entries. | ||
| 55 | + * <p> | ||
| 56 | + * When persistence is disabled, a full cluster restart will wipe out all | ||
| 57 | + * queue entries. | ||
| 58 | + * </p> | ||
| 59 | + * @return this DistributedQueueBuilder for method chaining | ||
| 60 | + */ | ||
| 61 | + DistributedQueueBuilder<E> withPersistenceDisabled(); | ||
| 62 | + | ||
| 63 | + /** | ||
| 64 | + * Builds a queue based on the configuration options | ||
| 65 | + * supplied to this builder. | ||
| 66 | + * | ||
| 67 | + * @return new distributed queue | ||
| 68 | + * @throws java.lang.RuntimeException if a mandatory parameter is missing | ||
| 69 | + */ | ||
| 70 | + DistributedQueue<E> build(); | ||
| 71 | +} |
| 1 | +/* | ||
| 2 | + * Copyright 2015 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 | + */ | ||
| 1 | package org.onosproject.store.service; | 16 | package org.onosproject.store.service; |
| 2 | 17 | ||
| 3 | import java.util.Set; | 18 | import java.util.Set; | ... | ... |
| ... | @@ -56,6 +56,14 @@ public interface StorageService { | ... | @@ -56,6 +56,14 @@ public interface StorageService { |
| 56 | <E> DistributedSetBuilder<E> setBuilder(); | 56 | <E> DistributedSetBuilder<E> setBuilder(); |
| 57 | 57 | ||
| 58 | /** | 58 | /** |
| 59 | + * Creates a new distributed queue builder. | ||
| 60 | + * | ||
| 61 | + * @param <E> queue entry type | ||
| 62 | + * @return builder for an distributed queue | ||
| 63 | + */ | ||
| 64 | + <E> DistributedQueueBuilder<E> queueBuilder(); | ||
| 65 | + | ||
| 66 | + /** | ||
| 59 | * Creates a new AtomicCounterBuilder. | 67 | * Creates a new AtomicCounterBuilder. |
| 60 | * | 68 | * |
| 61 | * @return atomic counter builder | 69 | * @return atomic counter builder | ... | ... |
| ... | @@ -16,6 +16,7 @@ | ... | @@ -16,6 +16,7 @@ |
| 16 | 16 | ||
| 17 | package org.onosproject.store.consistent.impl; | 17 | package org.onosproject.store.consistent.impl; |
| 18 | 18 | ||
| 19 | +import com.google.common.base.Charsets; | ||
| 19 | import com.google.common.collect.ImmutableSet; | 20 | import com.google.common.collect.ImmutableSet; |
| 20 | import com.google.common.collect.Lists; | 21 | import com.google.common.collect.Lists; |
| 21 | import com.google.common.collect.Maps; | 22 | import com.google.common.collect.Maps; |
| ... | @@ -46,6 +47,7 @@ import org.apache.felix.scr.annotations.Service; | ... | @@ -46,6 +47,7 @@ import org.apache.felix.scr.annotations.Service; |
| 46 | import static org.onlab.util.Tools.groupedThreads; | 47 | import static org.onlab.util.Tools.groupedThreads; |
| 47 | 48 | ||
| 48 | import org.onosproject.cluster.ClusterService; | 49 | import org.onosproject.cluster.ClusterService; |
| 50 | +import org.onosproject.cluster.NodeId; | ||
| 49 | import org.onosproject.core.IdGenerator; | 51 | import org.onosproject.core.IdGenerator; |
| 50 | import org.onosproject.store.cluster.impl.ClusterDefinitionManager; | 52 | import org.onosproject.store.cluster.impl.ClusterDefinitionManager; |
| 51 | import org.onosproject.store.cluster.impl.NodeInfo; | 53 | import org.onosproject.store.cluster.impl.NodeInfo; |
| ... | @@ -55,6 +57,7 @@ import org.onosproject.store.ecmap.EventuallyConsistentMapBuilderImpl; | ... | @@ -55,6 +57,7 @@ import org.onosproject.store.ecmap.EventuallyConsistentMapBuilderImpl; |
| 55 | import org.onosproject.store.service.AtomicCounterBuilder; | 57 | import org.onosproject.store.service.AtomicCounterBuilder; |
| 56 | import org.onosproject.store.service.ConsistentMapBuilder; | 58 | import org.onosproject.store.service.ConsistentMapBuilder; |
| 57 | import org.onosproject.store.service.ConsistentMapException; | 59 | import org.onosproject.store.service.ConsistentMapException; |
| 60 | +import org.onosproject.store.service.DistributedQueueBuilder; | ||
| 58 | import org.onosproject.store.service.EventuallyConsistentMapBuilder; | 61 | import org.onosproject.store.service.EventuallyConsistentMapBuilder; |
| 59 | import org.onosproject.store.service.MapEvent; | 62 | import org.onosproject.store.service.MapEvent; |
| 60 | import org.onosproject.store.service.MapInfo; | 63 | import org.onosproject.store.service.MapInfo; |
| ... | @@ -98,16 +101,21 @@ public class DatabaseManager implements StorageService, StorageAdminService { | ... | @@ -98,16 +101,21 @@ public class DatabaseManager implements StorageService, StorageAdminService { |
| 98 | private static final int RAFT_ELECTION_TIMEOUT_MILLIS = 3000; | 101 | private static final int RAFT_ELECTION_TIMEOUT_MILLIS = 3000; |
| 99 | private static final int DATABASE_OPERATION_TIMEOUT_MILLIS = 5000; | 102 | private static final int DATABASE_OPERATION_TIMEOUT_MILLIS = 5000; |
| 100 | 103 | ||
| 104 | + protected static final MessageSubject QUEUE_UPDATED_TOPIC = new MessageSubject("distributed-queue-updated"); | ||
| 105 | + | ||
| 101 | private ClusterCoordinator coordinator; | 106 | private ClusterCoordinator coordinator; |
| 102 | protected PartitionedDatabase partitionedDatabase; | 107 | protected PartitionedDatabase partitionedDatabase; |
| 103 | protected Database inMemoryDatabase; | 108 | protected Database inMemoryDatabase; |
| 109 | + protected NodeId localNodeId; | ||
| 104 | 110 | ||
| 105 | private TransactionManager transactionManager; | 111 | private TransactionManager transactionManager; |
| 106 | private final IdGenerator transactionIdGenerator = () -> RandomUtils.nextLong(); | 112 | private final IdGenerator transactionIdGenerator = () -> RandomUtils.nextLong(); |
| 107 | 113 | ||
| 108 | private ExecutorService eventDispatcher; | 114 | private ExecutorService eventDispatcher; |
| 115 | + private ExecutorService queuePollExecutor; | ||
| 109 | 116 | ||
| 110 | - private final Set<DefaultAsyncConsistentMap> maps = Sets.newCopyOnWriteArraySet(); | 117 | + private final Map<String, DefaultAsyncConsistentMap> maps = Maps.newConcurrentMap(); |
| 118 | + private final Map<String, DefaultDistributedQueue> queues = Maps.newConcurrentMap(); | ||
| 111 | 119 | ||
| 112 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 120 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| 113 | protected ClusterService clusterService; | 121 | protected ClusterService clusterService; |
| ... | @@ -121,6 +129,7 @@ public class DatabaseManager implements StorageService, StorageAdminService { | ... | @@ -121,6 +129,7 @@ public class DatabaseManager implements StorageService, StorageAdminService { |
| 121 | 129 | ||
| 122 | @Activate | 130 | @Activate |
| 123 | public void activate() { | 131 | public void activate() { |
| 132 | + localNodeId = clusterService.getLocalNode().id(); | ||
| 124 | // load database configuration | 133 | // load database configuration |
| 125 | File databaseDefFile = new File(PARTITION_DEFINITION_FILE); | 134 | File databaseDefFile = new File(PARTITION_DEFINITION_FILE); |
| 126 | log.info("Loading database definition: {}", databaseDefFile.getAbsolutePath()); | 135 | log.info("Loading database definition: {}", databaseDefFile.getAbsolutePath()); |
| ... | @@ -201,6 +210,19 @@ public class DatabaseManager implements StorageService, StorageAdminService { | ... | @@ -201,6 +210,19 @@ public class DatabaseManager implements StorageService, StorageAdminService { |
| 201 | 210 | ||
| 202 | eventDispatcher = Executors.newSingleThreadExecutor( | 211 | eventDispatcher = Executors.newSingleThreadExecutor( |
| 203 | groupedThreads("onos/store/manager", "map-event-dispatcher")); | 212 | groupedThreads("onos/store/manager", "map-event-dispatcher")); |
| 213 | + | ||
| 214 | + queuePollExecutor = Executors.newFixedThreadPool(4, | ||
| 215 | + groupedThreads("onos/store/manager", "queue-poll-handler")); | ||
| 216 | + | ||
| 217 | + clusterCommunicator.<String>addSubscriber(QUEUE_UPDATED_TOPIC, | ||
| 218 | + data -> new String(data, Charsets.UTF_8), | ||
| 219 | + name -> { | ||
| 220 | + DefaultDistributedQueue q = queues.get(name); | ||
| 221 | + if (q != null) { | ||
| 222 | + q.tryPoll(); | ||
| 223 | + } | ||
| 224 | + }, | ||
| 225 | + queuePollExecutor); | ||
| 204 | log.info("Started"); | 226 | log.info("Started"); |
| 205 | } | 227 | } |
| 206 | 228 | ||
| ... | @@ -226,8 +248,10 @@ public class DatabaseManager implements StorageService, StorageAdminService { | ... | @@ -226,8 +248,10 @@ public class DatabaseManager implements StorageService, StorageAdminService { |
| 226 | log.info("Successfully closed databases."); | 248 | log.info("Successfully closed databases."); |
| 227 | } | 249 | } |
| 228 | }); | 250 | }); |
| 229 | - maps.forEach(map -> clusterCommunicator.removeSubscriber(mapUpdatesSubject(map.name()))); | 251 | + clusterCommunicator.removeSubscriber(QUEUE_UPDATED_TOPIC); |
| 252 | + maps.values().forEach(this::unregisterMap); | ||
| 230 | eventDispatcher.shutdown(); | 253 | eventDispatcher.shutdown(); |
| 254 | + queuePollExecutor.shutdown(); | ||
| 231 | log.info("Stopped"); | 255 | log.info("Stopped"); |
| 232 | } | 256 | } |
| 233 | 257 | ||
| ... | @@ -318,6 +342,12 @@ public class DatabaseManager implements StorageService, StorageAdminService { | ... | @@ -318,6 +342,12 @@ public class DatabaseManager implements StorageService, StorageAdminService { |
| 318 | return new DefaultDistributedSetBuilder<>(this); | 342 | return new DefaultDistributedSetBuilder<>(this); |
| 319 | } | 343 | } |
| 320 | 344 | ||
| 345 | + | ||
| 346 | + @Override | ||
| 347 | + public <E> DistributedQueueBuilder<E> queueBuilder() { | ||
| 348 | + return new DefaultDistributedQueueBuilder<>(this); | ||
| 349 | + } | ||
| 350 | + | ||
| 321 | @Override | 351 | @Override |
| 322 | public AtomicCounterBuilder atomicCounterBuilder() { | 352 | public AtomicCounterBuilder atomicCounterBuilder() { |
| 323 | return new DefaultAtomicCounterBuilder(inMemoryDatabase, partitionedDatabase); | 353 | return new DefaultAtomicCounterBuilder(inMemoryDatabase, partitionedDatabase); |
| ... | @@ -386,8 +416,8 @@ public class DatabaseManager implements StorageService, StorageAdminService { | ... | @@ -386,8 +416,8 @@ public class DatabaseManager implements StorageService, StorageAdminService { |
| 386 | } | 416 | } |
| 387 | 417 | ||
| 388 | protected <K, V> void registerMap(DefaultAsyncConsistentMap<K, V> map) { | 418 | protected <K, V> void registerMap(DefaultAsyncConsistentMap<K, V> map) { |
| 389 | - // TODO: Support different local instances of the same map. | 419 | + // TODO: Support multiple local instances of the same map. |
| 390 | - if (!maps.add(map)) { | 420 | + if (maps.putIfAbsent(map.name(), map) != null) { |
| 391 | throw new IllegalStateException("Map by name " + map.name() + " already exists"); | 421 | throw new IllegalStateException("Map by name " + map.name() + " already exists"); |
| 392 | } | 422 | } |
| 393 | 423 | ||
| ... | @@ -397,6 +427,19 @@ public class DatabaseManager implements StorageService, StorageAdminService { | ... | @@ -397,6 +427,19 @@ public class DatabaseManager implements StorageService, StorageAdminService { |
| 397 | eventDispatcher); | 427 | eventDispatcher); |
| 398 | } | 428 | } |
| 399 | 429 | ||
| 430 | + protected <K, V> void unregisterMap(DefaultAsyncConsistentMap<K, V> map) { | ||
| 431 | + if (maps.remove(map.name()) != null) { | ||
| 432 | + clusterCommunicator.removeSubscriber(mapUpdatesSubject(map.name())); | ||
| 433 | + } | ||
| 434 | + } | ||
| 435 | + | ||
| 436 | + protected <E> void registerQueue(DefaultDistributedQueue<E> queue) { | ||
| 437 | + // TODO: Support multiple local instances of the same queue. | ||
| 438 | + if (queues.putIfAbsent(queue.name(), queue) != null) { | ||
| 439 | + throw new IllegalStateException("Queue by name " + queue.name() + " already exists"); | ||
| 440 | + } | ||
| 441 | + } | ||
| 442 | + | ||
| 400 | protected static MessageSubject mapUpdatesSubject(String mapName) { | 443 | protected static MessageSubject mapUpdatesSubject(String mapName) { |
| 401 | return new MessageSubject(mapName + "-map-updates"); | 444 | return new MessageSubject(mapName + "-map-updates"); |
| 402 | } | 445 | } | ... | ... |
| ... | @@ -21,6 +21,7 @@ import java.util.Map; | ... | @@ -21,6 +21,7 @@ import java.util.Map; |
| 21 | import java.util.Set; | 21 | import java.util.Set; |
| 22 | import java.util.concurrent.CompletableFuture; | 22 | import java.util.concurrent.CompletableFuture; |
| 23 | 23 | ||
| 24 | +import org.onosproject.cluster.NodeId; | ||
| 24 | import org.onosproject.store.service.Transaction; | 25 | import org.onosproject.store.service.Transaction; |
| 25 | import org.onosproject.store.service.Versioned; | 26 | import org.onosproject.store.service.Versioned; |
| 26 | 27 | ||
| ... | @@ -249,6 +250,36 @@ public interface DatabaseProxy<K, V> { | ... | @@ -249,6 +250,36 @@ public interface DatabaseProxy<K, V> { |
| 249 | CompletableFuture<Long> counterGet(String counterName); | 250 | CompletableFuture<Long> counterGet(String counterName); |
| 250 | 251 | ||
| 251 | /** | 252 | /** |
| 253 | + * Returns the size of queue. | ||
| 254 | + * @param queueName queue name | ||
| 255 | + * @return queue size | ||
| 256 | + */ | ||
| 257 | + CompletableFuture<Long> queueSize(String queueName); | ||
| 258 | + | ||
| 259 | + /** | ||
| 260 | + * Inserts an entry into the queue. | ||
| 261 | + * @param queueName queue name | ||
| 262 | + * @param entry queue entry | ||
| 263 | + * @return set of nodes to notify about the queue update | ||
| 264 | + */ | ||
| 265 | + CompletableFuture<Set<NodeId>> queuePush(String queueName, byte[] entry); | ||
| 266 | + | ||
| 267 | + /** | ||
| 268 | + * Removes an entry from the queue if the queue is non-empty. | ||
| 269 | + * @param queueName queue name | ||
| 270 | + * @param nodeId If the queue is empty the identifier of node to notify when an entry becomes available | ||
| 271 | + * @return entry. Can be null if queue is empty | ||
| 272 | + */ | ||
| 273 | + CompletableFuture<byte[]> queuePop(String queueName, NodeId nodeId); | ||
| 274 | + | ||
| 275 | + /** | ||
| 276 | + * Returns but does not remove an entry from the queue. | ||
| 277 | + * @param queueName queue name | ||
| 278 | + * @return entry. Can be null if queue is empty | ||
| 279 | + */ | ||
| 280 | + CompletableFuture<byte[]> queuePeek(String queueName); | ||
| 281 | + | ||
| 282 | + /** | ||
| 252 | * Prepare and commit the specified transaction. | 283 | * Prepare and commit the specified transaction. |
| 253 | * | 284 | * |
| 254 | * @param transaction transaction to commit (after preparation) | 285 | * @param transaction transaction to commit (after preparation) | ... | ... |
| ... | @@ -21,6 +21,7 @@ import java.nio.ByteBuffer; | ... | @@ -21,6 +21,7 @@ import java.nio.ByteBuffer; |
| 21 | import org.apache.commons.lang3.tuple.ImmutablePair; | 21 | import org.apache.commons.lang3.tuple.ImmutablePair; |
| 22 | import org.apache.commons.lang3.tuple.Pair; | 22 | import org.apache.commons.lang3.tuple.Pair; |
| 23 | import org.onlab.util.KryoNamespace; | 23 | import org.onlab.util.KryoNamespace; |
| 24 | +import org.onosproject.cluster.NodeId; | ||
| 24 | import org.onosproject.store.serializers.KryoNamespaces; | 25 | import org.onosproject.store.serializers.KryoNamespaces; |
| 25 | import org.onosproject.store.serializers.KryoSerializer; | 26 | import org.onosproject.store.serializers.KryoSerializer; |
| 26 | import org.onosproject.store.service.DatabaseUpdate; | 27 | import org.onosproject.store.service.DatabaseUpdate; |
| ... | @@ -78,6 +79,7 @@ public class DatabaseSerializer extends SerializerConfig { | ... | @@ -78,6 +79,7 @@ public class DatabaseSerializer extends SerializerConfig { |
| 78 | .register(Result.Status.class) | 79 | .register(Result.Status.class) |
| 79 | .register(DefaultTransaction.class) | 80 | .register(DefaultTransaction.class) |
| 80 | .register(Transaction.State.class) | 81 | .register(Transaction.State.class) |
| 82 | + .register(NodeId.class) | ||
| 81 | .build(); | 83 | .build(); |
| 82 | 84 | ||
| 83 | private static final KryoSerializer SERIALIZER = new KryoSerializer() { | 85 | private static final KryoSerializer SERIALIZER = new KryoSerializer() { | ... | ... |
| ... | @@ -21,6 +21,7 @@ import java.util.Map; | ... | @@ -21,6 +21,7 @@ import java.util.Map; |
| 21 | import java.util.Map.Entry; | 21 | import java.util.Map.Entry; |
| 22 | import java.util.Set; | 22 | import java.util.Set; |
| 23 | 23 | ||
| 24 | +import org.onosproject.cluster.NodeId; | ||
| 24 | import org.onosproject.store.service.Transaction; | 25 | import org.onosproject.store.service.Transaction; |
| 25 | import org.onosproject.store.service.Versioned; | 26 | import org.onosproject.store.service.Versioned; |
| 26 | 27 | ||
| ... | @@ -113,6 +114,18 @@ public interface DatabaseState<K, V> { | ... | @@ -113,6 +114,18 @@ public interface DatabaseState<K, V> { |
| 113 | Long counterGetAndAdd(String counterName, long delta); | 114 | Long counterGetAndAdd(String counterName, long delta); |
| 114 | 115 | ||
| 115 | @Query | 116 | @Query |
| 117 | + Long queueSize(String queueName); | ||
| 118 | + | ||
| 119 | + @Query | ||
| 120 | + byte[] queuePeek(String queueName); | ||
| 121 | + | ||
| 122 | + @Command | ||
| 123 | + byte[] queuePop(String queueName, NodeId requestor); | ||
| 124 | + | ||
| 125 | + @Command | ||
| 126 | + Set<NodeId> queuePush(String queueName, byte[] entry); | ||
| 127 | + | ||
| 128 | + @Query | ||
| 116 | Long counterGet(String counterName); | 129 | Long counterGet(String counterName); |
| 117 | 130 | ||
| 118 | @Command | 131 | @Command | ... | ... |
| ... | @@ -28,6 +28,7 @@ import java.util.Set; | ... | @@ -28,6 +28,7 @@ import java.util.Set; |
| 28 | import java.util.concurrent.CompletableFuture; | 28 | import java.util.concurrent.CompletableFuture; |
| 29 | import java.util.function.Supplier; | 29 | import java.util.function.Supplier; |
| 30 | 30 | ||
| 31 | +import org.onosproject.cluster.NodeId; | ||
| 31 | import org.onosproject.store.service.Transaction; | 32 | import org.onosproject.store.service.Transaction; |
| 32 | import org.onosproject.store.service.Versioned; | 33 | import org.onosproject.store.service.Versioned; |
| 33 | 34 | ||
| ... | @@ -187,6 +188,26 @@ public class DefaultDatabase extends AbstractResource<Database> implements Datab | ... | @@ -187,6 +188,26 @@ public class DefaultDatabase extends AbstractResource<Database> implements Datab |
| 187 | } | 188 | } |
| 188 | 189 | ||
| 189 | @Override | 190 | @Override |
| 191 | + public CompletableFuture<Long> queueSize(String queueName) { | ||
| 192 | + return checkOpen(() -> proxy.queueSize(queueName)); | ||
| 193 | + } | ||
| 194 | + | ||
| 195 | + @Override | ||
| 196 | + public CompletableFuture<Set<NodeId>> queuePush(String queueName, byte[] entry) { | ||
| 197 | + return checkOpen(() -> proxy.queuePush(queueName, entry)); | ||
| 198 | + } | ||
| 199 | + | ||
| 200 | + @Override | ||
| 201 | + public CompletableFuture<byte[]> queuePop(String queueName, NodeId nodeId) { | ||
| 202 | + return checkOpen(() -> proxy.queuePop(queueName, nodeId)); | ||
| 203 | + } | ||
| 204 | + | ||
| 205 | + @Override | ||
| 206 | + public CompletableFuture<byte[]> queuePeek(String queueName) { | ||
| 207 | + return checkOpen(() -> proxy.queuePeek(queueName)); | ||
| 208 | + } | ||
| 209 | + | ||
| 210 | + @Override | ||
| 190 | public CompletableFuture<Boolean> prepareAndCommit(Transaction transaction) { | 211 | public CompletableFuture<Boolean> prepareAndCommit(Transaction transaction) { |
| 191 | return checkOpen(() -> proxy.prepareAndCommit(transaction)); | 212 | return checkOpen(() -> proxy.prepareAndCommit(transaction)); |
| 192 | } | 213 | } | ... | ... |
| ... | @@ -19,13 +19,16 @@ package org.onosproject.store.consistent.impl; | ... | @@ -19,13 +19,16 @@ package org.onosproject.store.consistent.impl; |
| 19 | import java.util.Arrays; | 19 | import java.util.Arrays; |
| 20 | import java.util.Collection; | 20 | import java.util.Collection; |
| 21 | import java.util.HashSet; | 21 | import java.util.HashSet; |
| 22 | +import java.util.LinkedList; | ||
| 22 | import java.util.Map; | 23 | import java.util.Map; |
| 23 | import java.util.Map.Entry; | 24 | import java.util.Map.Entry; |
| 25 | +import java.util.Queue; | ||
| 24 | import java.util.concurrent.atomic.AtomicLong; | 26 | import java.util.concurrent.atomic.AtomicLong; |
| 25 | import java.util.stream.Collectors; | 27 | import java.util.stream.Collectors; |
| 26 | import java.util.Set; | 28 | import java.util.Set; |
| 27 | 29 | ||
| 28 | import org.apache.commons.lang3.tuple.Pair; | 30 | import org.apache.commons.lang3.tuple.Pair; |
| 31 | +import org.onosproject.cluster.NodeId; | ||
| 29 | import org.onosproject.store.service.DatabaseUpdate; | 32 | import org.onosproject.store.service.DatabaseUpdate; |
| 30 | import org.onosproject.store.service.Transaction; | 33 | import org.onosproject.store.service.Transaction; |
| 31 | import org.onosproject.store.service.Versioned; | 34 | import org.onosproject.store.service.Versioned; |
| ... | @@ -46,6 +49,8 @@ public class DefaultDatabaseState implements DatabaseState<String, byte[]> { | ... | @@ -46,6 +49,8 @@ public class DefaultDatabaseState implements DatabaseState<String, byte[]> { |
| 46 | private Long nextVersion; | 49 | private Long nextVersion; |
| 47 | private Map<String, AtomicLong> counters; | 50 | private Map<String, AtomicLong> counters; |
| 48 | private Map<String, Map<String, Versioned<byte[]>>> tables; | 51 | private Map<String, Map<String, Versioned<byte[]>>> tables; |
| 52 | + private Map<String, Queue<byte[]>> queues; | ||
| 53 | + private Map<String, Set<NodeId>> queueUpdateNotificationTargets; | ||
| 49 | 54 | ||
| 50 | /** | 55 | /** |
| 51 | * This locks map has a structure similar to the "tables" map above and | 56 | * This locks map has a structure similar to the "tables" map above and |
| ... | @@ -77,6 +82,16 @@ public class DefaultDatabaseState implements DatabaseState<String, byte[]> { | ... | @@ -77,6 +82,16 @@ public class DefaultDatabaseState implements DatabaseState<String, byte[]> { |
| 77 | locks = Maps.newConcurrentMap(); | 82 | locks = Maps.newConcurrentMap(); |
| 78 | context.put("locks", locks); | 83 | context.put("locks", locks); |
| 79 | } | 84 | } |
| 85 | + queues = context.get("queues"); | ||
| 86 | + if (queues == null) { | ||
| 87 | + queues = Maps.newConcurrentMap(); | ||
| 88 | + context.put("queues", queues); | ||
| 89 | + } | ||
| 90 | + queueUpdateNotificationTargets = context.get("queueUpdateNotificationTargets"); | ||
| 91 | + if (queueUpdateNotificationTargets == null) { | ||
| 92 | + queueUpdateNotificationTargets = Maps.newConcurrentMap(); | ||
| 93 | + context.put("queueUpdateNotificationTargets", queueUpdateNotificationTargets); | ||
| 94 | + } | ||
| 80 | nextVersion = context.get("nextVersion"); | 95 | nextVersion = context.get("nextVersion"); |
| 81 | if (nextVersion == null) { | 96 | if (nextVersion == null) { |
| 82 | nextVersion = new Long(0); | 97 | nextVersion = new Long(0); |
| ... | @@ -288,6 +303,36 @@ public class DefaultDatabaseState implements DatabaseState<String, byte[]> { | ... | @@ -288,6 +303,36 @@ public class DefaultDatabaseState implements DatabaseState<String, byte[]> { |
| 288 | } | 303 | } |
| 289 | 304 | ||
| 290 | @Override | 305 | @Override |
| 306 | + public Long queueSize(String queueName) { | ||
| 307 | + return Long.valueOf(getQueue(queueName).size()); | ||
| 308 | + } | ||
| 309 | + | ||
| 310 | + @Override | ||
| 311 | + public byte[] queuePeek(String queueName) { | ||
| 312 | + Queue<byte[]> queue = getQueue(queueName); | ||
| 313 | + return queue.peek(); | ||
| 314 | + } | ||
| 315 | + | ||
| 316 | + @Override | ||
| 317 | + public byte[] queuePop(String queueName, NodeId requestor) { | ||
| 318 | + Queue<byte[]> queue = getQueue(queueName); | ||
| 319 | + if (queue.size() == 0 && requestor != null) { | ||
| 320 | + getQueueUpdateNotificationTargets(queueName).add(requestor); | ||
| 321 | + return null; | ||
| 322 | + } else { | ||
| 323 | + return queue.remove(); | ||
| 324 | + } | ||
| 325 | + } | ||
| 326 | + | ||
| 327 | + @Override | ||
| 328 | + public Set<NodeId> queuePush(String queueName, byte[] entry) { | ||
| 329 | + getQueue(queueName).add(entry); | ||
| 330 | + Set<NodeId> notifyList = ImmutableSet.copyOf(getQueueUpdateNotificationTargets(queueName)); | ||
| 331 | + getQueueUpdateNotificationTargets(queueName).clear(); | ||
| 332 | + return notifyList; | ||
| 333 | + } | ||
| 334 | + | ||
| 335 | + @Override | ||
| 291 | public boolean prepareAndCommit(Transaction transaction) { | 336 | public boolean prepareAndCommit(Transaction transaction) { |
| 292 | if (prepare(transaction)) { | 337 | if (prepare(transaction)) { |
| 293 | return commit(transaction); | 338 | return commit(transaction); |
| ... | @@ -335,6 +380,14 @@ public class DefaultDatabaseState implements DatabaseState<String, byte[]> { | ... | @@ -335,6 +380,14 @@ public class DefaultDatabaseState implements DatabaseState<String, byte[]> { |
| 335 | return counters.computeIfAbsent(counterName, name -> new AtomicLong(0)); | 380 | return counters.computeIfAbsent(counterName, name -> new AtomicLong(0)); |
| 336 | } | 381 | } |
| 337 | 382 | ||
| 383 | + private Queue<byte[]> getQueue(String queueName) { | ||
| 384 | + return queues.computeIfAbsent(queueName, name -> new LinkedList<>()); | ||
| 385 | + } | ||
| 386 | + | ||
| 387 | + private Set<NodeId> getQueueUpdateNotificationTargets(String queueName) { | ||
| 388 | + return queueUpdateNotificationTargets.computeIfAbsent(queueName, name -> new HashSet<>()); | ||
| 389 | + } | ||
| 390 | + | ||
| 338 | private boolean isUpdatePossible(DatabaseUpdate update) { | 391 | private boolean isUpdatePossible(DatabaseUpdate update) { |
| 339 | Versioned<byte[]> existingEntry = get(update.tableName(), update.key()); | 392 | Versioned<byte[]> existingEntry = get(update.tableName(), update.key()); |
| 340 | switch (update.type()) { | 393 | switch (update.type()) { | ... | ... |
core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDistributedQueue.java
0 → 100644
| 1 | +/* | ||
| 2 | + * Copyright 2015 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.consistent.impl; | ||
| 17 | + | ||
| 18 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
| 19 | + | ||
| 20 | +import java.util.Set; | ||
| 21 | +import java.util.concurrent.CompletableFuture; | ||
| 22 | +import java.util.function.Consumer; | ||
| 23 | + | ||
| 24 | +import org.onosproject.cluster.NodeId; | ||
| 25 | +import org.onosproject.store.service.DistributedQueue; | ||
| 26 | +import org.onosproject.store.service.Serializer; | ||
| 27 | + | ||
| 28 | +import com.google.common.collect.Sets; | ||
| 29 | +import com.google.common.util.concurrent.Futures; | ||
| 30 | + | ||
| 31 | +/** | ||
| 32 | + * DistributedQueue implementation that provides FIFO ordering semantics. | ||
| 33 | + * | ||
| 34 | + * @param <E> queue entry type | ||
| 35 | + */ | ||
| 36 | +public class DefaultDistributedQueue<E> implements DistributedQueue<E> { | ||
| 37 | + | ||
| 38 | + private final String name; | ||
| 39 | + private final Database database; | ||
| 40 | + private final Serializer serializer; | ||
| 41 | + private final NodeId localNodeId; | ||
| 42 | + private final Set<CompletableFuture<E>> pendingFutures = Sets.newIdentityHashSet(); | ||
| 43 | + private final Consumer<Set<NodeId>> notifyConsumers; | ||
| 44 | + | ||
| 45 | + private static final String ERROR_NULL_ENTRY = "Null entries are not allowed"; | ||
| 46 | + | ||
| 47 | + public DefaultDistributedQueue(String name, | ||
| 48 | + Database database, | ||
| 49 | + Serializer serializer, | ||
| 50 | + NodeId localNodeId, | ||
| 51 | + Consumer<Set<NodeId>> notifyConsumers) { | ||
| 52 | + this.name = checkNotNull(name, "queue name cannot be null"); | ||
| 53 | + this.database = checkNotNull(database, "database cannot be null"); | ||
| 54 | + this.serializer = checkNotNull(serializer, "serializer cannot be null"); | ||
| 55 | + this.localNodeId = localNodeId; | ||
| 56 | + this.notifyConsumers = notifyConsumers; | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + @Override | ||
| 60 | + public long size() { | ||
| 61 | + return Futures.getUnchecked(database.queueSize(name)); | ||
| 62 | + } | ||
| 63 | + | ||
| 64 | + @Override | ||
| 65 | + public void push(E entry) { | ||
| 66 | + checkNotNull(entry, ERROR_NULL_ENTRY); | ||
| 67 | + Futures.getUnchecked(database.queuePush(name, serializer.encode(entry)) | ||
| 68 | + .thenAccept(notifyConsumers) | ||
| 69 | + .thenApply(v -> null)); | ||
| 70 | + } | ||
| 71 | + | ||
| 72 | + @Override | ||
| 73 | + public CompletableFuture<E> pop() { | ||
| 74 | + return database.queuePop(name, localNodeId) | ||
| 75 | + .thenCompose(v -> { | ||
| 76 | + if (v != null) { | ||
| 77 | + return CompletableFuture.completedFuture(serializer.decode(v)); | ||
| 78 | + } else { | ||
| 79 | + CompletableFuture<E> newPendingFuture = new CompletableFuture<>(); | ||
| 80 | + pendingFutures.add(newPendingFuture); | ||
| 81 | + return newPendingFuture; | ||
| 82 | + } | ||
| 83 | + }); | ||
| 84 | + } | ||
| 85 | + | ||
| 86 | + @Override | ||
| 87 | + public E peek() { | ||
| 88 | + return Futures.getUnchecked(database.queuePeek(name) | ||
| 89 | + .thenApply(v -> v != null ? serializer.decode(v) : null)); | ||
| 90 | + } | ||
| 91 | + | ||
| 92 | + public String name() { | ||
| 93 | + return name; | ||
| 94 | + } | ||
| 95 | + | ||
| 96 | + protected void tryPoll() { | ||
| 97 | + Set<CompletableFuture<E>> completedFutures = Sets.newHashSet(); | ||
| 98 | + for (CompletableFuture<E> future : pendingFutures) { | ||
| 99 | + E entry = Futures.getUnchecked(database.queuePop(name, localNodeId) | ||
| 100 | + .thenApply(v -> v != null ? serializer.decode(v) : null)); | ||
| 101 | + if (entry != null) { | ||
| 102 | + future.complete(entry); | ||
| 103 | + completedFutures.add(future); | ||
| 104 | + } else { | ||
| 105 | + break; | ||
| 106 | + } | ||
| 107 | + } | ||
| 108 | + pendingFutures.removeAll(completedFutures); | ||
| 109 | + } | ||
| 110 | +} | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| 1 | +/* | ||
| 2 | + * Copyright 2015 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.consistent.impl; | ||
| 17 | + | ||
| 18 | +import static com.google.common.base.Preconditions.checkArgument; | ||
| 19 | +import static com.google.common.base.Preconditions.checkState; | ||
| 20 | + | ||
| 21 | +import java.util.Set; | ||
| 22 | +import java.util.function.Consumer; | ||
| 23 | + | ||
| 24 | +import org.onosproject.cluster.NodeId; | ||
| 25 | +import org.onosproject.store.service.DistributedQueue; | ||
| 26 | +import org.onosproject.store.service.DistributedQueueBuilder; | ||
| 27 | +import org.onosproject.store.service.Serializer; | ||
| 28 | + | ||
| 29 | +import com.google.common.base.Charsets; | ||
| 30 | + | ||
| 31 | +/** | ||
| 32 | + * Default implementation of a {@code DistributedQueueBuilder}. | ||
| 33 | + * | ||
| 34 | + * @param <E> queue entry type | ||
| 35 | + */ | ||
| 36 | +public class DefaultDistributedQueueBuilder<E> implements DistributedQueueBuilder<E> { | ||
| 37 | + | ||
| 38 | + private Serializer serializer; | ||
| 39 | + private String name; | ||
| 40 | + private boolean persistenceEnabled = true; | ||
| 41 | + private final DatabaseManager databaseManager; | ||
| 42 | + | ||
| 43 | + public DefaultDistributedQueueBuilder( | ||
| 44 | + DatabaseManager databaseManager) { | ||
| 45 | + this.databaseManager = databaseManager; | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + @Override | ||
| 49 | + public DistributedQueueBuilder<E> withName(String name) { | ||
| 50 | + checkArgument(name != null && !name.isEmpty()); | ||
| 51 | + this.name = name; | ||
| 52 | + return this; | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + @Override | ||
| 56 | + public DistributedQueueBuilder<E> withSerializer(Serializer serializer) { | ||
| 57 | + checkArgument(serializer != null); | ||
| 58 | + this.serializer = serializer; | ||
| 59 | + return this; | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | + @Override | ||
| 63 | + public DistributedQueueBuilder<E> withPersistenceDisabled() { | ||
| 64 | + persistenceEnabled = false; | ||
| 65 | + return this; | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + private boolean validInputs() { | ||
| 69 | + return name != null && serializer != null; | ||
| 70 | + } | ||
| 71 | + | ||
| 72 | + @Override | ||
| 73 | + public DistributedQueue<E> build() { | ||
| 74 | + checkState(validInputs()); | ||
| 75 | + Consumer<Set<NodeId>> notifyOthers = nodes -> databaseManager.clusterCommunicator.multicast(name, | ||
| 76 | + DatabaseManager.QUEUE_UPDATED_TOPIC, | ||
| 77 | + s -> s.getBytes(Charsets.UTF_8), | ||
| 78 | + nodes); | ||
| 79 | + DefaultDistributedQueue<E> queue = new DefaultDistributedQueue<>( | ||
| 80 | + name, | ||
| 81 | + persistenceEnabled ? databaseManager.partitionedDatabase : databaseManager.inMemoryDatabase, | ||
| 82 | + serializer, | ||
| 83 | + databaseManager.localNodeId, | ||
| 84 | + notifyOthers); | ||
| 85 | + databaseManager.registerQueue(queue); | ||
| 86 | + return queue; | ||
| 87 | + } | ||
| 88 | +} |
| ... | @@ -27,6 +27,7 @@ import java.util.concurrent.atomic.AtomicBoolean; | ... | @@ -27,6 +27,7 @@ import java.util.concurrent.atomic.AtomicBoolean; |
| 27 | import java.util.concurrent.atomic.AtomicInteger; | 27 | import java.util.concurrent.atomic.AtomicInteger; |
| 28 | import java.util.stream.Collectors; | 28 | import java.util.stream.Collectors; |
| 29 | 29 | ||
| 30 | +import org.onosproject.cluster.NodeId; | ||
| 30 | import org.onosproject.store.service.DatabaseUpdate; | 31 | import org.onosproject.store.service.DatabaseUpdate; |
| 31 | import org.onosproject.store.service.Transaction; | 32 | import org.onosproject.store.service.Transaction; |
| 32 | import org.onosproject.store.service.Versioned; | 33 | import org.onosproject.store.service.Versioned; |
| ... | @@ -276,6 +277,31 @@ public class PartitionedDatabase implements Database { | ... | @@ -276,6 +277,31 @@ public class PartitionedDatabase implements Database { |
| 276 | return partitioner.getPartition(counterName, counterName).counterGetAndAdd(counterName, delta); | 277 | return partitioner.getPartition(counterName, counterName).counterGetAndAdd(counterName, delta); |
| 277 | } | 278 | } |
| 278 | 279 | ||
| 280 | + | ||
| 281 | + @Override | ||
| 282 | + public CompletableFuture<Long> queueSize(String queueName) { | ||
| 283 | + checkState(isOpen.get(), DB_NOT_OPEN); | ||
| 284 | + return partitioner.getPartition(queueName, queueName).queueSize(queueName); | ||
| 285 | + } | ||
| 286 | + | ||
| 287 | + @Override | ||
| 288 | + public CompletableFuture<Set<NodeId>> queuePush(String queueName, byte[] entry) { | ||
| 289 | + checkState(isOpen.get(), DB_NOT_OPEN); | ||
| 290 | + return partitioner.getPartition(queueName, queueName).queuePush(queueName, entry); | ||
| 291 | + } | ||
| 292 | + | ||
| 293 | + @Override | ||
| 294 | + public CompletableFuture<byte[]> queuePop(String queueName, NodeId nodeId) { | ||
| 295 | + checkState(isOpen.get(), DB_NOT_OPEN); | ||
| 296 | + return partitioner.getPartition(queueName, queueName).queuePop(queueName, nodeId); | ||
| 297 | + } | ||
| 298 | + | ||
| 299 | + @Override | ||
| 300 | + public CompletableFuture<byte[]> queuePeek(String queueName) { | ||
| 301 | + checkState(isOpen.get(), DB_NOT_OPEN); | ||
| 302 | + return partitioner.getPartition(queueName, queueName).queuePeek(queueName); | ||
| 303 | + } | ||
| 304 | + | ||
| 279 | @Override | 305 | @Override |
| 280 | public CompletableFuture<Boolean> prepareAndCommit(Transaction transaction) { | 306 | public CompletableFuture<Boolean> prepareAndCommit(Transaction transaction) { |
| 281 | Map<Database, Transaction> subTransactions = createSubTransactions(transaction); | 307 | Map<Database, Transaction> subTransactions = createSubTransactions(transaction); | ... | ... |
-
Please register or login to post a comment