Madan Jampani
Committed by Gerrit Code Review

Dropping DatabaseManager and related code. Goodbye!

Change-Id: I5d90d62678402234462dad8be455903de481da21
Showing 34 changed files with 3 additions and 4924 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.primitives.impl;
17 -
18 -import java.util.concurrent.CompletableFuture;
19 -
20 -import org.onosproject.core.ApplicationId;
21 -import org.onosproject.store.service.Serializer;
22 -import org.onosproject.store.service.Versioned;
23 -
24 -import com.google.common.cache.CacheBuilder;
25 -import com.google.common.cache.CacheLoader;
26 -import com.google.common.cache.LoadingCache;
27 -
28 -/**
29 - * Extension of {@link DefaultAsyncConsistentMap} that provides a weaker read consistency
30 - * guarantee in return for better read performance.
31 - * <p>
32 - * For read/write operations that are local to a node this map implementation provides
33 - * guarantees similar to a ConsistentMap. However for read/write operations executed
34 - * across multiple nodes this implementation only provides eventual consistency.
35 - *
36 - * @param <K> key type
37 - * @param <V> value type
38 - */
39 -public class AsyncCachingConsistentMap<K, V> extends DefaultAsyncConsistentMap<K, V> {
40 -
41 - private final LoadingCache<K, CompletableFuture<Versioned<V>>> cache =
42 - CacheBuilder.newBuilder()
43 - .maximumSize(10000) // TODO: make configurable
44 - .build(new CacheLoader<K, CompletableFuture<Versioned<V>>>() {
45 - @Override
46 - public CompletableFuture<Versioned<V>> load(K key)
47 - throws Exception {
48 - return AsyncCachingConsistentMap.super.get(key);
49 - }
50 - });
51 -
52 - public AsyncCachingConsistentMap(String name,
53 - ApplicationId applicationId,
54 - Database database,
55 - Serializer serializer,
56 - boolean readOnly,
57 - boolean purgeOnUninstall,
58 - boolean meteringEnabled) {
59 - super(name, applicationId, database, serializer, readOnly, purgeOnUninstall, meteringEnabled);
60 - addListener(event -> cache.invalidate(event.key()));
61 - }
62 -
63 - @Override
64 - public CompletableFuture<Versioned<V>> get(K key) {
65 - CompletableFuture<Versioned<V>> cachedValue = cache.getIfPresent(key);
66 - if (cachedValue != null) {
67 - if (cachedValue.isCompletedExceptionally()) {
68 - cache.invalidate(key);
69 - } else {
70 - return cachedValue;
71 - }
72 - }
73 - return cache.getUnchecked(key);
74 - }
75 -
76 - @Override
77 - protected void beforeUpdate(K key) {
78 - super.beforeUpdate(key);
79 - cache.invalidate(key);
80 - }
81 -}
...\ 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.primitives.impl;
17 -
18 -import static com.google.common.base.MoreObjects.toStringHelper;
19 -
20 -import java.util.Collections;
21 -import java.util.List;
22 -
23 -import com.google.common.collect.ImmutableList;
24 -
25 -/**
26 - * Result of a Transaction commit operation.
27 - */
28 -public final class CommitResponse {
29 -
30 - private boolean success;
31 - private List<UpdateResult<String, byte[]>> updates;
32 -
33 - public static CommitResponse success(List<UpdateResult<String, byte[]>> updates) {
34 - return new CommitResponse(true, updates);
35 - }
36 -
37 - public static CommitResponse failure() {
38 - return new CommitResponse(false, Collections.emptyList());
39 - }
40 -
41 - private CommitResponse(boolean success, List<UpdateResult<String, byte[]>> updates) {
42 - this.success = success;
43 - this.updates = ImmutableList.copyOf(updates);
44 - }
45 -
46 - public boolean success() {
47 - return success;
48 - }
49 -
50 - public List<UpdateResult<String, byte[]>> updates() {
51 - return updates;
52 - }
53 -
54 - @Override
55 - public String toString() {
56 - return toStringHelper(this)
57 - .add("success", success)
58 - .add("udpates", updates)
59 - .toString();
60 - }
61 -}
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.primitives.impl;
17 -
18 -import java.net.URI;
19 -import java.nio.ByteBuffer;
20 -import java.util.concurrent.CompletableFuture;
21 -
22 -import org.onlab.util.Tools;
23 -import org.onosproject.cluster.ClusterService;
24 -import org.onosproject.cluster.ControllerNode;
25 -import org.onosproject.cluster.NodeId;
26 -import org.onosproject.store.cluster.messaging.ClusterCommunicationService;
27 -import org.onosproject.store.cluster.messaging.MessageSubject;
28 -
29 -import net.kuujo.copycat.protocol.AbstractProtocol;
30 -import net.kuujo.copycat.protocol.ProtocolClient;
31 -import net.kuujo.copycat.protocol.ProtocolHandler;
32 -import net.kuujo.copycat.protocol.ProtocolServer;
33 -import net.kuujo.copycat.util.Configurable;
34 -
35 -/**
36 - * Protocol for Copycat communication that employs
37 - * {@code ClusterCommunicationService}.
38 - */
39 -public class CopycatCommunicationProtocol extends AbstractProtocol {
40 -
41 - private static final MessageSubject COPYCAT_MESSAGE_SUBJECT =
42 - new MessageSubject("onos-copycat-message");
43 -
44 - protected ClusterService clusterService;
45 - protected ClusterCommunicationService clusterCommunicator;
46 -
47 - public CopycatCommunicationProtocol(ClusterService clusterService,
48 - ClusterCommunicationService clusterCommunicator) {
49 - this.clusterService = clusterService;
50 - this.clusterCommunicator = clusterCommunicator;
51 - }
52 -
53 - @Override
54 - public Configurable copy() {
55 - return this;
56 - }
57 -
58 - @Override
59 - public ProtocolClient createClient(URI uri) {
60 - NodeId nodeId = uriToNodeId(uri);
61 - if (nodeId == null) {
62 - throw new IllegalStateException("Unknown peer " + uri);
63 - }
64 - return new Client(nodeId);
65 - }
66 -
67 - @Override
68 - public ProtocolServer createServer(URI uri) {
69 - return new Server();
70 - }
71 -
72 - private class Server implements ProtocolServer {
73 -
74 - @Override
75 - public void handler(ProtocolHandler handler) {
76 - if (handler == null) {
77 - clusterCommunicator.removeSubscriber(COPYCAT_MESSAGE_SUBJECT);
78 - } else {
79 - clusterCommunicator.addSubscriber(COPYCAT_MESSAGE_SUBJECT,
80 - ByteBuffer::wrap,
81 - handler,
82 - Tools::byteBuffertoArray);
83 - // FIXME: Tools::byteBuffertoArray involves a array copy.
84 - }
85 - }
86 -
87 - @Override
88 - public CompletableFuture<Void> listen() {
89 - return CompletableFuture.completedFuture(null);
90 - }
91 -
92 - @Override
93 - public CompletableFuture<Void> close() {
94 - clusterCommunicator.removeSubscriber(COPYCAT_MESSAGE_SUBJECT);
95 - return CompletableFuture.completedFuture(null);
96 - }
97 - }
98 -
99 - private class Client implements ProtocolClient {
100 - private final NodeId peer;
101 -
102 - public Client(NodeId peer) {
103 - this.peer = peer;
104 - }
105 -
106 - @Override
107 - public CompletableFuture<ByteBuffer> write(ByteBuffer request) {
108 - return clusterCommunicator.sendAndReceive(request,
109 - COPYCAT_MESSAGE_SUBJECT,
110 - Tools::byteBuffertoArray,
111 - ByteBuffer::wrap,
112 - peer);
113 - }
114 -
115 - @Override
116 - public CompletableFuture<Void> connect() {
117 - return CompletableFuture.completedFuture(null);
118 - }
119 -
120 - @Override
121 - public CompletableFuture<Void> close() {
122 - return CompletableFuture.completedFuture(null);
123 - }
124 - }
125 -
126 - private NodeId uriToNodeId(URI uri) {
127 - return clusterService.getNodes()
128 - .stream()
129 - .filter(node -> uri.getHost().equals(node.ip().toString()))
130 - .map(ControllerNode::id)
131 - .findAny()
132 - .orElse(null);
133 - }
134 -}
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 -
17 -package org.onosproject.store.primitives.impl;
18 -
19 -
20 -import java.util.function.Consumer;
21 -
22 -import net.kuujo.copycat.cluster.ClusterConfig;
23 -import net.kuujo.copycat.cluster.internal.coordinator.ClusterCoordinator;
24 -import net.kuujo.copycat.cluster.internal.coordinator.CoordinatorConfig;
25 -import net.kuujo.copycat.cluster.internal.coordinator.DefaultClusterCoordinator;
26 -import net.kuujo.copycat.resource.Resource;
27 -
28 -/**
29 - * Database.
30 - */
31 -public interface Database extends DatabaseProxy<String, byte[]>, Resource<Database> {
32 -
33 - /**
34 - * Creates a new database with the default cluster configuration.<p>
35 - *
36 - * The database will be constructed with the default cluster configuration. The default cluster configuration
37 - * searches for two resources on the classpath - {@code cluster} and {cluster-defaults} - in that order. Configuration
38 - * options specified in {@code cluster.conf} will override those in {cluster-defaults.conf}.<p>
39 - *
40 - * Additionally, the database will be constructed with an database configuration that searches the classpath for
41 - * three configuration files - {@code name}, {@code database}, {@code database-defaults}, {@code resource}, and
42 - * {@code resource-defaults} - in that order. The first resource is a configuration resource with the same name
43 - * as the map resource. If the resource is namespaced - e.g. `databases.my-database.conf` - then resource
44 - * configurations will be loaded according to namespaces as well; for example, `databases.conf`.
45 - *
46 - * @param name The database name.
47 - * @return The database.
48 - */
49 - static Database create(String name) {
50 - return create(name, new ClusterConfig(), new DatabaseConfig());
51 - }
52 -
53 - /**
54 - * Creates a new database.<p>
55 - *
56 - * The database will be constructed with an database configuration that searches the classpath for
57 - * three configuration files - {@code name}, {@code database}, {@code database-defaults}, {@code resource}, and
58 - * {@code resource-defaults} - in that order. The first resource is a configuration resource with the same name
59 - * as the database resource. If the resource is namespaced - e.g. `databases.my-database.conf` - then resource
60 - * configurations will be loaded according to namespaces as well; for example, `databases.conf`.
61 - *
62 - * @param name The database name.
63 - * @param cluster The cluster configuration.
64 - * @return The database.
65 - */
66 - static Database create(String name, ClusterConfig cluster) {
67 - return create(name, cluster, new DatabaseConfig());
68 - }
69 -
70 - /**
71 - * Creates a new database.
72 - *
73 - * @param name The database name.
74 - * @param cluster The cluster configuration.
75 - * @param config The database configuration.
76 -
77 - * @return The database.
78 - */
79 - static Database create(String name, ClusterConfig cluster, DatabaseConfig config) {
80 - ClusterCoordinator coordinator =
81 - new DefaultClusterCoordinator(new CoordinatorConfig().withName(name).withClusterConfig(cluster));
82 - return coordinator.<Database>getResource(name, config.resolve(cluster))
83 - .addStartupTask(() -> coordinator.open().thenApply(v -> null))
84 - .addShutdownTask(coordinator::close);
85 - }
86 -
87 - /**
88 - * Tells whether the database supports change notifications.
89 - * @return true if notifications are supported; false otherwise
90 - */
91 - default boolean hasChangeNotificationSupport() {
92 - return true;
93 - }
94 -
95 - /**
96 - * Registers a new consumer of StateMachineUpdates.
97 - * @param consumer consumer to register
98 - */
99 - void registerConsumer(Consumer<StateMachineUpdate> consumer);
100 -
101 - /**
102 - * Unregisters a consumer of StateMachineUpdates.
103 - * @param consumer consumer to unregister
104 - */
105 - void unregisterConsumer(Consumer<StateMachineUpdate> consumer);
106 -}
...\ 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 -
17 -package org.onosproject.store.primitives.impl;
18 -
19 -import com.typesafe.config.ConfigValueFactory;
20 -import net.kuujo.copycat.cluster.ClusterConfig;
21 -import net.kuujo.copycat.cluster.internal.coordinator.CoordinatedResourceConfig;
22 -import net.kuujo.copycat.protocol.Consistency;
23 -import net.kuujo.copycat.resource.ResourceConfig;
24 -import net.kuujo.copycat.state.StateLogConfig;
25 -import net.kuujo.copycat.util.internal.Assert;
26 -
27 -import java.util.Map;
28 -
29 -/**
30 - * Database configuration.
31 - *
32 - */
33 -public class DatabaseConfig extends ResourceConfig<DatabaseConfig> {
34 - private static final String DATABASE_CONSISTENCY = "consistency";
35 -
36 - private static final String DEFAULT_CONFIGURATION = "database-defaults";
37 - private static final String CONFIGURATION = "database";
38 -
39 - private String name;
40 -
41 - public DatabaseConfig() {
42 - super(CONFIGURATION, DEFAULT_CONFIGURATION);
43 - }
44 -
45 - public DatabaseConfig(Map<String, Object> config) {
46 - super(config, CONFIGURATION, DEFAULT_CONFIGURATION);
47 - }
48 -
49 - public DatabaseConfig(String resource) {
50 - super(resource, CONFIGURATION, DEFAULT_CONFIGURATION);
51 - }
52 -
53 - protected DatabaseConfig(DatabaseConfig config) {
54 - super(config);
55 - }
56 -
57 - @Override
58 - public DatabaseConfig copy() {
59 - return new DatabaseConfig(this);
60 - }
61 -
62 - /**
63 - * Sets the database read consistency.
64 - *
65 - * @param consistency The database read consistency.
66 - * @throws java.lang.NullPointerException If the consistency is {@code null}
67 - */
68 - public void setConsistency(String consistency) {
69 - this.config = config.withValue(DATABASE_CONSISTENCY,
70 - ConfigValueFactory.fromAnyRef(
71 - Consistency.parse(Assert.isNotNull(consistency, "consistency")).toString()));
72 - }
73 -
74 - /**
75 - * Sets the database read consistency.
76 - *
77 - * @param consistency The database read consistency.
78 - * @throws java.lang.NullPointerException If the consistency is {@code null}
79 - */
80 - public void setConsistency(Consistency consistency) {
81 - this.config = config.withValue(DATABASE_CONSISTENCY,
82 - ConfigValueFactory.fromAnyRef(
83 - Assert.isNotNull(consistency, "consistency").toString()));
84 - }
85 -
86 - /**
87 - * Returns the database read consistency.
88 - *
89 - * @return The database read consistency.
90 - */
91 - public Consistency getConsistency() {
92 - return Consistency.parse(config.getString(DATABASE_CONSISTENCY));
93 - }
94 -
95 - /**
96 - * Sets the database read consistency, returning the configuration for method chaining.
97 - *
98 - * @param consistency The database read consistency.
99 - * @return The database configuration.
100 - * @throws java.lang.NullPointerException If the consistency is {@code null}
101 - */
102 - public DatabaseConfig withConsistency(String consistency) {
103 - setConsistency(consistency);
104 - return this;
105 - }
106 -
107 - /**
108 - * Sets the database read consistency, returning the configuration for method chaining.
109 - *
110 - * @param consistency The database read consistency.
111 - * @return The database configuration.
112 - * @throws java.lang.NullPointerException If the consistency is {@code null}
113 - */
114 - public DatabaseConfig withConsistency(Consistency consistency) {
115 - setConsistency(consistency);
116 - return this;
117 - }
118 -
119 - /**
120 - * Returns the database name.
121 - *
122 - * @return The database name
123 - */
124 - public String getName() {
125 - return name;
126 - }
127 -
128 - /**
129 - * Sets the database name, returning the configuration for method chaining.
130 - *
131 - * @param name The database name
132 - * @return The database configuration
133 - * @throws java.lang.NullPointerException If the name is {@code null}
134 - */
135 - public DatabaseConfig withName(String name) {
136 - setName(Assert.isNotNull(name, "name"));
137 - return this;
138 - }
139 -
140 - /**
141 - * Sets the database name.
142 - *
143 - * @param name The database name
144 - * @throws java.lang.NullPointerException If the name is {@code null}
145 - */
146 - public void setName(String name) {
147 - this.name = Assert.isNotNull(name, "name");
148 - }
149 -
150 - @Override
151 - public CoordinatedResourceConfig resolve(ClusterConfig cluster) {
152 - return new StateLogConfig(toMap())
153 - .resolve(cluster)
154 - .withResourceType(DefaultDatabase.class);
155 - }
156 -
157 -}
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 -
17 -package org.onosproject.store.primitives.impl;
18 -
19 -import static org.onosproject.app.ApplicationEvent.Type.APP_DEACTIVATED;
20 -import static org.onosproject.app.ApplicationEvent.Type.APP_UNINSTALLED;
21 -import static org.slf4j.LoggerFactory.getLogger;
22 -
23 -import java.util.Collection;
24 -import java.util.List;
25 -import java.util.Map;
26 -import java.util.Set;
27 -import java.util.UUID;
28 -import java.util.concurrent.CompletableFuture;
29 -import java.util.concurrent.ExecutionException;
30 -import java.util.concurrent.Executors;
31 -import java.util.concurrent.TimeUnit;
32 -import java.util.concurrent.TimeoutException;
33 -import java.util.function.Function;
34 -import java.util.function.Supplier;
35 -import java.util.stream.Collectors;
36 -
37 -import net.kuujo.copycat.CopycatConfig;
38 -import net.kuujo.copycat.cluster.ClusterConfig;
39 -import net.kuujo.copycat.cluster.Member;
40 -import net.kuujo.copycat.cluster.Member.Type;
41 -import net.kuujo.copycat.cluster.internal.coordinator.ClusterCoordinator;
42 -import net.kuujo.copycat.cluster.internal.coordinator.DefaultClusterCoordinator;
43 -import net.kuujo.copycat.log.BufferedLog;
44 -import net.kuujo.copycat.log.FileLog;
45 -import net.kuujo.copycat.log.Log;
46 -import net.kuujo.copycat.protocol.Consistency;
47 -import net.kuujo.copycat.protocol.Protocol;
48 -import net.kuujo.copycat.util.concurrent.NamedThreadFactory;
49 -
50 -import org.apache.felix.scr.annotations.Activate;
51 -import org.apache.felix.scr.annotations.Component;
52 -import org.apache.felix.scr.annotations.Deactivate;
53 -import org.apache.felix.scr.annotations.Reference;
54 -import org.apache.felix.scr.annotations.ReferenceCardinality;
55 -import org.apache.felix.scr.annotations.ReferencePolicy;
56 -import org.apache.felix.scr.annotations.Service;
57 -import org.onosproject.app.ApplicationEvent;
58 -import org.onosproject.app.ApplicationListener;
59 -import org.onosproject.app.ApplicationService;
60 -import org.onosproject.cluster.ClusterMetadataService;
61 -import org.onosproject.cluster.ClusterService;
62 -import org.onosproject.cluster.ControllerNode;
63 -import org.onosproject.cluster.NodeId;
64 -import org.onosproject.cluster.PartitionId;
65 -import org.onosproject.core.ApplicationId;
66 -import org.onosproject.persistence.PersistenceService;
67 -import org.onosproject.store.cluster.messaging.ClusterCommunicationService;
68 -import org.onosproject.store.primitives.MapUpdate;
69 -import org.onosproject.store.primitives.TransactionId;
70 -import org.onosproject.store.serializers.KryoNamespaces;
71 -import org.onosproject.store.service.AsyncConsistentMap;
72 -import org.onosproject.store.service.AtomicCounterBuilder;
73 -import org.onosproject.store.service.AtomicValueBuilder;
74 -import org.onosproject.store.service.ConsistentMapBuilder;
75 -import org.onosproject.store.service.ConsistentMapException;
76 -import org.onosproject.store.service.DistributedQueueBuilder;
77 -import org.onosproject.store.service.DistributedSetBuilder;
78 -import org.onosproject.store.service.EventuallyConsistentMapBuilder;
79 -import org.onosproject.store.service.LeaderElectorBuilder;
80 -import org.onosproject.store.service.MapInfo;
81 -import org.onosproject.store.service.PartitionInfo;
82 -import org.onosproject.store.service.Serializer;
83 -import org.onosproject.store.service.StorageAdminService;
84 -import org.onosproject.store.service.StorageService;
85 -import org.onosproject.store.service.TransactionContextBuilder;
86 -import org.slf4j.Logger;
87 -
88 -import com.google.common.collect.ArrayListMultimap;
89 -import com.google.common.collect.ImmutableList;
90 -import com.google.common.collect.Lists;
91 -import com.google.common.collect.Maps;
92 -import com.google.common.collect.Multimap;
93 -import com.google.common.collect.Multimaps;
94 -import com.google.common.collect.Sets;
95 -import com.google.common.util.concurrent.Futures;
96 -
97 -/**
98 - * Database manager.
99 - */
100 -@Component(immediate = true, enabled = false)
101 -@Service
102 -public class DatabaseManager implements StorageService, StorageAdminService {
103 -
104 - private final Logger log = getLogger(getClass());
105 -
106 - public static final String BASE_PARTITION_NAME = "p0";
107 -
108 - private static final int RAFT_ELECTION_TIMEOUT_MILLIS = 3000;
109 - private static final int DATABASE_OPERATION_TIMEOUT_MILLIS = 5000;
110 -
111 - private ClusterCoordinator coordinator;
112 - protected PartitionedDatabase partitionedDatabase;
113 - protected Database inMemoryDatabase;
114 - protected NodeId localNodeId;
115 -
116 - private TransactionManager transactionManager;
117 - private final Supplier<TransactionId> transactionIdGenerator =
118 - () -> TransactionId.from(UUID.randomUUID().toString());
119 -
120 - private ApplicationListener appListener = new InternalApplicationListener();
121 -
122 - private final Multimap<String, DefaultAsyncConsistentMap> maps =
123 - Multimaps.synchronizedMultimap(ArrayListMultimap.create());
124 - private final Multimap<ApplicationId, DefaultAsyncConsistentMap> mapsByApplication =
125 - Multimaps.synchronizedMultimap(ArrayListMultimap.create());
126 -
127 - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
128 - protected ClusterMetadataService clusterMetadataService;
129 -
130 - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
131 - protected ClusterService clusterService;
132 -
133 - @Reference(cardinality = ReferenceCardinality.OPTIONAL_UNARY, policy = ReferencePolicy.DYNAMIC)
134 - protected ApplicationService applicationService;
135 -
136 - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
137 - protected ClusterCommunicationService clusterCommunicator;
138 -
139 - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
140 - protected PersistenceService persistenceService;
141 -
142 - protected String nodeIdToUri(NodeId nodeId) {
143 - ControllerNode node = clusterService.getNode(nodeId);
144 - return String.format("onos://%s:%d", node.ip(), node.tcpPort());
145 - }
146 -
147 - protected void bindApplicationService(ApplicationService service) {
148 - applicationService = service;
149 - applicationService.addListener(appListener);
150 - }
151 -
152 - protected void unbindApplicationService(ApplicationService service) {
153 - applicationService.removeListener(appListener);
154 - this.applicationService = null;
155 - }
156 -
157 - @Activate
158 - public void activate() {
159 - localNodeId = clusterService.getLocalNode().id();
160 -
161 - Map<PartitionId, Set<NodeId>> partitionMap = Maps.newHashMap();
162 - clusterMetadataService.getClusterMetadata().getPartitions().forEach(p -> {
163 - partitionMap.put(p.getId(), Sets.newHashSet(p.getMembers()));
164 - });
165 -
166 - String[] activeNodeUris = partitionMap.values()
167 - .stream()
168 - .reduce((s1, s2) -> Sets.union(s1, s2))
169 - .get()
170 - .stream()
171 - .map(this::nodeIdToUri)
172 - .toArray(String[]::new);
173 -
174 - String localNodeUri = nodeIdToUri(clusterMetadataService.getLocalNode().id());
175 - Protocol protocol = new CopycatCommunicationProtocol(clusterService, clusterCommunicator);
176 -
177 - ClusterConfig clusterConfig = new ClusterConfig()
178 - .withProtocol(protocol)
179 - .withElectionTimeout(electionTimeoutMillis(activeNodeUris))
180 - .withHeartbeatInterval(heartbeatTimeoutMillis(activeNodeUris))
181 - .withMembers(activeNodeUris)
182 - .withLocalMember(localNodeUri);
183 -
184 - CopycatConfig copycatConfig = new CopycatConfig()
185 - .withName("onos")
186 - .withClusterConfig(clusterConfig)
187 - .withDefaultSerializer(new DatabaseSerializer())
188 - .withDefaultExecutor(Executors.newSingleThreadExecutor(new NamedThreadFactory("copycat-coordinator-%d")));
189 -
190 - coordinator = new DefaultClusterCoordinator(copycatConfig.resolve());
191 -
192 - Function<PartitionId, Log> logFunction = id -> id.asInt() == 0 ? newInMemoryLog() : newPersistentLog();
193 -
194 - Map<PartitionId, Database> databases = Maps.transformEntries(partitionMap, (k, v) -> {
195 - String[] replicas = v.stream().map(this::nodeIdToUri).toArray(String[]::new);
196 - DatabaseConfig config = newDatabaseConfig(String.format("p%s", k), logFunction.apply(k), replicas);
197 - return coordinator.<Database>getResource(config.getName(), config.resolve(clusterConfig)
198 - .withSerializer(copycatConfig.getDefaultSerializer())
199 - .withDefaultExecutor(copycatConfig.getDefaultExecutor()));
200 - });
201 -
202 - inMemoryDatabase = databases.remove(PartitionId.from(0));
203 -
204 - partitionedDatabase = new PartitionedDatabase("onos-store", databases.values());
205 -
206 - CompletableFuture<Void> status = coordinator.open()
207 - .thenCompose(v -> CompletableFuture.allOf(inMemoryDatabase.open(), partitionedDatabase.open())
208 - .whenComplete((db, error) -> {
209 - if (error != null) {
210 - log.error("Failed to initialize database.", error);
211 - } else {
212 - log.info("Successfully initialized database.");
213 - }
214 - }));
215 -
216 - Futures.getUnchecked(status);
217 -
218 - AsyncConsistentMap<TransactionId, Transaction> transactions =
219 - this.<TransactionId, Transaction>consistentMapBuilder()
220 - .withName("onos-transactions")
221 - .withSerializer(Serializer.using(KryoNamespaces.API,
222 - MapUpdate.class,
223 - MapUpdate.Type.class,
224 - Transaction.class,
225 - Transaction.State.class))
226 - .buildAsyncMap();
227 -
228 - transactionManager = new TransactionManager(partitionedDatabase, transactions);
229 - partitionedDatabase.setTransactionManager(transactionManager);
230 -
231 - log.info("Started");
232 - }
233 -
234 - @Deactivate
235 - public void deactivate() {
236 - CompletableFuture.allOf(inMemoryDatabase.close(), partitionedDatabase.close())
237 - .thenCompose(v -> coordinator.close())
238 - .whenComplete((result, error) -> {
239 - if (error != null) {
240 - log.warn("Failed to cleanly close databases.", error);
241 - } else {
242 - log.info("Successfully closed databases.");
243 - }
244 - });
245 - ImmutableList.copyOf(maps.values()).forEach(this::unregisterMap);
246 - if (applicationService != null) {
247 - applicationService.removeListener(appListener);
248 - }
249 - log.info("Stopped");
250 - }
251 -
252 - @Override
253 - public TransactionContextBuilder transactionContextBuilder() {
254 - return new DefaultTransactionContextBuilder(this::consistentMapBuilder,
255 - transactionManager::execute,
256 - transactionIdGenerator.get());
257 - }
258 -
259 - @Override
260 - public List<PartitionInfo> getPartitionInfo() {
261 - return Lists.asList(
262 - inMemoryDatabase,
263 - partitionedDatabase.getPartitions().toArray(new Database[]{}))
264 - .stream()
265 - .map(DatabaseManager::toPartitionInfo)
266 - .collect(Collectors.toList());
267 - }
268 -
269 - private Log newPersistentLog() {
270 - String logDir = System.getProperty("karaf.data", "./data");
271 - return new FileLog()
272 - .withDirectory(logDir)
273 - .withSegmentSize(1073741824) // 1GB
274 - .withFlushOnWrite(true)
275 - .withSegmentInterval(Long.MAX_VALUE);
276 - }
277 -
278 - private Log newInMemoryLog() {
279 - return new BufferedLog()
280 - .withFlushOnWrite(false)
281 - .withFlushInterval(Long.MAX_VALUE)
282 - .withSegmentSize(10485760) // 10MB
283 - .withSegmentInterval(Long.MAX_VALUE);
284 - }
285 -
286 - private DatabaseConfig newDatabaseConfig(String name, Log log, String[] replicas) {
287 - return new DatabaseConfig()
288 - .withName(name)
289 - .withElectionTimeout(electionTimeoutMillis(replicas))
290 - .withHeartbeatInterval(heartbeatTimeoutMillis(replicas))
291 - .withConsistency(Consistency.DEFAULT)
292 - .withLog(log)
293 - .withDefaultSerializer(new DatabaseSerializer())
294 - .withReplicas(replicas);
295 - }
296 -
297 - private long electionTimeoutMillis(String[] replicas) {
298 - return replicas.length == 1 ? 10L : RAFT_ELECTION_TIMEOUT_MILLIS;
299 - }
300 -
301 - private long heartbeatTimeoutMillis(String[] replicas) {
302 - return electionTimeoutMillis(replicas) / 2;
303 - }
304 -
305 - /**
306 - * Maps a Raft Database object to a PartitionInfo object.
307 - *
308 - * @param database database containing input data
309 - * @return PartitionInfo object
310 - */
311 - private static PartitionInfo toPartitionInfo(Database database) {
312 - return new PartitionInfo(database.name(),
313 - database.cluster().term(),
314 - database.cluster().members()
315 - .stream()
316 - .filter(member -> Type.ACTIVE.equals(member.type()))
317 - .map(Member::uri)
318 - .sorted()
319 - .collect(Collectors.toList()),
320 - database.cluster().leader() != null ?
321 - database.cluster().leader().uri() : null);
322 - }
323 -
324 -
325 - @Override
326 - public <K, V> EventuallyConsistentMapBuilder<K, V> eventuallyConsistentMapBuilder() {
327 - return new EventuallyConsistentMapBuilderImpl<>(clusterService,
328 - clusterCommunicator,
329 - persistenceService);
330 - }
331 -
332 - @Override
333 - public <K, V> ConsistentMapBuilder<K, V> consistentMapBuilder() {
334 - return new DefaultConsistentMapBuilder<>(this);
335 - }
336 -
337 - @Override
338 - public <E> DistributedSetBuilder<E> setBuilder() {
339 - return new DefaultDistributedSetBuilder<>(() -> this.<E, Boolean>consistentMapBuilder());
340 - }
341 -
342 -
343 - @Override
344 - public <E> DistributedQueueBuilder<E> queueBuilder() {
345 - return new DefaultDistributedQueueBuilder<>(this);
346 - }
347 -
348 - @Override
349 - public AtomicCounterBuilder atomicCounterBuilder() {
350 - return new DefaultAtomicCounterBuilder(inMemoryDatabase, partitionedDatabase);
351 - }
352 -
353 - @Override
354 - public <V> AtomicValueBuilder<V> atomicValueBuilder() {
355 - Supplier<ConsistentMapBuilder<String, byte[]>> mapBuilderSupplier =
356 - () -> this.<String, byte[]>consistentMapBuilder()
357 - .withName("onos-atomic-values")
358 - .withMeteringDisabled()
359 - .withSerializer(Serializer.using(KryoNamespaces.BASIC));
360 - return new DefaultAtomicValueBuilder<>(mapBuilderSupplier);
361 - }
362 -
363 - @Override
364 - public LeaderElectorBuilder leaderElectorBuilder() {
365 - throw new UnsupportedOperationException();
366 - }
367 -
368 - @Override
369 - public List<MapInfo> getMapInfo() {
370 - List<MapInfo> maps = Lists.newArrayList();
371 - maps.addAll(getMapInfo(inMemoryDatabase));
372 - maps.addAll(getMapInfo(partitionedDatabase));
373 - return maps;
374 - }
375 -
376 - private List<MapInfo> getMapInfo(Database database) {
377 - return complete(database.maps())
378 - .stream()
379 - .map(name -> new MapInfo(name, complete(database.mapSize(name))))
380 - .filter(info -> info.size() > 0)
381 - .collect(Collectors.toList());
382 - }
383 -
384 -
385 - @Override
386 - public Map<String, Long> getCounters() {
387 - Map<String, Long> counters = Maps.newHashMap();
388 - counters.putAll(complete(inMemoryDatabase.counters()));
389 - counters.putAll(complete(partitionedDatabase.counters()));
390 - return counters;
391 - }
392 -
393 - @Override
394 - public Map<String, Long> getPartitionedDatabaseCounters() {
395 - Map<String, Long> counters = Maps.newHashMap();
396 - counters.putAll(complete(partitionedDatabase.counters()));
397 - return counters;
398 - }
399 -
400 - @Override
401 - public Map<String, Long> getInMemoryDatabaseCounters() {
402 - Map<String, Long> counters = Maps.newHashMap();
403 - counters.putAll(complete(inMemoryDatabase.counters()));
404 - return counters;
405 - }
406 -
407 - @Override
408 - public Collection<TransactionId> getPendingTransactions() {
409 - return complete(transactionManager.getPendingTransactionIds());
410 - }
411 -
412 - private static <T> T complete(CompletableFuture<T> future) {
413 - try {
414 - return future.get(DATABASE_OPERATION_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
415 - } catch (InterruptedException e) {
416 - Thread.currentThread().interrupt();
417 - throw new ConsistentMapException.Interrupted();
418 - } catch (TimeoutException e) {
419 - throw new ConsistentMapException.Timeout();
420 - } catch (ExecutionException e) {
421 - throw new ConsistentMapException(e.getCause());
422 - }
423 - }
424 -
425 - protected <K, V> DefaultAsyncConsistentMap<K, V> registerMap(DefaultAsyncConsistentMap<K, V> map) {
426 - maps.put(map.name(), map);
427 - if (map.applicationId() != null) {
428 - mapsByApplication.put(map.applicationId(), map);
429 - }
430 - return map;
431 - }
432 -
433 - protected <K, V> void unregisterMap(DefaultAsyncConsistentMap<K, V> map) {
434 - maps.remove(map.name(), map);
435 - if (map.applicationId() != null) {
436 - mapsByApplication.remove(map.applicationId(), map);
437 - }
438 - }
439 -
440 - private class InternalApplicationListener implements ApplicationListener {
441 - @Override
442 - public void event(ApplicationEvent event) {
443 - if (event.type() == APP_UNINSTALLED || event.type() == APP_DEACTIVATED) {
444 - ApplicationId appId = event.subject().id();
445 - List<DefaultAsyncConsistentMap> mapsToRemove;
446 - synchronized (mapsByApplication) {
447 - mapsToRemove = ImmutableList.copyOf(mapsByApplication.get(appId));
448 - }
449 - mapsToRemove.forEach(DatabaseManager.this::unregisterMap);
450 - if (event.type() == APP_UNINSTALLED) {
451 - mapsToRemove.stream().filter(map -> map.purgeOnUninstall()).forEach(map -> map.clear());
452 - }
453 - }
454 - }
455 - }
456 -}
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 -
17 -package org.onosproject.store.primitives.impl;
18 -
19 -import static com.google.common.base.Preconditions.checkState;
20 -
21 -import java.util.List;
22 -import com.google.common.base.Charsets;
23 -import com.google.common.collect.ImmutableList;
24 -import com.google.common.hash.Hashing;
25 -
26 -/**
27 - * Partitioner for mapping map entries to individual database partitions.
28 - * <p>
29 - * By default a md5 hash of the hash key (key or map name) is used to pick a
30 - * partition.
31 - */
32 -public abstract class DatabasePartitioner implements Partitioner<String> {
33 - // Database partitions sorted by their partition name.
34 - protected final List<Database> partitions;
35 -
36 - public DatabasePartitioner(List<Database> partitions) {
37 - checkState(partitions != null && !partitions.isEmpty(), "Partitions cannot be null or empty");
38 - this.partitions = ImmutableList.copyOf(partitions);
39 - }
40 -
41 - protected int hash(String key) {
42 - return Math.abs(Hashing.md5().newHasher().putBytes(key.getBytes(Charsets.UTF_8)).hash().asInt());
43 - }
44 -
45 -}
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 -
17 -package org.onosproject.store.primitives.impl;
18 -
19 -import org.onlab.util.Match;
20 -import org.onosproject.store.service.Versioned;
21 -
22 -import java.util.Collection;
23 -import java.util.Map;
24 -import java.util.Set;
25 -import java.util.concurrent.CompletableFuture;
26 -
27 -/**
28 - * Database proxy.
29 - */
30 -public interface DatabaseProxy<K, V> {
31 -
32 - /**
33 - * Returns a set of all map names.
34 - *
35 - * @return A completable future to be completed with the result once complete.
36 - */
37 - CompletableFuture<Set<String>> maps();
38 -
39 - /**
40 - * Returns a mapping from counter name to next value.
41 - *
42 - * @return A completable future to be completed with the result once complete.
43 - */
44 - CompletableFuture<Map<String, Long>> counters();
45 -
46 - /**
47 - * Returns the number of entries in map.
48 - *
49 - * @param mapName map name
50 - * @return A completable future to be completed with the result once complete.
51 - */
52 - CompletableFuture<Integer> mapSize(String mapName);
53 -
54 - /**
55 - * Checks whether the map is empty.
56 - *
57 - * @param mapName map name
58 - * @return A completable future to be completed with the result once complete.
59 - */
60 - CompletableFuture<Boolean> mapIsEmpty(String mapName);
61 -
62 - /**
63 - * Checks whether the map contains a key.
64 - *
65 - * @param mapName map name
66 - * @param key key to check.
67 - * @return A completable future to be completed with the result once complete.
68 - */
69 - CompletableFuture<Boolean> mapContainsKey(String mapName, K key);
70 -
71 - /**
72 - * Checks whether the map contains a value.
73 - *
74 - * @param mapName map name
75 - * @param value The value to check.
76 - * @return A completable future to be completed with the result once complete.
77 - */
78 - CompletableFuture<Boolean> mapContainsValue(String mapName, V value);
79 -
80 - /**
81 - * Gets a value from the map.
82 - *
83 - * @param mapName map name
84 - * @param key The key to get.
85 - * @return A completable future to be completed with the result once complete.
86 - */
87 - CompletableFuture<Versioned<V>> mapGet(String mapName, K key);
88 -
89 - /**
90 - * Updates the map.
91 - *
92 - * @param mapName map name
93 - * @param key The key to set
94 - * @param valueMatch match for checking existing value
95 - * @param versionMatch match for checking existing version
96 - * @param value new value
97 - * @return A completable future to be completed with the result once complete
98 - */
99 - CompletableFuture<Result<UpdateResult<K, V>>> mapUpdate(
100 - String mapName, K key, Match<V> valueMatch, Match<Long> versionMatch, V value);
101 -
102 - /**
103 - * Clears the map.
104 - *
105 - * @param mapName map name
106 - * @return A completable future to be completed with the result once complete.
107 - */
108 - CompletableFuture<Result<Void>> mapClear(String mapName);
109 -
110 - /**
111 - * Gets a set of keys in the map.
112 - *
113 - * @param mapName map name
114 - * @return A completable future to be completed with the result once complete.
115 - */
116 - CompletableFuture<Set<K>> mapKeySet(String mapName);
117 -
118 - /**
119 - * Gets a collection of values in the map.
120 - *
121 - * @param mapName map name
122 - * @return A completable future to be completed with the result once complete.
123 - */
124 - CompletableFuture<Collection<Versioned<V>>> mapValues(String mapName);
125 -
126 - /**
127 - * Gets a set of entries in the map.
128 - *
129 - * @param mapName map name
130 - * @return A completable future to be completed with the result once complete.
131 - */
132 - CompletableFuture<Set<Map.Entry<K, Versioned<V>>>> mapEntrySet(String mapName);
133 -
134 - /**
135 - * Atomically add the given value to current value of the specified counter.
136 - *
137 - * @param counterName counter name
138 - * @param delta value to add
139 - * @return updated value
140 - */
141 - CompletableFuture<Long> counterAddAndGet(String counterName, long delta);
142 -
143 - /**
144 - * Atomically add the given value to current value of the specified counter.
145 - *
146 - * @param counterName counter name
147 - * @param delta value to add
148 - * @return previous value
149 - */
150 - CompletableFuture<Long> counterGetAndAdd(String counterName, long delta);
151 -
152 -
153 - /**
154 - * Atomically sets the given value to current value of the specified counter.
155 - *
156 - * @param counterName counter name
157 - * @param value value to set
158 - * @return void future
159 - */
160 - CompletableFuture<Void> counterSet(String counterName, long value);
161 -
162 - /**
163 - * Atomically sets the given counter to the specified update value if and only if the current value is equal to the
164 - * expected value.
165 - * @param counterName counter name
166 - * @param expectedValue value to use for equivalence check
167 - * @param update value to set if expected value is current value
168 - * @return true if an update occurred, false otherwise
169 - */
170 - CompletableFuture<Boolean> counterCompareAndSet(String counterName, long expectedValue, long update);
171 -
172 - /**
173 - * Returns the current value of the specified atomic counter.
174 - *
175 - * @param counterName counter name
176 - * @return current value
177 - */
178 - CompletableFuture<Long> counterGet(String counterName);
179 -
180 - /**
181 - * Returns the size of queue.
182 - *
183 - * @param queueName queue name
184 - * @return queue size
185 - */
186 - CompletableFuture<Long> queueSize(String queueName);
187 -
188 - /**
189 - * Inserts an entry into the queue.
190 - *
191 - * @param queueName queue name
192 - * @param entry queue entry
193 - * @return void future
194 - */
195 - CompletableFuture<Void> queuePush(String queueName, byte[] entry);
196 -
197 - /**
198 - * Removes an entry from the queue if the queue is non-empty.
199 - *
200 - * @param queueName queue name
201 - * @return entry future. Can be completed with null if queue is empty
202 - */
203 - CompletableFuture<byte[]> queuePop(String queueName);
204 -
205 - /**
206 - * Returns but does not remove an entry from the queue.
207 - *
208 - * @param queueName queue name
209 - * @return entry. Can be null if queue is empty
210 - */
211 - CompletableFuture<byte[]> queuePeek(String queueName);
212 -
213 - /**
214 - * Prepare and commit the specified transaction.
215 - *
216 - * @param transaction transaction to commit (after preparation)
217 - * @return A completable future to be completed with the result once complete
218 - */
219 - CompletableFuture<CommitResponse> prepareAndCommit(Transaction transaction);
220 -
221 - /**
222 - * Prepare the specified transaction for commit. A successful prepare implies
223 - * all the affected resources are locked thus ensuring no concurrent updates can interfere.
224 - *
225 - * @param transaction transaction to prepare (for commit)
226 - * @return A completable future to be completed with the result once complete. The future is completed
227 - * with true if the transaction is successfully prepared i.e. all pre-conditions are met and
228 - * applicable resources locked.
229 - */
230 - CompletableFuture<Boolean> prepare(Transaction transaction);
231 -
232 - /**
233 - * Commit the specified transaction. A successful commit implies
234 - * all the updates are applied, are now durable and are now visible externally.
235 - *
236 - * @param transaction transaction to commit
237 - * @return A completable future to be completed with the result once complete
238 - */
239 - CompletableFuture<CommitResponse> commit(Transaction transaction);
240 -
241 - /**
242 - * Rollback the specified transaction. A successful rollback implies
243 - * all previously acquired locks for the affected resources are released.
244 - *
245 - * @param transaction transaction to rollback
246 - * @return A completable future to be completed with the result once complete
247 - */
248 - CompletableFuture<Boolean> rollback(Transaction transaction);
249 -}
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 -
17 -package org.onosproject.store.primitives.impl;
18 -
19 -import java.nio.ByteBuffer;
20 -
21 -import org.onlab.util.KryoNamespace;
22 -import org.onlab.util.Match;
23 -import org.onosproject.cluster.NodeId;
24 -import org.onosproject.store.primitives.MapUpdate;
25 -import org.onosproject.store.primitives.TransactionId;
26 -import org.onosproject.store.serializers.KryoNamespaces;
27 -import org.onosproject.store.serializers.KryoSerializer;
28 -import org.onosproject.store.service.Versioned;
29 -
30 -import net.kuujo.copycat.cluster.internal.MemberInfo;
31 -import net.kuujo.copycat.raft.protocol.AppendRequest;
32 -import net.kuujo.copycat.raft.protocol.AppendResponse;
33 -import net.kuujo.copycat.raft.protocol.CommitRequest;
34 -import net.kuujo.copycat.raft.protocol.CommitResponse;
35 -import net.kuujo.copycat.raft.protocol.PollRequest;
36 -import net.kuujo.copycat.raft.protocol.PollResponse;
37 -import net.kuujo.copycat.raft.protocol.QueryRequest;
38 -import net.kuujo.copycat.raft.protocol.QueryResponse;
39 -import net.kuujo.copycat.raft.protocol.ReplicaInfo;
40 -import net.kuujo.copycat.raft.protocol.SyncRequest;
41 -import net.kuujo.copycat.raft.protocol.SyncResponse;
42 -import net.kuujo.copycat.raft.protocol.VoteRequest;
43 -import net.kuujo.copycat.raft.protocol.VoteResponse;
44 -import net.kuujo.copycat.util.serializer.SerializerConfig;
45 -
46 -/**
47 - * Serializer for DatabaseManager's interaction with Copycat.
48 - */
49 -public class DatabaseSerializer extends SerializerConfig {
50 -
51 - private static final KryoNamespace COPYCAT = KryoNamespace.newBuilder()
52 - .nextId(KryoNamespace.FLOATING_ID)
53 - .register(AppendRequest.class)
54 - .register(AppendResponse.class)
55 - .register(SyncRequest.class)
56 - .register(SyncResponse.class)
57 - .register(VoteRequest.class)
58 - .register(VoteResponse.class)
59 - .register(PollRequest.class)
60 - .register(PollResponse.class)
61 - .register(QueryRequest.class)
62 - .register(QueryResponse.class)
63 - .register(CommitRequest.class)
64 - .register(CommitResponse.class)
65 - .register(ReplicaInfo.class)
66 - .register(MemberInfo.class)
67 - .build();
68 -
69 - private static final KryoNamespace ONOS_STORE = KryoNamespace.newBuilder()
70 - .nextId(KryoNamespace.FLOATING_ID)
71 - .register(Versioned.class)
72 - .register(MapUpdate.class)
73 - .register(MapUpdate.Type.class)
74 - .register(Result.class)
75 - .register(UpdateResult.class)
76 - .register(Result.Status.class)
77 - .register(Transaction.class)
78 - .register(Transaction.State.class)
79 - .register(TransactionId.class)
80 - .register(org.onosproject.store.primitives.impl.CommitResponse.class)
81 - .register(Match.class)
82 - .register(NodeId.class)
83 - .build();
84 -
85 - private static final KryoSerializer SERIALIZER = new KryoSerializer() {
86 - @Override
87 - protected void setupKryoPool() {
88 - serializerPool = KryoNamespace.newBuilder()
89 - .register(KryoNamespaces.BASIC)
90 - .register(COPYCAT)
91 - .register(ONOS_STORE)
92 - .build();
93 - }
94 - };
95 -
96 - @Override
97 - public ByteBuffer writeObject(Object object) {
98 - return ByteBuffer.wrap(SERIALIZER.encode(object));
99 - }
100 -
101 - @Override
102 - public <T> T readObject(ByteBuffer buffer) {
103 - return SERIALIZER.decode(buffer);
104 - }
105 -}
...\ 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 -
17 -package org.onosproject.store.primitives.impl;
18 -
19 -import net.kuujo.copycat.state.Command;
20 -import net.kuujo.copycat.state.Initializer;
21 -import net.kuujo.copycat.state.Query;
22 -import net.kuujo.copycat.state.StateContext;
23 -
24 -import org.onlab.util.Match;
25 -import org.onosproject.store.service.Versioned;
26 -
27 -import java.util.Collection;
28 -import java.util.Map;
29 -import java.util.Map.Entry;
30 -import java.util.Set;
31 -
32 -/**
33 - * Database state.
34 - *
35 - */
36 -public interface DatabaseState<K, V> {
37 -
38 - /**
39 - * Initializes the database state.
40 - *
41 - * @param context The map state context.
42 - */
43 - @Initializer
44 - void init(StateContext<DatabaseState<K, V>> context);
45 -
46 - @Query
47 - Set<String> maps();
48 -
49 - @Query
50 - Map<String, Long> counters();
51 -
52 - @Query
53 - int mapSize(String mapName);
54 -
55 - @Query
56 - boolean mapIsEmpty(String mapName);
57 -
58 - @Query
59 - boolean mapContainsKey(String mapName, K key);
60 -
61 - @Query
62 - boolean mapContainsValue(String mapName, V value);
63 -
64 - @Query
65 - Versioned<V> mapGet(String mapName, K key);
66 -
67 - @Command
68 - Result<UpdateResult<K, V>> mapUpdate(String mapName, K key, Match<V> valueMatch, Match<Long> versionMatch, V value);
69 -
70 - @Command
71 - Result<Void> mapClear(String mapName);
72 -
73 - @Query
74 - Set<K> mapKeySet(String mapName);
75 -
76 - @Query
77 - Collection<Versioned<V>> mapValues(String mapName);
78 -
79 - @Query
80 - Set<Entry<K, Versioned<V>>> mapEntrySet(String mapName);
81 -
82 - @Command
83 - Long counterAddAndGet(String counterName, long delta);
84 -
85 - @Command
86 - Boolean counterCompareAndSet(String counterName, long expectedValue, long updateValue);
87 -
88 - @Command
89 - Long counterGetAndAdd(String counterName, long delta);
90 -
91 - @Query
92 - Long queueSize(String queueName);
93 -
94 - @Query
95 - byte[] queuePeek(String queueName);
96 -
97 - @Command
98 - byte[] queuePop(String queueName);
99 -
100 - @Command
101 - void queuePush(String queueName, byte[] entry);
102 -
103 - @Query
104 - Long counterGet(String counterName);
105 -
106 - @Command
107 - void counterSet(String counterName, long value);
108 -
109 - @Command
110 - CommitResponse prepareAndCommit(Transaction transaction);
111 -
112 - @Command
113 - boolean prepare(Transaction transaction);
114 -
115 - @Command
116 - CommitResponse commit(Transaction transaction);
117 -
118 - @Command
119 - boolean rollback(Transaction transaction);
120 -}
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.primitives.impl;
17 -
18 -import org.onosproject.store.service.AsyncAtomicCounter;
19 -import org.onosproject.utils.MeteringAgent;
20 -
21 -import java.util.concurrent.CompletableFuture;
22 -
23 -import static com.google.common.base.Preconditions.checkNotNull;
24 -
25 -/**
26 - * Default implementation for a distributed AsyncAtomicCounter backed by
27 - * partitioned Raft DB.
28 - * <p>
29 - * The initial value will be zero.
30 - */
31 -public class DefaultAsyncAtomicCounter implements AsyncAtomicCounter {
32 -
33 - private final String name;
34 - private final Database database;
35 - private final MeteringAgent monitor;
36 -
37 - private static final String PRIMITIVE_NAME = "atomicCounter";
38 - private static final String INCREMENT_AND_GET = "incrementAndGet";
39 - private static final String GET_AND_INCREMENT = "getAndIncrement";
40 - private static final String GET_AND_ADD = "getAndAdd";
41 - private static final String ADD_AND_GET = "addAndGet";
42 - private static final String GET = "get";
43 - private static final String SET = "set";
44 - private static final String COMPARE_AND_SET = "compareAndSet";
45 -
46 - public DefaultAsyncAtomicCounter(String name,
47 - Database database,
48 - boolean meteringEnabled) {
49 - this.name = checkNotNull(name);
50 - this.database = checkNotNull(database);
51 - this.monitor = new MeteringAgent(PRIMITIVE_NAME, name, meteringEnabled);
52 - }
53 -
54 - @Override
55 - public String name() {
56 - return name;
57 - }
58 -
59 - @Override
60 - public CompletableFuture<Long> incrementAndGet() {
61 - final MeteringAgent.Context timer = monitor.startTimer(INCREMENT_AND_GET);
62 - return addAndGet(1L)
63 - .whenComplete((r, e) -> timer.stop(e));
64 - }
65 -
66 - @Override
67 - public CompletableFuture<Long> get() {
68 - final MeteringAgent.Context timer = monitor.startTimer(GET);
69 - return database.counterGet(name)
70 - .whenComplete((r, e) -> timer.stop(e));
71 - }
72 -
73 - @Override
74 - public CompletableFuture<Long> getAndIncrement() {
75 - final MeteringAgent.Context timer = monitor.startTimer(GET_AND_INCREMENT);
76 - return getAndAdd(1L)
77 - .whenComplete((r, e) -> timer.stop(e));
78 - }
79 -
80 - @Override
81 - public CompletableFuture<Long> getAndAdd(long delta) {
82 - final MeteringAgent.Context timer = monitor.startTimer(GET_AND_ADD);
83 - return database.counterGetAndAdd(name, delta)
84 - .whenComplete((r, e) -> timer.stop(e));
85 - }
86 -
87 - @Override
88 - public CompletableFuture<Long> addAndGet(long delta) {
89 - final MeteringAgent.Context timer = monitor.startTimer(ADD_AND_GET);
90 - return database.counterAddAndGet(name, delta)
91 - .whenComplete((r, e) -> timer.stop(e));
92 - }
93 -
94 - @Override
95 - public CompletableFuture<Void> set(long value) {
96 - final MeteringAgent.Context timer = monitor.startTimer(SET);
97 - return database.counterSet(name, value)
98 - .whenComplete((r, e) -> timer.stop(e));
99 - }
100 -
101 - @Override
102 - public CompletableFuture<Boolean> compareAndSet(long expectedValue, long updateValue) {
103 - final MeteringAgent.Context timer = monitor.startTimer(COMPARE_AND_SET);
104 - return database.counterCompareAndSet(name, expectedValue, updateValue)
105 - .whenComplete((r, e) -> timer.stop(e));
106 - }
107 -}
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 -
17 -package org.onosproject.store.primitives.impl;
18 -
19 -import static com.google.common.base.Preconditions.checkNotNull;
20 -import static org.onosproject.store.primitives.impl.StateMachineUpdate.Target.MAP_UPDATE;
21 -import static org.onosproject.store.primitives.impl.StateMachineUpdate.Target.TX_COMMIT;
22 -import static org.slf4j.LoggerFactory.getLogger;
23 -
24 -import java.util.Collection;
25 -import java.util.Collections;
26 -import java.util.Map;
27 -import java.util.Map.Entry;
28 -import java.util.Objects;
29 -import java.util.Set;
30 -import java.util.concurrent.CompletableFuture;
31 -import java.util.concurrent.CopyOnWriteArraySet;
32 -import java.util.concurrent.atomic.AtomicReference;
33 -import java.util.function.BiFunction;
34 -import java.util.function.Function;
35 -import java.util.function.Predicate;
36 -import java.util.stream.Collectors;
37 -
38 -import org.onlab.util.HexString;
39 -import org.onlab.util.Match;
40 -import org.onlab.util.SharedExecutors;
41 -import org.onlab.util.Tools;
42 -import org.onosproject.core.ApplicationId;
43 -import org.onosproject.store.primitives.TransactionId;
44 -import org.onosproject.store.service.AsyncConsistentMap;
45 -import org.onosproject.store.service.ConsistentMapException;
46 -import org.onosproject.store.service.ConsistentMapException.ConcurrentModification;
47 -import org.onosproject.store.service.MapEvent;
48 -import org.onosproject.store.service.MapEventListener;
49 -import org.onosproject.store.service.MapTransaction;
50 -import org.onosproject.store.service.Serializer;
51 -import org.onosproject.store.service.Versioned;
52 -import org.onosproject.utils.MeteringAgent;
53 -import org.slf4j.Logger;
54 -
55 -import com.google.common.cache.CacheBuilder;
56 -import com.google.common.cache.CacheLoader;
57 -import com.google.common.cache.LoadingCache;
58 -import com.google.common.collect.Maps;
59 -
60 -/**
61 - * AsyncConsistentMap implementation that is backed by a Raft consensus
62 - * based database.
63 - *
64 - * @param <K> type of key.
65 - * @param <V> type of value.
66 - */
67 -public class DefaultAsyncConsistentMap<K, V> implements AsyncConsistentMap<K, V> {
68 -
69 - private final String name;
70 - private final ApplicationId applicationId;
71 - private final Database database;
72 - private final Serializer serializer;
73 - private final boolean readOnly;
74 - private final boolean purgeOnUninstall;
75 -
76 - private static final String PRIMITIVE_NAME = "consistentMap";
77 - private static final String SIZE = "size";
78 - private static final String IS_EMPTY = "isEmpty";
79 - private static final String CONTAINS_KEY = "containsKey";
80 - private static final String CONTAINS_VALUE = "containsValue";
81 - private static final String GET = "get";
82 - private static final String COMPUTE_IF = "computeIf";
83 - private static final String PUT = "put";
84 - private static final String PUT_AND_GET = "putAndGet";
85 - private static final String PUT_IF_ABSENT = "putIfAbsent";
86 - private static final String REMOVE = "remove";
87 - private static final String CLEAR = "clear";
88 - private static final String KEY_SET = "keySet";
89 - private static final String VALUES = "values";
90 - private static final String ENTRY_SET = "entrySet";
91 - private static final String REPLACE = "replace";
92 - private static final String COMPUTE_IF_ABSENT = "computeIfAbsent";
93 -
94 - private final Set<MapEventListener<K, V>> listeners = new CopyOnWriteArraySet<>();
95 -
96 - private final Logger log = getLogger(getClass());
97 - private final MeteringAgent monitor;
98 -
99 - private static final String ERROR_NULL_KEY = "Key cannot be null";
100 - private static final String ERROR_NULL_VALUE = "Null values are not allowed";
101 -
102 - // String representation of serialized byte[] -> original key Object
103 - private final LoadingCache<String, K> keyCache = CacheBuilder.newBuilder()
104 - .softValues()
105 - .build(new CacheLoader<String, K>() {
106 -
107 - @Override
108 - public K load(String key) {
109 - return serializer.decode(HexString.fromHexString(key));
110 - }
111 - });
112 -
113 - protected String sK(K key) {
114 - String s = HexString.toHexString(serializer.encode(key));
115 - keyCache.put(s, key);
116 - return s;
117 - }
118 -
119 - protected K dK(String key) {
120 - return keyCache.getUnchecked(key);
121 - }
122 -
123 - public DefaultAsyncConsistentMap(String name,
124 - ApplicationId applicationId,
125 - Database database,
126 - Serializer serializer,
127 - boolean readOnly,
128 - boolean purgeOnUninstall,
129 - boolean meteringEnabled) {
130 - this.name = checkNotNull(name, "map name cannot be null");
131 - this.applicationId = applicationId;
132 - this.database = checkNotNull(database, "database cannot be null");
133 - this.serializer = checkNotNull(serializer, "serializer cannot be null");
134 - this.readOnly = readOnly;
135 - this.purgeOnUninstall = purgeOnUninstall;
136 - this.database.registerConsumer(update -> {
137 - SharedExecutors.getSingleThreadExecutor().execute(() -> {
138 - if (listeners.isEmpty()) {
139 - return;
140 - }
141 - try {
142 - if (update.target() == MAP_UPDATE) {
143 - Result<UpdateResult<String, byte[]>> result = update.output();
144 - if (result.success() && result.value().mapName().equals(name)) {
145 - MapEvent<K, V> mapEvent = result.value()
146 - .<K, V>map(this::dK,
147 - v -> serializer.decode(Tools.copyOf(v)))
148 - .toMapEvent();
149 - notifyListeners(mapEvent);
150 - }
151 - } else if (update.target() == TX_COMMIT) {
152 - CommitResponse response = update.output();
153 - if (response.success()) {
154 - response.updates().forEach(u -> {
155 - if (u.mapName().equals(name)) {
156 - MapEvent<K, V> mapEvent =
157 - u.<K, V>map(this::dK,
158 - v -> serializer.decode(Tools.copyOf(v)))
159 - .toMapEvent();
160 - notifyListeners(mapEvent);
161 - }
162 - });
163 - }
164 - }
165 - } catch (Exception e) {
166 - log.warn("Error notifying listeners", e);
167 - }
168 - });
169 - });
170 - this.monitor = new MeteringAgent(PRIMITIVE_NAME, name, meteringEnabled);
171 - }
172 -
173 - /**
174 - * Returns this map name.
175 - * @return map name
176 - */
177 - @Override
178 - public String name() {
179 - return name;
180 - }
181 -
182 - /**
183 - * Returns the serializer for map entries.
184 - * @return map entry serializer
185 - */
186 - public Serializer serializer() {
187 - return serializer;
188 - }
189 -
190 - /**
191 - * Returns the applicationId owning this map.
192 - * @return application Id
193 - */
194 - @Override
195 - public ApplicationId applicationId() {
196 - return applicationId;
197 - }
198 -
199 - /**
200 - * Returns whether the map entries should be purged when the application
201 - * owning it is uninstalled.
202 - * @return true is map needs to cleared on app uninstall; false otherwise
203 - */
204 - public boolean purgeOnUninstall() {
205 - return purgeOnUninstall;
206 - }
207 -
208 - @Override
209 - public CompletableFuture<Integer> size() {
210 - final MeteringAgent.Context timer = monitor.startTimer(SIZE);
211 - return database.mapSize(name)
212 - .whenComplete((r, e) -> timer.stop(e));
213 - }
214 -
215 - @Override
216 - public CompletableFuture<Boolean> isEmpty() {
217 - final MeteringAgent.Context timer = monitor.startTimer(IS_EMPTY);
218 - return database.mapIsEmpty(name)
219 - .whenComplete((r, e) -> timer.stop(e));
220 - }
221 -
222 - @Override
223 - public CompletableFuture<Boolean> containsKey(K key) {
224 - checkNotNull(key, ERROR_NULL_KEY);
225 - final MeteringAgent.Context timer = monitor.startTimer(CONTAINS_KEY);
226 - return database.mapContainsKey(name, sK(key))
227 - .whenComplete((r, e) -> timer.stop(e));
228 - }
229 -
230 - @Override
231 - public CompletableFuture<Boolean> containsValue(V value) {
232 - checkNotNull(value, ERROR_NULL_VALUE);
233 - final MeteringAgent.Context timer = monitor.startTimer(CONTAINS_VALUE);
234 - return database.mapContainsValue(name, serializer.encode(value))
235 - .whenComplete((r, e) -> timer.stop(e));
236 - }
237 -
238 - @Override
239 - public CompletableFuture<Versioned<V>> get(K key) {
240 - checkNotNull(key, ERROR_NULL_KEY);
241 - final MeteringAgent.Context timer = monitor.startTimer(GET);
242 - return database.mapGet(name, sK(key))
243 - .whenComplete((r, e) -> timer.stop(e))
244 - .thenApply(v -> v != null ? v.map(serializer::decode) : null);
245 - }
246 -
247 - @Override
248 - public CompletableFuture<Versioned<V>> computeIfAbsent(K key,
249 - Function<? super K, ? extends V> mappingFunction) {
250 - checkNotNull(key, ERROR_NULL_KEY);
251 - checkNotNull(mappingFunction, "Mapping function cannot be null");
252 - final MeteringAgent.Context timer = monitor.startTimer(COMPUTE_IF_ABSENT);
253 - return updateAndGet(key, Match.ifNull(), Match.any(), mappingFunction.apply(key))
254 - .whenComplete((r, e) -> timer.stop(e))
255 - .thenApply(v -> v.newValue());
256 - }
257 -
258 - @Override
259 - public CompletableFuture<Versioned<V>> computeIfPresent(K key,
260 - BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
261 - return computeIf(key, Objects::nonNull, remappingFunction);
262 - }
263 -
264 - @Override
265 - public CompletableFuture<Versioned<V>> compute(K key,
266 - BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
267 - return computeIf(key, v -> true, remappingFunction);
268 - }
269 -
270 - @Override
271 - public CompletableFuture<Versioned<V>> computeIf(K key,
272 - Predicate<? super V> condition,
273 - BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
274 - checkNotNull(key, ERROR_NULL_KEY);
275 - checkNotNull(condition, "predicate function cannot be null");
276 - checkNotNull(remappingFunction, "Remapping function cannot be null");
277 - final MeteringAgent.Context timer = monitor.startTimer(COMPUTE_IF);
278 - return get(key).thenCompose(r1 -> {
279 - V existingValue = r1 == null ? null : r1.value();
280 - // if the condition evaluates to false, return existing value.
281 - if (!condition.test(existingValue)) {
282 - return CompletableFuture.completedFuture(r1);
283 - }
284 -
285 - AtomicReference<V> computedValue = new AtomicReference<>();
286 - // if remappingFunction throws an exception, return the exception.
287 - try {
288 - computedValue.set(remappingFunction.apply(key, existingValue));
289 - } catch (Exception e) {
290 - return Tools.exceptionalFuture(e);
291 - }
292 - if (computedValue.get() == null && r1 == null) {
293 - return CompletableFuture.completedFuture(null);
294 - }
295 - Match<V> valueMatcher = r1 == null ? Match.ifNull() : Match.any();
296 - Match<Long> versionMatcher = r1 == null ? Match.any() : Match.ifValue(r1.version());
297 - return updateAndGet(key, valueMatcher, versionMatcher, computedValue.get())
298 - .whenComplete((r, e) -> timer.stop(e))
299 - .thenApply(v -> {
300 - if (v.updated()) {
301 - return v.newValue();
302 - } else {
303 - throw new ConcurrentModification("Concurrent update to " + name + " detected");
304 - }
305 - });
306 - });
307 - }
308 -
309 - @Override
310 - public CompletableFuture<Versioned<V>> put(K key, V value) {
311 - checkNotNull(key, ERROR_NULL_KEY);
312 - checkNotNull(value, ERROR_NULL_VALUE);
313 - final MeteringAgent.Context timer = monitor.startTimer(PUT);
314 - return updateAndGet(key, Match.any(), Match.any(), value).thenApply(v -> v.oldValue())
315 - .whenComplete((r, e) -> timer.stop(e));
316 - }
317 -
318 - @Override
319 - public CompletableFuture<Versioned<V>> putAndGet(K key, V value) {
320 - checkNotNull(key, ERROR_NULL_KEY);
321 - checkNotNull(value, ERROR_NULL_VALUE);
322 - final MeteringAgent.Context timer = monitor.startTimer(PUT_AND_GET);
323 - return updateAndGet(key, Match.any(), Match.any(), value).thenApply(v -> v.newValue())
324 - .whenComplete((r, e) -> timer.stop(e));
325 - }
326 -
327 - @Override
328 - public CompletableFuture<Versioned<V>> remove(K key) {
329 - checkNotNull(key, ERROR_NULL_KEY);
330 - final MeteringAgent.Context timer = monitor.startTimer(REMOVE);
331 - return updateAndGet(key, Match.any(), Match.any(), null).thenApply(v -> v.oldValue())
332 - .whenComplete((r, e) -> timer.stop(e));
333 - }
334 -
335 - @Override
336 - public CompletableFuture<Void> clear() {
337 - checkIfUnmodifiable();
338 - final MeteringAgent.Context timer = monitor.startTimer(CLEAR);
339 - return database.mapClear(name).thenApply(this::unwrapResult)
340 - .whenComplete((r, e) -> timer.stop(e));
341 - }
342 -
343 - @Override
344 - public CompletableFuture<Set<K>> keySet() {
345 - final MeteringAgent.Context timer = monitor.startTimer(KEY_SET);
346 - return database.mapKeySet(name)
347 - .thenApply(s -> newMappingKeySet(s))
348 - .whenComplete((r, e) -> timer.stop(e));
349 - }
350 -
351 - @Override
352 - public CompletableFuture<Collection<Versioned<V>>> values() {
353 - final MeteringAgent.Context timer = monitor.startTimer(VALUES);
354 - return database.mapValues(name)
355 - .whenComplete((r, e) -> timer.stop(e))
356 - .thenApply(c -> c
357 - .stream()
358 - .map(v -> v.<V>map(serializer::decode))
359 - .collect(Collectors.toList()));
360 - }
361 -
362 - @Override
363 - public CompletableFuture<Set<Entry<K, Versioned<V>>>> entrySet() {
364 - final MeteringAgent.Context timer = monitor.startTimer(ENTRY_SET);
365 - return database.mapEntrySet(name)
366 - .whenComplete((r, e) -> timer.stop(e))
367 - .thenApply(s -> newMappingEntrySet(s));
368 - }
369 -
370 - @Override
371 - public CompletableFuture<Versioned<V>> putIfAbsent(K key, V value) {
372 - checkNotNull(key, ERROR_NULL_KEY);
373 - checkNotNull(value, ERROR_NULL_VALUE);
374 - final MeteringAgent.Context timer = monitor.startTimer(PUT_IF_ABSENT);
375 - return updateAndGet(key, Match.ifNull(), Match.any(), value)
376 - .whenComplete((r, e) -> timer.stop(e))
377 - .thenApply(v -> v.oldValue());
378 - }
379 -
380 - @Override
381 - public CompletableFuture<Boolean> remove(K key, V value) {
382 - checkNotNull(key, ERROR_NULL_KEY);
383 - checkNotNull(value, ERROR_NULL_VALUE);
384 - final MeteringAgent.Context timer = monitor.startTimer(REMOVE);
385 - return updateAndGet(key, Match.ifValue(value), Match.any(), null)
386 - .whenComplete((r, e) -> timer.stop(e))
387 - .thenApply(v -> v.updated());
388 - }
389 -
390 - @Override
391 - public CompletableFuture<Boolean> remove(K key, long version) {
392 - checkNotNull(key, ERROR_NULL_KEY);
393 - final MeteringAgent.Context timer = monitor.startTimer(REMOVE);
394 - return updateAndGet(key, Match.any(), Match.ifValue(version), null)
395 - .whenComplete((r, e) -> timer.stop(e))
396 - .thenApply(v -> v.updated());
397 - }
398 -
399 - @Override
400 - public CompletableFuture<Versioned<V>> replace(K key, V value) {
401 - checkNotNull(key, ERROR_NULL_KEY);
402 - checkNotNull(value, ERROR_NULL_VALUE);
403 - final MeteringAgent.Context timer = monitor.startTimer(REPLACE);
404 - return updateAndGet(key, Match.ifNotNull(), Match.any(), value)
405 - .whenComplete((r, e) -> timer.stop(e))
406 - .thenApply(v -> v.oldValue());
407 - }
408 -
409 - @Override
410 - public CompletableFuture<Boolean> replace(K key, V oldValue, V newValue) {
411 - checkNotNull(key, ERROR_NULL_KEY);
412 - checkNotNull(oldValue, ERROR_NULL_VALUE);
413 - checkNotNull(newValue, ERROR_NULL_VALUE);
414 - final MeteringAgent.Context timer = monitor.startTimer(REPLACE);
415 - return updateAndGet(key, Match.ifValue(oldValue), Match.any(), newValue)
416 - .whenComplete((r, e) -> timer.stop(e))
417 - .thenApply(v -> v.updated());
418 - }
419 -
420 - @Override
421 - public CompletableFuture<Boolean> replace(K key, long oldVersion, V newValue) {
422 - final MeteringAgent.Context timer = monitor.startTimer(REPLACE);
423 - return updateAndGet(key, Match.any(), Match.ifValue(oldVersion), newValue)
424 - .whenComplete((r, e) -> timer.stop(e))
425 - .thenApply(v -> v.updated());
426 - }
427 -
428 - /**
429 - * Pre-update hook for performing required checks/actions before going forward with an update operation.
430 - * @param key map key.
431 - */
432 - protected void beforeUpdate(K key) {
433 - checkIfUnmodifiable();
434 - }
435 -
436 - private Set<K> newMappingKeySet(Set<String> s) {
437 - return new MappingSet<>(s, Collections::unmodifiableSet,
438 - this::sK, this::dK);
439 - }
440 -
441 - private Set<Entry<K, Versioned<V>>> newMappingEntrySet(Set<Entry<String, Versioned<byte[]>>> s) {
442 - return new MappingSet<>(s, Collections::unmodifiableSet,
443 - this::reverseMapRawEntry, this::mapRawEntry);
444 - }
445 -
446 - private Map.Entry<K, Versioned<V>> mapRawEntry(Map.Entry<String, Versioned<byte[]>> e) {
447 - return Maps.immutableEntry(dK(e.getKey()), e.getValue().<V>map(serializer::decode));
448 - }
449 -
450 - private Map.Entry<String, Versioned<byte[]>> reverseMapRawEntry(Map.Entry<K, Versioned<V>> e) {
451 - return Maps.immutableEntry(sK(e.getKey()), e.getValue().map(serializer::encode));
452 - }
453 -
454 - private CompletableFuture<UpdateResult<K, V>> updateAndGet(K key,
455 - Match<V> oldValueMatch,
456 - Match<Long> oldVersionMatch,
457 - V value) {
458 - beforeUpdate(key);
459 - return database.mapUpdate(name,
460 - sK(key),
461 - oldValueMatch.map(serializer::encode),
462 - oldVersionMatch,
463 - value == null ? null : serializer.encode(value))
464 - .thenApply(this::unwrapResult)
465 - .thenApply(r -> r.<K, V>map(this::dK, serializer::decode));
466 - }
467 -
468 - private <T> T unwrapResult(Result<T> result) {
469 - if (result.status() == Result.Status.LOCKED) {
470 - throw new ConsistentMapException.ConcurrentModification();
471 - } else if (result.success()) {
472 - return result.value();
473 - } else {
474 - throw new IllegalStateException("Must not be here");
475 - }
476 - }
477 -
478 - private void checkIfUnmodifiable() {
479 - if (readOnly) {
480 - throw new UnsupportedOperationException();
481 - }
482 - }
483 -
484 - @Override
485 - public CompletableFuture<Void> addListener(MapEventListener<K, V> listener) {
486 - listeners.add(listener);
487 - return CompletableFuture.completedFuture(null);
488 - }
489 -
490 - @Override
491 - public CompletableFuture<Void> removeListener(MapEventListener<K, V> listener) {
492 - listeners.remove(listener);
493 - return CompletableFuture.completedFuture(null);
494 - }
495 -
496 - @Override
497 - public CompletableFuture<Boolean> prepare(MapTransaction<K, V> transaction) {
498 - return Tools.exceptionalFuture(new UnsupportedOperationException());
499 - }
500 -
501 - @Override
502 - public CompletableFuture<Void> commit(TransactionId transactionId) {
503 - return Tools.exceptionalFuture(new UnsupportedOperationException());
504 - }
505 -
506 - @Override
507 - public CompletableFuture<Void> rollback(TransactionId transactionId) {
508 - return Tools.exceptionalFuture(new UnsupportedOperationException());
509 - }
510 -
511 - protected void notifyListeners(MapEvent<K, V> event) {
512 - if (event == null) {
513 - return;
514 - }
515 - listeners.forEach(listener -> {
516 - try {
517 - listener.event(event);
518 - } catch (Exception e) {
519 - log.warn("Failure notifying listener about {}", event, e);
520 - }
521 - });
522 - }
523 -}
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.primitives.impl;
17 -
18 -import org.onosproject.store.service.AsyncAtomicCounter;
19 -import org.onosproject.store.service.AtomicCounterBuilder;
20 -
21 -import static com.google.common.base.Preconditions.checkNotNull;
22 -
23 -/**
24 - * Default implementation of AtomicCounterBuilder.
25 - */
26 -public class DefaultAtomicCounterBuilder extends AtomicCounterBuilder {
27 -
28 - private final Database partitionedDatabase;
29 - private final Database inMemoryDatabase;
30 -
31 - public DefaultAtomicCounterBuilder(Database inMemoryDatabase, Database partitionedDatabase) {
32 - this.inMemoryDatabase = inMemoryDatabase;
33 - this.partitionedDatabase = partitionedDatabase;
34 - }
35 -
36 - @Override
37 - public AsyncAtomicCounter build() {
38 - Database database = partitionsDisabled() ? inMemoryDatabase : partitionedDatabase;
39 - return new DefaultAsyncAtomicCounter(checkNotNull(name()), database, meteringEnabled());
40 - }
41 -}
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.primitives.impl;
17 -
18 -import org.onosproject.store.service.AsyncConsistentMap;
19 -import org.onosproject.store.service.ConsistentMap;
20 -import org.onosproject.store.service.ConsistentMapBuilder;
21 -
22 -import static com.google.common.base.Preconditions.checkState;
23 -
24 -/**
25 - * Default Consistent Map builder.
26 - *
27 - * @param <K> type for map key
28 - * @param <V> type for map value
29 - */
30 -public class DefaultConsistentMapBuilder<K, V> extends ConsistentMapBuilder<K, V> {
31 -
32 - private final DatabaseManager manager;
33 -
34 - public DefaultConsistentMapBuilder(DatabaseManager manager) {
35 - this.manager = manager;
36 - }
37 -
38 - private void validateInputs() {
39 - checkState(name() != null, "name must be specified");
40 - checkState(serializer() != null, "serializer must be specified");
41 - if (purgeOnUninstall()) {
42 - checkState(applicationId() != null, "ApplicationId must be specified when purgeOnUninstall is enabled");
43 - }
44 - }
45 -
46 - @Override
47 - public ConsistentMap<K, V> build() {
48 - return buildAndRegisterMap().asConsistentMap();
49 - }
50 -
51 - @Override
52 - public AsyncConsistentMap<K, V> buildAsyncMap() {
53 - return buildAndRegisterMap();
54 - }
55 -
56 - private DefaultAsyncConsistentMap<K, V> buildAndRegisterMap() {
57 - validateInputs();
58 - Database database = partitionsDisabled() ? manager.inMemoryDatabase : manager.partitionedDatabase;
59 - if (relaxedReadConsistency()) {
60 - return manager.registerMap(
61 - new AsyncCachingConsistentMap<>(name(),
62 - applicationId(),
63 - database,
64 - serializer(),
65 - readOnly(),
66 - purgeOnUninstall(),
67 - meteringEnabled()));
68 - } else {
69 - return manager.registerMap(
70 - new DefaultAsyncConsistentMap<>(name(),
71 - applicationId(),
72 - database,
73 - serializer(),
74 - readOnly(),
75 - purgeOnUninstall(),
76 - meteringEnabled()));
77 - }
78 - }
79 -}
...\ 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 -
17 -package org.onosproject.store.primitives.impl;
18 -
19 -import com.google.common.collect.Sets;
20 -
21 -import net.kuujo.copycat.resource.internal.AbstractResource;
22 -import net.kuujo.copycat.resource.internal.ResourceManager;
23 -import net.kuujo.copycat.state.StateMachine;
24 -import net.kuujo.copycat.state.internal.DefaultStateMachine;
25 -import net.kuujo.copycat.util.concurrent.Futures;
26 -import net.kuujo.copycat.util.function.TriConsumer;
27 -
28 -import org.onlab.util.Match;
29 -import org.onosproject.store.service.Versioned;
30 -
31 -import java.util.Collection;
32 -import java.util.Map;
33 -import java.util.Set;
34 -import java.util.concurrent.CompletableFuture;
35 -import java.util.function.Consumer;
36 -import java.util.function.Supplier;
37 -
38 -/**
39 - * Default database.
40 - */
41 -public class DefaultDatabase extends AbstractResource<Database> implements Database {
42 - private final StateMachine<DatabaseState<String, byte[]>> stateMachine;
43 - private DatabaseProxy<String, byte[]> proxy;
44 - private final Set<Consumer<StateMachineUpdate>> consumers = Sets.newCopyOnWriteArraySet();
45 - private final TriConsumer<String, Object, Object> watcher = new InternalStateMachineWatcher();
46 -
47 - @SuppressWarnings({"unchecked", "rawtypes"})
48 - public DefaultDatabase(ResourceManager context) {
49 - super(context);
50 - this.stateMachine = new DefaultStateMachine(context,
51 - DatabaseState.class,
52 - DefaultDatabaseState.class,
53 - DefaultDatabase.class.getClassLoader());
54 - this.stateMachine.addStartupTask(() -> {
55 - stateMachine.registerWatcher(watcher);
56 - return CompletableFuture.completedFuture(null);
57 - });
58 - this.stateMachine.addShutdownTask(() -> {
59 - stateMachine.unregisterWatcher(watcher);
60 - return CompletableFuture.completedFuture(null);
61 - });
62 - }
63 -
64 - /**
65 - * If the database is closed, returning a failed CompletableFuture. Otherwise, calls the given supplier to
66 - * return the completed future result.
67 - *
68 - * @param supplier The supplier to call if the database is open.
69 - * @param <T> The future result type.
70 - * @return A completable future that if this database is closed is immediately failed.
71 - */
72 - protected <T> CompletableFuture<T> checkOpen(Supplier<CompletableFuture<T>> supplier) {
73 - if (proxy == null) {
74 - return Futures.exceptionalFuture(new IllegalStateException("Database closed"));
75 - }
76 - return supplier.get();
77 - }
78 -
79 - @Override
80 - public CompletableFuture<Set<String>> maps() {
81 - return checkOpen(() -> proxy.maps());
82 - }
83 -
84 - @Override
85 - public CompletableFuture<Map<String, Long>> counters() {
86 - return checkOpen(() -> proxy.counters());
87 - }
88 -
89 - @Override
90 - public CompletableFuture<Integer> mapSize(String mapName) {
91 - return checkOpen(() -> proxy.mapSize(mapName));
92 - }
93 -
94 - @Override
95 - public CompletableFuture<Boolean> mapIsEmpty(String mapName) {
96 - return checkOpen(() -> proxy.mapIsEmpty(mapName));
97 - }
98 -
99 - @Override
100 - public CompletableFuture<Boolean> mapContainsKey(String mapName, String key) {
101 - return checkOpen(() -> proxy.mapContainsKey(mapName, key));
102 - }
103 -
104 - @Override
105 - public CompletableFuture<Boolean> mapContainsValue(String mapName, byte[] value) {
106 - return checkOpen(() -> proxy.mapContainsValue(mapName, value));
107 - }
108 -
109 - @Override
110 - public CompletableFuture<Versioned<byte[]>> mapGet(String mapName, String key) {
111 - return checkOpen(() -> proxy.mapGet(mapName, key));
112 - }
113 -
114 - @Override
115 - public CompletableFuture<Result<UpdateResult<String, byte[]>>> mapUpdate(
116 - String mapName, String key, Match<byte[]> valueMatch, Match<Long> versionMatch, byte[] value) {
117 - return checkOpen(() -> proxy.mapUpdate(mapName, key, valueMatch, versionMatch, value));
118 - }
119 -
120 - @Override
121 - public CompletableFuture<Result<Void>> mapClear(String mapName) {
122 - return checkOpen(() -> proxy.mapClear(mapName));
123 - }
124 -
125 - @Override
126 - public CompletableFuture<Set<String>> mapKeySet(String mapName) {
127 - return checkOpen(() -> proxy.mapKeySet(mapName));
128 - }
129 -
130 - @Override
131 - public CompletableFuture<Collection<Versioned<byte[]>>> mapValues(String mapName) {
132 - return checkOpen(() -> proxy.mapValues(mapName));
133 - }
134 -
135 - @Override
136 - public CompletableFuture<Set<Map.Entry<String, Versioned<byte[]>>>> mapEntrySet(String mapName) {
137 - return checkOpen(() -> proxy.mapEntrySet(mapName));
138 - }
139 -
140 - @Override
141 - public CompletableFuture<Long> counterGet(String counterName) {
142 - return checkOpen(() -> proxy.counterGet(counterName));
143 - }
144 -
145 - @Override
146 - public CompletableFuture<Long> counterAddAndGet(String counterName, long delta) {
147 - return checkOpen(() -> proxy.counterAddAndGet(counterName, delta));
148 - }
149 -
150 - @Override
151 - public CompletableFuture<Long> counterGetAndAdd(String counterName, long delta) {
152 - return checkOpen(() -> proxy.counterGetAndAdd(counterName, delta));
153 - }
154 -
155 - @Override
156 - public CompletableFuture<Void> counterSet(String counterName, long value) {
157 - return checkOpen(() -> proxy.counterSet(counterName, value));
158 - }
159 -
160 - @Override
161 - public CompletableFuture<Boolean> counterCompareAndSet(String counterName, long expectedValue, long update) {
162 - return checkOpen(() -> proxy.counterCompareAndSet(counterName, expectedValue, update));
163 - }
164 -
165 - @Override
166 - public CompletableFuture<Long> queueSize(String queueName) {
167 - return checkOpen(() -> proxy.queueSize(queueName));
168 - }
169 -
170 - @Override
171 - public CompletableFuture<Void> queuePush(String queueName, byte[] entry) {
172 - return checkOpen(() -> proxy.queuePush(queueName, entry));
173 - }
174 -
175 - @Override
176 - public CompletableFuture<byte[]> queuePop(String queueName) {
177 - return checkOpen(() -> proxy.queuePop(queueName));
178 - }
179 -
180 - @Override
181 - public CompletableFuture<byte[]> queuePeek(String queueName) {
182 - return checkOpen(() -> proxy.queuePeek(queueName));
183 - }
184 -
185 - @Override
186 - public CompletableFuture<CommitResponse> prepareAndCommit(Transaction transaction) {
187 - return checkOpen(() -> proxy.prepareAndCommit(transaction));
188 - }
189 -
190 - @Override
191 - public CompletableFuture<Boolean> prepare(Transaction transaction) {
192 - return checkOpen(() -> proxy.prepare(transaction));
193 - }
194 -
195 - @Override
196 - public CompletableFuture<CommitResponse> commit(Transaction transaction) {
197 - return checkOpen(() -> proxy.commit(transaction));
198 - }
199 -
200 - @Override
201 - public CompletableFuture<Boolean> rollback(Transaction transaction) {
202 - return checkOpen(() -> proxy.rollback(transaction));
203 - }
204 -
205 - @Override
206 - @SuppressWarnings("unchecked")
207 - public synchronized CompletableFuture<Database> open() {
208 - return runStartupTasks()
209 - .thenCompose(v -> stateMachine.open())
210 - .thenRun(() -> {
211 - this.proxy = stateMachine.createProxy(DatabaseProxy.class, this.getClass().getClassLoader());
212 - })
213 - .thenApply(v -> null);
214 - }
215 -
216 - @Override
217 - public synchronized CompletableFuture<Void> close() {
218 - proxy = null;
219 - return stateMachine.close()
220 - .thenCompose(v -> runShutdownTasks());
221 - }
222 -
223 - @Override
224 - public int hashCode() {
225 - return name().hashCode();
226 - }
227 -
228 - @Override
229 - public boolean equals(Object other) {
230 - if (other instanceof Database) {
231 - return name().equals(((Database) other).name());
232 - }
233 - return false;
234 - }
235 -
236 - @Override
237 - public void registerConsumer(Consumer<StateMachineUpdate> consumer) {
238 - consumers.add(consumer);
239 - }
240 -
241 - @Override
242 - public void unregisterConsumer(Consumer<StateMachineUpdate> consumer) {
243 - consumers.remove(consumer);
244 - }
245 -
246 - private class InternalStateMachineWatcher implements TriConsumer<String, Object, Object> {
247 - @Override
248 - public void accept(String name, Object input, Object output) {
249 - StateMachineUpdate update = new StateMachineUpdate(name, input, output);
250 - consumers.forEach(consumer -> consumer.accept(update));
251 - }
252 - }
253 -}
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 -
17 -package org.onosproject.store.primitives.impl;
18 -
19 -import com.google.common.base.Objects;
20 -import com.google.common.collect.ImmutableList;
21 -import com.google.common.collect.ImmutableSet;
22 -import com.google.common.collect.Lists;
23 -import com.google.common.collect.Maps;
24 -
25 -import net.kuujo.copycat.state.Initializer;
26 -import net.kuujo.copycat.state.StateContext;
27 -
28 -import org.onlab.util.Match;
29 -import org.onosproject.store.primitives.MapUpdate;
30 -import org.onosproject.store.primitives.TransactionId;
31 -import org.onosproject.store.service.Versioned;
32 -
33 -import java.util.Arrays;
34 -import java.util.Collection;
35 -import java.util.LinkedList;
36 -import java.util.Map;
37 -import java.util.Map.Entry;
38 -import java.util.Queue;
39 -import java.util.Set;
40 -import java.util.concurrent.atomic.AtomicLong;
41 -import java.util.stream.Collectors;
42 -
43 -/**
44 - * Default database state.
45 - */
46 -public class DefaultDatabaseState implements DatabaseState<String, byte[]> {
47 - private Long nextVersion;
48 - private Map<String, AtomicLong> counters;
49 - private Map<String, Map<String, Versioned<byte[]>>> maps;
50 - private Map<String, Queue<byte[]>> queues;
51 -
52 - /**
53 - * This locks map has a structure similar to the "tables" map above and
54 - * holds all the provisional updates made during a transaction's prepare phase.
55 - * The entry value is represented as the tuple: (transactionId, newValue)
56 - * If newValue == null that signifies this update is attempting to
57 - * delete the existing value.
58 - * This map also serves as a lock on the entries that are being updated.
59 - * The presence of a entry in this map indicates that element is
60 - * participating in a transaction and is currently locked for updates.
61 - */
62 - private Map<String, Map<String, Update>> locks;
63 -
64 - @Initializer
65 - @Override
66 - public void init(StateContext<DatabaseState<String, byte[]>> context) {
67 - counters = context.get("counters");
68 - if (counters == null) {
69 - counters = Maps.newConcurrentMap();
70 - context.put("counters", counters);
71 - }
72 - maps = context.get("maps");
73 - if (maps == null) {
74 - maps = Maps.newConcurrentMap();
75 - context.put("maps", maps);
76 - }
77 - locks = context.get("locks");
78 - if (locks == null) {
79 - locks = Maps.newConcurrentMap();
80 - context.put("locks", locks);
81 - }
82 - queues = context.get("queues");
83 - if (queues == null) {
84 - queues = Maps.newConcurrentMap();
85 - context.put("queues", queues);
86 - }
87 - nextVersion = context.get("nextVersion");
88 - if (nextVersion == null) {
89 - nextVersion = 0L;
90 - context.put("nextVersion", nextVersion);
91 - }
92 - }
93 -
94 - @Override
95 - public Set<String> maps() {
96 - return ImmutableSet.copyOf(maps.keySet());
97 - }
98 -
99 - @Override
100 - public Map<String, Long> counters() {
101 - Map<String, Long> counterMap = Maps.newHashMap();
102 - counters.forEach((k, v) -> counterMap.put(k, v.get()));
103 - return counterMap;
104 - }
105 -
106 - @Override
107 - public int mapSize(String mapName) {
108 - return getMap(mapName).size();
109 - }
110 -
111 - @Override
112 - public boolean mapIsEmpty(String mapName) {
113 - return getMap(mapName).isEmpty();
114 - }
115 -
116 - @Override
117 - public boolean mapContainsKey(String mapName, String key) {
118 - return getMap(mapName).containsKey(key);
119 - }
120 -
121 - @Override
122 - public boolean mapContainsValue(String mapName, byte[] value) {
123 - return getMap(mapName).values().stream().anyMatch(v -> Arrays.equals(v.value(), value));
124 - }
125 -
126 - @Override
127 - public Versioned<byte[]> mapGet(String mapName, String key) {
128 - return getMap(mapName).get(key);
129 - }
130 -
131 -
132 - @Override
133 - public Result<UpdateResult<String, byte[]>> mapUpdate(
134 - String mapName,
135 - String key,
136 - Match<byte[]> valueMatch,
137 - Match<Long> versionMatch,
138 - byte[] value) {
139 - if (isLockedForUpdates(mapName, key)) {
140 - return Result.locked();
141 - }
142 - Versioned<byte[]> currentValue = getMap(mapName).get(key);
143 - if (!valueMatch.matches(currentValue == null ? null : currentValue.value()) ||
144 - !versionMatch.matches(currentValue == null ? null : currentValue.version())) {
145 - return Result.ok(new UpdateResult<>(false, mapName, key, currentValue, currentValue));
146 - } else {
147 - if (value == null) {
148 - if (currentValue == null) {
149 - return Result.ok(new UpdateResult<>(false, mapName, key, null, null));
150 - } else {
151 - getMap(mapName).remove(key);
152 - return Result.ok(new UpdateResult<>(true, mapName, key, currentValue, null));
153 - }
154 - }
155 - Versioned<byte[]> newValue = new Versioned<>(value, ++nextVersion);
156 - getMap(mapName).put(key, newValue);
157 - return Result.ok(new UpdateResult<>(true, mapName, key, currentValue, newValue));
158 - }
159 - }
160 -
161 - @Override
162 - public Result<Void> mapClear(String mapName) {
163 - if (areTransactionsInProgress(mapName)) {
164 - return Result.locked();
165 - }
166 - getMap(mapName).clear();
167 - return Result.ok(null);
168 - }
169 -
170 - @Override
171 - public Set<String> mapKeySet(String mapName) {
172 - return ImmutableSet.copyOf(getMap(mapName).keySet());
173 - }
174 -
175 - @Override
176 - public Collection<Versioned<byte[]>> mapValues(String mapName) {
177 - return ImmutableList.copyOf(getMap(mapName).values());
178 - }
179 -
180 - @Override
181 - public Set<Entry<String, Versioned<byte[]>>> mapEntrySet(String mapName) {
182 - return ImmutableSet.copyOf(getMap(mapName)
183 - .entrySet()
184 - .stream()
185 - .map(entry -> Maps.immutableEntry(entry.getKey(), entry.getValue()))
186 - .collect(Collectors.toSet()));
187 - }
188 -
189 - @Override
190 - public Long counterAddAndGet(String counterName, long delta) {
191 - return getCounter(counterName).addAndGet(delta);
192 - }
193 -
194 - @Override
195 - public Long counterGetAndAdd(String counterName, long delta) {
196 - return getCounter(counterName).getAndAdd(delta);
197 - }
198 -
199 - @Override
200 - public Boolean counterCompareAndSet(String counterName, long expectedValue, long updateValue) {
201 - return getCounter(counterName).compareAndSet(expectedValue, updateValue);
202 - }
203 -
204 - @Override
205 - public Long counterGet(String counterName) {
206 - return getCounter(counterName).get();
207 - }
208 -
209 - @Override
210 - public void counterSet(String counterName, long value) {
211 - getCounter(counterName).set(value);
212 - }
213 -
214 - @Override
215 - public Long queueSize(String queueName) {
216 - return Long.valueOf(getQueue(queueName).size());
217 - }
218 -
219 - @Override
220 - public byte[] queuePeek(String queueName) {
221 - return getQueue(queueName).peek();
222 - }
223 -
224 - @Override
225 - public byte[] queuePop(String queueName) {
226 - return getQueue(queueName).poll();
227 - }
228 -
229 - @Override
230 - public void queuePush(String queueName, byte[] entry) {
231 - getQueue(queueName).offer(entry);
232 - }
233 -
234 - @Override
235 - public CommitResponse prepareAndCommit(Transaction transaction) {
236 - if (prepare(transaction)) {
237 - return commit(transaction);
238 - }
239 - return CommitResponse.failure();
240 - }
241 -
242 - @Override
243 - public boolean prepare(Transaction transaction) {
244 - if (transaction.updates().stream().anyMatch(update ->
245 - isLockedByAnotherTransaction(update.mapName(),
246 - update.key(),
247 - transaction.id()))) {
248 - return false;
249 - }
250 -
251 - if (transaction.updates().stream().allMatch(this::isUpdatePossible)) {
252 - transaction.updates().forEach(update -> doProvisionalUpdate(update, transaction.id()));
253 - return true;
254 - }
255 - return false;
256 - }
257 -
258 - @Override
259 - public CommitResponse commit(Transaction transaction) {
260 - return CommitResponse.success(Lists.transform(transaction.updates(),
261 - update -> commitProvisionalUpdate(update, transaction.id())));
262 - }
263 -
264 - @Override
265 - public boolean rollback(Transaction transaction) {
266 - transaction.updates().forEach(update -> undoProvisionalUpdate(update, transaction.id()));
267 - return true;
268 - }
269 -
270 - private Map<String, Versioned<byte[]>> getMap(String mapName) {
271 - return maps.computeIfAbsent(mapName, name -> Maps.newConcurrentMap());
272 - }
273 -
274 - private Map<String, Update> getLockMap(String mapName) {
275 - return locks.computeIfAbsent(mapName, name -> Maps.newConcurrentMap());
276 - }
277 -
278 - private AtomicLong getCounter(String counterName) {
279 - return counters.computeIfAbsent(counterName, name -> new AtomicLong(0));
280 - }
281 -
282 - private Queue<byte[]> getQueue(String queueName) {
283 - return queues.computeIfAbsent(queueName, name -> new LinkedList<>());
284 - }
285 -
286 - private boolean isUpdatePossible(MapUpdate<String, byte[]> update) {
287 - Versioned<byte[]> existingEntry = mapGet(update.mapName(), update.key());
288 - switch (update.type()) {
289 - case PUT:
290 - case REMOVE:
291 - return true;
292 - case PUT_IF_ABSENT:
293 - return existingEntry == null;
294 - case PUT_IF_VERSION_MATCH:
295 - return existingEntry != null && existingEntry.version() == update.currentVersion();
296 - case PUT_IF_VALUE_MATCH:
297 - return existingEntry != null && Arrays.equals(existingEntry.value(), update.currentValue());
298 - case REMOVE_IF_VERSION_MATCH:
299 - return existingEntry == null || existingEntry.version() == update.currentVersion();
300 - case REMOVE_IF_VALUE_MATCH:
301 - return existingEntry == null || Arrays.equals(existingEntry.value(), update.currentValue());
302 - default:
303 - throw new IllegalStateException("Unsupported type: " + update.type());
304 - }
305 - }
306 -
307 - private void doProvisionalUpdate(MapUpdate<String, byte[]> update, TransactionId transactionId) {
308 - Map<String, Update> lockMap = getLockMap(update.mapName());
309 - switch (update.type()) {
310 - case PUT:
311 - case PUT_IF_ABSENT:
312 - case PUT_IF_VERSION_MATCH:
313 - case PUT_IF_VALUE_MATCH:
314 - lockMap.put(update.key(), new Update(transactionId, update.value()));
315 - break;
316 - case REMOVE:
317 - case REMOVE_IF_VERSION_MATCH:
318 - case REMOVE_IF_VALUE_MATCH:
319 - lockMap.put(update.key(), new Update(transactionId, null));
320 - break;
321 - default:
322 - throw new IllegalStateException("Unsupported type: " + update.type());
323 - }
324 - }
325 -
326 - private UpdateResult<String, byte[]> commitProvisionalUpdate(
327 - MapUpdate<String, byte[]> update, TransactionId transactionId) {
328 - String mapName = update.mapName();
329 - String key = update.key();
330 - Update provisionalUpdate = getLockMap(mapName).get(key);
331 - if (Objects.equal(transactionId, provisionalUpdate.transactionId())) {
332 - getLockMap(mapName).remove(key);
333 - } else {
334 - throw new IllegalStateException("Invalid transaction Id");
335 - }
336 - return mapUpdate(mapName, key, Match.any(), Match.any(), provisionalUpdate.value()).value();
337 - }
338 -
339 - private void undoProvisionalUpdate(MapUpdate<String, byte[]> update, TransactionId transactionId) {
340 - String mapName = update.mapName();
341 - String key = update.key();
342 - Update provisionalUpdate = getLockMap(mapName).get(key);
343 - if (provisionalUpdate == null) {
344 - return;
345 - }
346 - if (Objects.equal(transactionId, provisionalUpdate.transactionId())) {
347 - getLockMap(mapName).remove(key);
348 - }
349 - }
350 -
351 - private boolean isLockedByAnotherTransaction(String mapName, String key, TransactionId transactionId) {
352 - Update update = getLockMap(mapName).get(key);
353 - return update != null && !Objects.equal(transactionId, update.transactionId());
354 - }
355 -
356 - private boolean isLockedForUpdates(String mapName, String key) {
357 - return getLockMap(mapName).containsKey(key);
358 - }
359 -
360 - private boolean areTransactionsInProgress(String mapName) {
361 - return !getLockMap(mapName).isEmpty();
362 - }
363 -
364 - private class Update {
365 - private final TransactionId transactionId;
366 - private final byte[] value;
367 -
368 - public Update(TransactionId txId, byte[] value) {
369 - this.transactionId = txId;
370 - this.value = value;
371 - }
372 -
373 - public TransactionId transactionId() {
374 - return this.transactionId;
375 - }
376 -
377 - public byte[] value() {
378 - return this.value;
379 - }
380 - }
381 -}
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.primitives.impl;
17 -
18 -import com.google.common.collect.Sets;
19 -import com.google.common.util.concurrent.Futures;
20 -
21 -import org.onlab.util.SharedExecutors;
22 -import org.onosproject.store.service.DistributedPrimitive;
23 -import org.onosproject.store.service.DistributedQueue;
24 -import org.onosproject.store.service.Serializer;
25 -import org.onosproject.utils.MeteringAgent;
26 -
27 -import java.util.List;
28 -import java.util.Set;
29 -import java.util.concurrent.CompletableFuture;
30 -
31 -import static com.google.common.base.Preconditions.checkNotNull;
32 -import static org.onosproject.store.primitives.impl.StateMachineUpdate.Target.QUEUE_PUSH;
33 -
34 -/**
35 - * DistributedQueue implementation that provides FIFO ordering semantics.
36 - *
37 - * @param <E> queue entry type
38 - */
39 -public class DefaultDistributedQueue<E> implements DistributedQueue<E> {
40 -
41 - private final String name;
42 - private final Database database;
43 - private final Serializer serializer;
44 - private final Set<CompletableFuture<E>> pendingFutures = Sets.newIdentityHashSet();
45 -
46 - private static final String PRIMITIVE_NAME = "distributedQueue";
47 - private static final String SIZE = "size";
48 - private static final String PUSH = "push";
49 - private static final String POP = "pop";
50 - private static final String PEEK = "peek";
51 -
52 - private static final String ERROR_NULL_ENTRY = "Null entries are not allowed";
53 - private final MeteringAgent monitor;
54 -
55 - public DefaultDistributedQueue(String name,
56 - Database database,
57 - Serializer serializer,
58 - boolean meteringEnabled) {
59 - this.name = checkNotNull(name, "queue name cannot be null");
60 - this.database = checkNotNull(database, "database cannot be null");
61 - this.serializer = checkNotNull(serializer, "serializer cannot be null");
62 - this.monitor = new MeteringAgent(PRIMITIVE_NAME, name, meteringEnabled);
63 - this.database.registerConsumer(update -> {
64 - SharedExecutors.getSingleThreadExecutor().execute(() -> {
65 - if (update.target() == QUEUE_PUSH) {
66 - List<Object> input = update.input();
67 - String queueName = (String) input.get(0);
68 - if (queueName.equals(name)) {
69 - tryPoll();
70 - }
71 - }
72 - });
73 - });
74 - }
75 -
76 - @Override
77 - public long size() {
78 - final MeteringAgent.Context timer = monitor.startTimer(SIZE);
79 - return Futures.getUnchecked(database.queueSize(name).whenComplete((r, e) -> timer.stop(e)));
80 - }
81 -
82 - @Override
83 - public void push(E entry) {
84 - checkNotNull(entry, ERROR_NULL_ENTRY);
85 - final MeteringAgent.Context timer = monitor.startTimer(PUSH);
86 - Futures.getUnchecked(database.queuePush(name, serializer.encode(entry))
87 - .whenComplete((r, e) -> timer.stop(e)));
88 - }
89 -
90 - @Override
91 - public CompletableFuture<E> pop() {
92 - final MeteringAgent.Context timer = monitor.startTimer(POP);
93 - return database.queuePop(name)
94 - .whenComplete((r, e) -> timer.stop(e))
95 - .thenCompose(v -> {
96 - if (v != null) {
97 - return CompletableFuture.<E>completedFuture(serializer.decode(v));
98 - }
99 - CompletableFuture<E> newPendingFuture = new CompletableFuture<>();
100 - pendingFutures.add(newPendingFuture);
101 - return newPendingFuture;
102 - });
103 -
104 - }
105 -
106 - @Override
107 - public E peek() {
108 - final MeteringAgent.Context timer = monitor.startTimer(PEEK);
109 - return Futures.getUnchecked(database.queuePeek(name)
110 - .thenApply(v -> v != null ? serializer.<E>decode(v) : null)
111 - .whenComplete((r, e) -> timer.stop(e)));
112 - }
113 -
114 - @Override
115 - public String name() {
116 - return name;
117 - }
118 -
119 - @Override
120 - public DistributedPrimitive.Type primitiveType() {
121 - return DistributedPrimitive.Type.QUEUE;
122 - }
123 -
124 - protected void tryPoll() {
125 - Set<CompletableFuture<E>> completedFutures = Sets.newHashSet();
126 - for (CompletableFuture<E> future : pendingFutures) {
127 - E entry = Futures.getUnchecked(database.queuePop(name)
128 - .thenApply(v -> v != null ? serializer.decode(v) : null));
129 - if (entry != null) {
130 - future.complete(entry);
131 - completedFutures.add(future);
132 - } else {
133 - break;
134 - }
135 - }
136 - pendingFutures.removeAll(completedFutures);
137 - }
138 -}
...\ 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.primitives.impl;
17 -
18 -import org.onosproject.store.service.DistributedQueue;
19 -import org.onosproject.store.service.DistributedQueueBuilder;
20 -import org.onosproject.store.service.Serializer;
21 -
22 -import static com.google.common.base.Preconditions.checkArgument;
23 -import static com.google.common.base.Preconditions.checkState;
24 -
25 -/**
26 - * Default implementation of a {@code DistributedQueueBuilder}.
27 - *
28 - * @param <E> queue entry type
29 - */
30 -public class DefaultDistributedQueueBuilder<E> implements DistributedQueueBuilder<E> {
31 -
32 - private Serializer serializer;
33 - private String name;
34 - private boolean persistenceEnabled = true;
35 - private final DatabaseManager databaseManager;
36 - private boolean metering = true;
37 -
38 - public DefaultDistributedQueueBuilder(DatabaseManager databaseManager) {
39 - this.databaseManager = databaseManager;
40 - }
41 -
42 - @Override
43 - public DistributedQueueBuilder<E> withName(String name) {
44 - checkArgument(name != null && !name.isEmpty());
45 - this.name = name;
46 - return this;
47 - }
48 -
49 - @Override
50 - public DistributedQueueBuilder<E> withSerializer(Serializer serializer) {
51 - checkArgument(serializer != null);
52 - this.serializer = serializer;
53 - return this;
54 - }
55 -
56 - @Override
57 - public DistributedQueueBuilder<E> withMeteringDisabled() {
58 - metering = false;
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 - return new DefaultDistributedQueue<>(
76 - name,
77 - persistenceEnabled ? databaseManager.partitionedDatabase : databaseManager.inMemoryDatabase,
78 - serializer,
79 - metering);
80 - }
81 -}
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 -
17 -package org.onosproject.store.primitives.impl;
18 -
19 -import java.util.List;
20 -import java.util.Map;
21 -import java.util.concurrent.CompletableFuture;
22 -import java.util.function.Function;
23 -import java.util.function.Supplier;
24 -
25 -import static com.google.common.base.Preconditions.*;
26 -
27 -import org.onosproject.store.primitives.MapUpdate;
28 -import org.onosproject.store.primitives.TransactionId;
29 -import org.onosproject.store.primitives.resources.impl.CommitResult;
30 -import org.onosproject.store.service.CommitStatus;
31 -import org.onosproject.store.service.ConsistentMapBuilder;
32 -import org.onosproject.store.service.Serializer;
33 -import org.onosproject.store.service.TransactionContext;
34 -import org.onosproject.store.service.TransactionalMap;
35 -
36 -import com.google.common.base.MoreObjects;
37 -import com.google.common.base.MoreObjects.ToStringHelper;
38 -import com.google.common.collect.Lists;
39 -import com.google.common.collect.Maps;
40 -import com.google.common.util.concurrent.Futures;
41 -
42 -/**
43 - * Default TransactionContext implementation.
44 - */
45 -public class DefaultTransactionContext implements TransactionContext {
46 - private static final String TX_NOT_OPEN_ERROR = "Transaction Context is not open";
47 -
48 - @SuppressWarnings("rawtypes")
49 - private final Map<String, DefaultTransactionalMap> txMaps = Maps.newConcurrentMap();
50 - private boolean isOpen = false;
51 - private final Function<Transaction, CompletableFuture<CommitResult>> transactionCommitter;
52 - private final TransactionId transactionId;
53 - private final Supplier<ConsistentMapBuilder> mapBuilderSupplier;
54 -
55 - public DefaultTransactionContext(TransactionId transactionId,
56 - Function<Transaction, CompletableFuture<CommitResult>> transactionCommitter,
57 - Supplier<ConsistentMapBuilder> mapBuilderSupplier) {
58 - this.transactionId = transactionId;
59 - this.transactionCommitter = checkNotNull(transactionCommitter);
60 - this.mapBuilderSupplier = checkNotNull(mapBuilderSupplier);
61 - }
62 -
63 - @Override
64 - public TransactionId transactionId() {
65 - return transactionId;
66 - }
67 -
68 - @Override
69 - public void begin() {
70 - checkState(!isOpen, "Transaction Context is already open");
71 - isOpen = true;
72 - }
73 -
74 - @Override
75 - public boolean isOpen() {
76 - return isOpen;
77 - }
78 -
79 - @Override
80 - @SuppressWarnings("unchecked")
81 - public <K, V> TransactionalMap<K, V> getTransactionalMap(String mapName,
82 - Serializer serializer) {
83 - checkState(isOpen, TX_NOT_OPEN_ERROR);
84 - checkNotNull(mapName);
85 - checkNotNull(serializer);
86 - return txMaps.computeIfAbsent(mapName, name -> {
87 - ConsistentMapBuilder mapBuilder = (ConsistentMapBuilder) mapBuilderSupplier.get()
88 - .withName(name)
89 - .withSerializer(serializer);
90 - return new DefaultTransactionalMap<>(
91 - name,
92 - mapBuilder.buildAsyncMap(),
93 - this,
94 - serializer);
95 - });
96 - }
97 -
98 - @SuppressWarnings("unchecked")
99 - @Override
100 - public CompletableFuture<CommitStatus> commit() {
101 - // TODO: rework commit implementation to be more intuitive
102 - checkState(isOpen, TX_NOT_OPEN_ERROR);
103 - CommitStatus status;
104 - try {
105 - List<MapUpdate<String, byte[]>> updates = Lists.newLinkedList();
106 - txMaps.values().forEach(m -> updates.addAll(m.toMapUpdates()));
107 - Transaction transaction = new Transaction(transactionId, updates);
108 - status = Futures.getUnchecked(transactionCommitter.apply(transaction)) == CommitResult.OK
109 - ? CommitStatus.SUCCESS : CommitStatus.FAILURE;
110 - } catch (Exception e) {
111 - abort();
112 - status = CommitStatus.FAILURE;
113 - } finally {
114 - isOpen = false;
115 - }
116 - return CompletableFuture.completedFuture(status);
117 - }
118 -
119 - @Override
120 - public void abort() {
121 - if (isOpen) {
122 - try {
123 - txMaps.values().forEach(m -> m.abort());
124 - } finally {
125 - isOpen = false;
126 - }
127 - }
128 - }
129 -
130 - @Override
131 - public String toString() {
132 - ToStringHelper s = MoreObjects.toStringHelper(this)
133 - .add("transactionId", transactionId)
134 - .add("isOpen", isOpen);
135 -
136 - txMaps.entrySet().forEach(e -> {
137 - s.add(e.getKey(), e.getValue());
138 - });
139 - return s.toString();
140 - }
141 -
142 - @Override
143 - public String name() {
144 - return transactionId.toString();
145 - }
146 -}
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.primitives.impl;
17 -
18 -import java.util.concurrent.CompletableFuture;
19 -import java.util.function.Function;
20 -import java.util.function.Supplier;
21 -
22 -import org.onosproject.store.primitives.TransactionId;
23 -import org.onosproject.store.primitives.resources.impl.CommitResult;
24 -import org.onosproject.store.service.ConsistentMapBuilder;
25 -import org.onosproject.store.service.TransactionContext;
26 -import org.onosproject.store.service.TransactionContextBuilder;
27 -
28 -/**
29 - * The default implementation of a transaction context builder. This builder
30 - * generates a {@link DefaultTransactionContext}.
31 - */
32 -public class DefaultTransactionContextBuilder extends TransactionContextBuilder {
33 -
34 - private final Supplier<ConsistentMapBuilder> mapBuilderSupplier;
35 - private final Function<Transaction, CompletableFuture<CommitResult>> transactionCommitter;
36 - private final TransactionId transactionId;
37 -
38 - public DefaultTransactionContextBuilder(Supplier<ConsistentMapBuilder> mapBuilderSupplier,
39 - Function<Transaction, CompletableFuture<CommitResult>> transactionCommiter,
40 - TransactionId transactionId) {
41 - this.mapBuilderSupplier = mapBuilderSupplier;
42 - this.transactionCommitter = transactionCommiter;
43 - this.transactionId = transactionId;
44 - }
45 -
46 - @Override
47 - public TransactionContext build() {
48 - return new DefaultTransactionContext(transactionId, transactionCommitter, () -> {
49 - ConsistentMapBuilder mapBuilder = mapBuilderSupplier.get();
50 - if (partitionsDisabled()) {
51 - mapBuilder = (ConsistentMapBuilder) mapBuilder.withPartitionsDisabled();
52 - }
53 - return mapBuilder;
54 - });
55 - }
56 -}
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.primitives.impl;
17 -
18 -import java.util.Arrays;
19 -import java.util.Collection;
20 -import java.util.Iterator;
21 -import java.util.Set;
22 -import java.util.function.Function;
23 -import java.util.stream.Collectors;
24 -
25 -import com.google.common.collect.Iterators;
26 -
27 -/**
28 - * Set view backed by Set with element type {@code <BACK>} but returns
29 - * element as {@code <OUT>} for convenience.
30 - *
31 - * @param <BACK> Backing {@link Set} element type.
32 - * MappingSet will follow this type's equality behavior.
33 - * @param <OUT> external facing element type.
34 - * MappingSet will ignores equality defined by this type.
35 - */
36 -class MappingSet<BACK, OUT> implements Set<OUT> {
37 -
38 - private final Set<BACK> backedSet;
39 - private final Function<OUT, BACK> toBack;
40 - private final Function<BACK, OUT> toOut;
41 -
42 - public MappingSet(Set<BACK> backedSet,
43 - Function<Set<BACK>, Set<BACK>> supplier,
44 - Function<OUT, BACK> toBack, Function<BACK, OUT> toOut) {
45 - this.backedSet = supplier.apply(backedSet);
46 - this.toBack = toBack;
47 - this.toOut = toOut;
48 - }
49 -
50 - @Override
51 - public int size() {
52 - return backedSet.size();
53 - }
54 -
55 - @Override
56 - public boolean isEmpty() {
57 - return backedSet.isEmpty();
58 - }
59 -
60 - @Override
61 - public boolean contains(Object o) {
62 - return backedSet.contains(toBack.apply((OUT) o));
63 - }
64 -
65 - @Override
66 - public Iterator<OUT> iterator() {
67 - return Iterators.transform(backedSet.iterator(), toOut::apply);
68 - }
69 -
70 - @Override
71 - public Object[] toArray() {
72 - return backedSet.stream()
73 - .map(toOut)
74 - .toArray();
75 - }
76 -
77 - @Override
78 - public <T> T[] toArray(T[] a) {
79 - return backedSet.stream()
80 - .map(toOut)
81 - .toArray(size -> {
82 - if (size < a.length) {
83 - return (T[]) new Object[size];
84 - } else {
85 - Arrays.fill(a, null);
86 - return a;
87 - }
88 - });
89 - }
90 -
91 - @Override
92 - public boolean add(OUT e) {
93 - return backedSet.add(toBack.apply(e));
94 - }
95 -
96 - @Override
97 - public boolean remove(Object o) {
98 - return backedSet.remove(toBack.apply((OUT) o));
99 - }
100 -
101 - @Override
102 - public boolean containsAll(Collection<?> c) {
103 - return c.stream()
104 - .map(e -> toBack.apply((OUT) e))
105 - .allMatch(backedSet::contains);
106 - }
107 -
108 - @Override
109 - public boolean addAll(Collection<? extends OUT> c) {
110 - return backedSet.addAll(c.stream().map(toBack).collect(Collectors.toList()));
111 - }
112 -
113 - @Override
114 - public boolean retainAll(Collection<?> c) {
115 - return backedSet.retainAll(c.stream()
116 - .map(x -> toBack.apply((OUT) x))
117 - .collect(Collectors.toList()));
118 - }
119 -
120 - @Override
121 - public boolean removeAll(Collection<?> c) {
122 - return backedSet.removeAll(c.stream()
123 - .map(x -> toBack.apply((OUT) x))
124 - .collect(Collectors.toList()));
125 - }
126 -
127 - @Override
128 - public void clear() {
129 - backedSet.clear();
130 - }
131 -}
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 -
17 -package org.onosproject.store.primitives.impl;
18 -
19 -import com.google.common.collect.ImmutableList;
20 -import com.google.common.collect.Lists;
21 -import com.google.common.collect.Maps;
22 -import com.google.common.collect.Sets;
23 -
24 -import net.kuujo.copycat.Task;
25 -import net.kuujo.copycat.cluster.Cluster;
26 -import net.kuujo.copycat.resource.ResourceState;
27 -
28 -import org.onlab.util.Match;
29 -import org.onosproject.store.primitives.MapUpdate;
30 -import org.onosproject.store.primitives.resources.impl.CommitResult;
31 -import org.onosproject.store.service.Versioned;
32 -
33 -import java.util.Collection;
34 -import java.util.List;
35 -import java.util.Map;
36 -import java.util.Map.Entry;
37 -import java.util.Set;
38 -import java.util.concurrent.CompletableFuture;
39 -import java.util.concurrent.CopyOnWriteArrayList;
40 -import java.util.concurrent.atomic.AtomicBoolean;
41 -import java.util.concurrent.atomic.AtomicInteger;
42 -import java.util.function.Consumer;
43 -import java.util.stream.Collectors;
44 -
45 -import static com.google.common.base.Preconditions.checkState;
46 -
47 -/**
48 - * A database that partitions the keys across one or more database partitions.
49 - */
50 -public class PartitionedDatabase implements Database {
51 -
52 - private final String name;
53 - private final Partitioner<String> partitioner;
54 - private final List<Database> partitions;
55 - private final AtomicBoolean isOpen = new AtomicBoolean(false);
56 - private static final String DB_NOT_OPEN = "Partitioned Database is not open";
57 - private TransactionManager transactionManager;
58 -
59 - public PartitionedDatabase(
60 - String name,
61 - Collection<Database> partitions) {
62 - this.name = name;
63 - this.partitions = partitions
64 - .stream()
65 - .sorted((db1, db2) -> db1.name().compareTo(db2.name()))
66 - .collect(Collectors.toList());
67 - this.partitioner = new SimpleKeyHashPartitioner(this.partitions);
68 - }
69 -
70 - /**
71 - * Returns the databases for individual partitions.
72 - * @return list of database partitions
73 - */
74 - public List<Database> getPartitions() {
75 - return partitions;
76 - }
77 -
78 - /**
79 - * Returns true if the database is open.
80 - * @return true if open, false otherwise
81 - */
82 - @Override
83 - public boolean isOpen() {
84 - return isOpen.get();
85 - }
86 -
87 - @Override
88 - public CompletableFuture<Set<String>> maps() {
89 - checkState(isOpen.get(), DB_NOT_OPEN);
90 - Set<String> mapNames = Sets.newConcurrentHashSet();
91 - return CompletableFuture.allOf(partitions
92 - .stream()
93 - .map(db -> db.maps().thenApply(mapNames::addAll))
94 - .toArray(CompletableFuture[]::new))
95 - .thenApply(v -> mapNames);
96 - }
97 -
98 - @Override
99 - public CompletableFuture<Map<String, Long>> counters() {
100 - checkState(isOpen.get(), DB_NOT_OPEN);
101 - Map<String, Long> counters = Maps.newConcurrentMap();
102 - return CompletableFuture.allOf(partitions
103 - .stream()
104 - .map(db -> db.counters()
105 - .thenApply(m -> {
106 - counters.putAll(m);
107 - return null;
108 - }))
109 - .toArray(CompletableFuture[]::new))
110 - .thenApply(v -> counters);
111 - }
112 -
113 - @Override
114 - public CompletableFuture<Integer> mapSize(String mapName) {
115 - checkState(isOpen.get(), DB_NOT_OPEN);
116 - AtomicInteger totalSize = new AtomicInteger(0);
117 - return CompletableFuture.allOf(partitions
118 - .stream()
119 - .map(p -> p.mapSize(mapName).thenApply(totalSize::addAndGet))
120 - .toArray(CompletableFuture[]::new))
121 - .thenApply(v -> totalSize.get());
122 - }
123 -
124 - @Override
125 - public CompletableFuture<Boolean> mapIsEmpty(String mapName) {
126 - checkState(isOpen.get(), DB_NOT_OPEN);
127 - return mapSize(mapName).thenApply(size -> size == 0);
128 - }
129 -
130 - @Override
131 - public CompletableFuture<Boolean> mapContainsKey(String mapName, String key) {
132 - checkState(isOpen.get(), DB_NOT_OPEN);
133 - return partitioner.getPartition(mapName, key).mapContainsKey(mapName, key);
134 - }
135 -
136 - @Override
137 - public CompletableFuture<Boolean> mapContainsValue(String mapName, byte[] value) {
138 - checkState(isOpen.get(), DB_NOT_OPEN);
139 - AtomicBoolean containsValue = new AtomicBoolean(false);
140 - return CompletableFuture.allOf(partitions
141 - .stream()
142 - .map(p -> p.mapContainsValue(mapName, value)
143 - .thenApply(v -> containsValue.compareAndSet(false, v)))
144 - .toArray(CompletableFuture[]::new))
145 - .thenApply(v -> containsValue.get());
146 - }
147 -
148 - @Override
149 - public CompletableFuture<Versioned<byte[]>> mapGet(String mapName, String key) {
150 - checkState(isOpen.get(), DB_NOT_OPEN);
151 - return partitioner.getPartition(mapName, key).mapGet(mapName, key);
152 - }
153 -
154 - @Override
155 - public CompletableFuture<Result<UpdateResult<String, byte[]>>> mapUpdate(
156 - String mapName, String key, Match<byte[]> valueMatch,
157 - Match<Long> versionMatch, byte[] value) {
158 - return partitioner.getPartition(mapName, key).mapUpdate(mapName, key, valueMatch, versionMatch, value);
159 -
160 - }
161 -
162 - @Override
163 - public CompletableFuture<Result<Void>> mapClear(String mapName) {
164 - AtomicBoolean isLocked = new AtomicBoolean(false);
165 - checkState(isOpen.get(), DB_NOT_OPEN);
166 - return CompletableFuture.allOf(partitions
167 - .stream()
168 - .map(p -> p.mapClear(mapName)
169 - .thenApply(v -> isLocked.compareAndSet(false, Result.Status.LOCKED == v.status())))
170 - .toArray(CompletableFuture[]::new))
171 - .thenApply(v -> isLocked.get() ? Result.locked() : Result.ok(null));
172 - }
173 -
174 - @Override
175 - public CompletableFuture<Set<String>> mapKeySet(String mapName) {
176 - checkState(isOpen.get(), DB_NOT_OPEN);
177 - Set<String> keySet = Sets.newConcurrentHashSet();
178 - return CompletableFuture.allOf(partitions
179 - .stream()
180 - .map(p -> p.mapKeySet(mapName).thenApply(keySet::addAll))
181 - .toArray(CompletableFuture[]::new))
182 - .thenApply(v -> keySet);
183 - }
184 -
185 - @Override
186 - public CompletableFuture<Collection<Versioned<byte[]>>> mapValues(String mapName) {
187 - checkState(isOpen.get(), DB_NOT_OPEN);
188 - List<Versioned<byte[]>> values = new CopyOnWriteArrayList<>();
189 - return CompletableFuture.allOf(partitions
190 - .stream()
191 - .map(p -> p.mapValues(mapName).thenApply(values::addAll))
192 - .toArray(CompletableFuture[]::new))
193 - .thenApply(v -> values);
194 - }
195 -
196 - @Override
197 - public CompletableFuture<Set<Entry<String, Versioned<byte[]>>>> mapEntrySet(String mapName) {
198 - checkState(isOpen.get(), DB_NOT_OPEN);
199 - Set<Entry<String, Versioned<byte[]>>> entrySet = Sets.newConcurrentHashSet();
200 - return CompletableFuture.allOf(partitions
201 - .stream()
202 - .map(p -> p.mapEntrySet(mapName).thenApply(entrySet::addAll))
203 - .toArray(CompletableFuture[]::new))
204 - .thenApply(v -> entrySet);
205 - }
206 -
207 - @Override
208 - public CompletableFuture<Long> counterGet(String counterName) {
209 - checkState(isOpen.get(), DB_NOT_OPEN);
210 - return partitioner.getPartition(counterName, counterName).counterGet(counterName);
211 - }
212 -
213 - @Override
214 - public CompletableFuture<Long> counterAddAndGet(String counterName, long delta) {
215 - checkState(isOpen.get(), DB_NOT_OPEN);
216 - return partitioner.getPartition(counterName, counterName).counterAddAndGet(counterName, delta);
217 - }
218 -
219 - @Override
220 - public CompletableFuture<Long> counterGetAndAdd(String counterName, long delta) {
221 - checkState(isOpen.get(), DB_NOT_OPEN);
222 - return partitioner.getPartition(counterName, counterName).counterGetAndAdd(counterName, delta);
223 - }
224 -
225 - @Override
226 - public CompletableFuture<Void> counterSet(String counterName, long value) {
227 - checkState(isOpen.get(), DB_NOT_OPEN);
228 - return partitioner.getPartition(counterName, counterName).counterSet(counterName, value);
229 - }
230 -
231 - @Override
232 - public CompletableFuture<Boolean> counterCompareAndSet(String counterName, long expectedValue, long updateValue) {
233 - checkState(isOpen.get(), DB_NOT_OPEN);
234 - return partitioner.getPartition(counterName, counterName).
235 - counterCompareAndSet(counterName, expectedValue, updateValue);
236 -
237 - }
238 -
239 - @Override
240 - public CompletableFuture<Long> queueSize(String queueName) {
241 - checkState(isOpen.get(), DB_NOT_OPEN);
242 - return partitioner.getPartition(queueName, queueName).queueSize(queueName);
243 - }
244 -
245 - @Override
246 - public CompletableFuture<Void> queuePush(String queueName, byte[] entry) {
247 - checkState(isOpen.get(), DB_NOT_OPEN);
248 - return partitioner.getPartition(queueName, queueName).queuePush(queueName, entry);
249 - }
250 -
251 - @Override
252 - public CompletableFuture<byte[]> queuePop(String queueName) {
253 - checkState(isOpen.get(), DB_NOT_OPEN);
254 - return partitioner.getPartition(queueName, queueName).queuePop(queueName);
255 - }
256 -
257 - @Override
258 - public CompletableFuture<byte[]> queuePeek(String queueName) {
259 - checkState(isOpen.get(), DB_NOT_OPEN);
260 - return partitioner.getPartition(queueName, queueName).queuePeek(queueName);
261 - }
262 -
263 - @Override
264 - public CompletableFuture<CommitResponse> prepareAndCommit(Transaction transaction) {
265 - Map<Database, Transaction> subTransactions = createSubTransactions(transaction);
266 - if (subTransactions.isEmpty()) {
267 - return CompletableFuture.completedFuture(CommitResponse.success(ImmutableList.of()));
268 - } else if (subTransactions.size() == 1) {
269 - Entry<Database, Transaction> entry =
270 - subTransactions.entrySet().iterator().next();
271 - return entry.getKey().prepareAndCommit(entry.getValue());
272 - } else {
273 - if (transactionManager == null) {
274 - throw new IllegalStateException("TransactionManager is not initialized");
275 - }
276 - return transactionManager.execute(transaction)
277 - .thenApply(r -> r == CommitResult.OK
278 - ? CommitResponse.success(ImmutableList.of()) : CommitResponse.failure());
279 - }
280 - }
281 -
282 - @Override
283 - public CompletableFuture<Boolean> prepare(Transaction transaction) {
284 - Map<Database, Transaction> subTransactions = createSubTransactions(transaction);
285 - AtomicBoolean status = new AtomicBoolean(true);
286 - return CompletableFuture.allOf(subTransactions.entrySet()
287 - .stream()
288 - .map(entry -> entry
289 - .getKey()
290 - .prepare(entry.getValue())
291 - .thenApply(v -> status.compareAndSet(true, v)))
292 - .toArray(CompletableFuture[]::new))
293 - .thenApply(v -> status.get());
294 - }
295 -
296 - @Override
297 - public CompletableFuture<CommitResponse> commit(Transaction transaction) {
298 - Map<Database, Transaction> subTransactions = createSubTransactions(transaction);
299 - AtomicBoolean success = new AtomicBoolean(true);
300 - List<UpdateResult<String, byte[]>> allUpdates = Lists.newArrayList();
301 - return CompletableFuture.allOf(subTransactions.entrySet()
302 - .stream()
303 - .map(entry -> entry.getKey().commit(entry.getValue())
304 - .thenAccept(response -> {
305 - success.set(success.get() && response.success());
306 - if (success.get()) {
307 - allUpdates.addAll(response.updates());
308 - }
309 - }))
310 - .toArray(CompletableFuture[]::new))
311 - .thenApply(v -> success.get() ?
312 - CommitResponse.success(allUpdates) : CommitResponse.failure());
313 - }
314 -
315 - @Override
316 - public CompletableFuture<Boolean> rollback(Transaction transaction) {
317 - Map<Database, Transaction> subTransactions = createSubTransactions(transaction);
318 - return CompletableFuture.allOf(subTransactions.entrySet()
319 - .stream()
320 - .map(entry -> entry.getKey().rollback(entry.getValue()))
321 - .toArray(CompletableFuture[]::new))
322 - .thenApply(v -> true);
323 - }
324 -
325 - @Override
326 - public CompletableFuture<Database> open() {
327 - return CompletableFuture.allOf(partitions
328 - .stream()
329 - .map(Database::open)
330 - .toArray(CompletableFuture[]::new))
331 - .thenApply(v -> {
332 - isOpen.set(true);
333 - return this;
334 - });
335 - }
336 -
337 - @Override
338 - public CompletableFuture<Void> close() {
339 - checkState(isOpen.get(), DB_NOT_OPEN);
340 - return CompletableFuture.allOf(partitions
341 - .stream()
342 - .map(database -> database.close())
343 - .toArray(CompletableFuture[]::new));
344 - }
345 -
346 - @Override
347 - public boolean isClosed() {
348 - return !isOpen.get();
349 - }
350 -
351 - @Override
352 - public String name() {
353 - return name;
354 - }
355 -
356 - @Override
357 - public Cluster cluster() {
358 - throw new UnsupportedOperationException();
359 - }
360 -
361 - @Override
362 - public Database addStartupTask(Task<CompletableFuture<Void>> task) {
363 - throw new UnsupportedOperationException();
364 - }
365 -
366 - @Override
367 - public Database addShutdownTask(Task<CompletableFuture<Void>> task) {
368 - throw new UnsupportedOperationException();
369 - }
370 -
371 - @Override
372 - public ResourceState state() {
373 - throw new UnsupportedOperationException();
374 - }
375 -
376 - private Map<Database, Transaction> createSubTransactions(
377 - Transaction transaction) {
378 - Map<Database, List<MapUpdate<String, byte[]>>> perPartitionUpdates = Maps.newHashMap();
379 - for (MapUpdate<String, byte[]> update : transaction.updates()) {
380 - Database partition = partitioner.getPartition(update.mapName(), update.key());
381 - List<MapUpdate<String, byte[]>> partitionUpdates =
382 - perPartitionUpdates.computeIfAbsent(partition, k -> Lists.newLinkedList());
383 - partitionUpdates.add(update);
384 - }
385 - Map<Database, Transaction> subTransactions = Maps.newHashMap();
386 - perPartitionUpdates.forEach((k, v) -> subTransactions.put(k, new Transaction(transaction.id(), v)));
387 - return subTransactions;
388 - }
389 -
390 - protected void setTransactionManager(TransactionManager transactionManager) {
391 - this.transactionManager = transactionManager;
392 - }
393 -
394 - @Override
395 - public void registerConsumer(Consumer<StateMachineUpdate> consumer) {
396 - partitions.forEach(p -> p.registerConsumer(consumer));
397 - }
398 -
399 - @Override
400 - public void unregisterConsumer(Consumer<StateMachineUpdate> consumer) {
401 - partitions.forEach(p -> p.unregisterConsumer(consumer));
402 - }
403 -}
404 -
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 -
17 -package org.onosproject.store.primitives.impl;
18 -
19 -/**
20 - * Partitioner is responsible for mapping keys to individual database partitions.
21 - *
22 - * @param <K> key type.
23 - */
24 -public interface Partitioner<K> {
25 -
26 - /**
27 - * Returns the database partition.
28 - * @param mapName map name
29 - * @param key key
30 - * @return Database partition
31 - */
32 - Database getPartition(String mapName, K key);
33 -}
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.primitives.impl;
17 -
18 -import static com.google.common.base.MoreObjects.toStringHelper;
19 -
20 -import java.util.Objects;
21 -
22 -/**
23 - * Result of a database update operation.
24 - *
25 - * @param <V> return value type
26 - */
27 -public final class Result<V> {
28 -
29 - public enum Status {
30 - /**
31 - * Indicates a successful update.
32 - */
33 - OK,
34 -
35 - /**
36 - * Indicates a failure due to underlying state being locked by another transaction.
37 - */
38 - LOCKED
39 - }
40 -
41 - private final Status status;
42 - private final V value;
43 -
44 - /**
45 - * Creates a new Result instance with the specified value with status set to Status.OK.
46 - *
47 - * @param <V> result value type
48 - * @param value result value
49 - * @return Result instance
50 - */
51 - public static <V> Result<V> ok(V value) {
52 - return new Result<>(value, Status.OK);
53 - }
54 -
55 - /**
56 - * Creates a new Result instance with status set to Status.LOCKED.
57 - *
58 - * @param <V> result value type
59 - * @return Result instance
60 - */
61 - public static <V> Result<V> locked() {
62 - return new Result<>(null, Status.LOCKED);
63 - }
64 -
65 - private Result(V value, Status status) {
66 - this.value = value;
67 - this.status = status;
68 - }
69 -
70 - /**
71 - * Returns true if this result indicates a successful execution i.e status is Status.OK.
72 - *
73 - * @return true if successful, false otherwise
74 - */
75 - public boolean success() {
76 - return status == Status.OK;
77 - }
78 -
79 - /**
80 - * Returns the status of database update operation.
81 - *
82 - * @return database update status
83 - */
84 - public Status status() {
85 - return status;
86 - }
87 -
88 - /**
89 - * Returns the return value for the update.
90 - *
91 - * @return value returned by database update. If the status is another
92 - * other than Status.OK, this returns a null
93 - */
94 - public V value() {
95 - return value;
96 - }
97 -
98 - @Override
99 - public int hashCode() {
100 - return Objects.hash(value, status);
101 - }
102 -
103 - @SuppressWarnings("unchecked")
104 - @Override
105 - public boolean equals(Object other) {
106 - if (!(other instanceof Result)) {
107 - return false;
108 - }
109 - Result<V> that = (Result<V>) other;
110 - return Objects.equals(this.value, that.value) &&
111 - Objects.equals(this.status, that.status);
112 - }
113 -
114 - @Override
115 - public String toString() {
116 - return toStringHelper(this)
117 - .add("status", status)
118 - .add("value", value)
119 - .toString();
120 - }
121 -}
...\ 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 -
17 -package org.onosproject.store.primitives.impl;
18 -
19 -import java.util.List;
20 -
21 -/**
22 - * A simple Partitioner for mapping keys to database partitions.
23 - * <p>
24 - * This class uses a md5 hash based hashing scheme for hashing the key to
25 - * a partition.
26 - *
27 - */
28 -public class SimpleKeyHashPartitioner extends DatabasePartitioner {
29 -
30 - public SimpleKeyHashPartitioner(List<Database> partitions) {
31 - super(partitions);
32 - }
33 -
34 - @Override
35 - public Database getPartition(String mapName, String key) {
36 - return partitions.get(hash(key) % partitions.size());
37 - }
38 -}
...\ 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 -
17 -package org.onosproject.store.primitives.impl;
18 -
19 -import java.util.List;
20 -
21 -/**
22 - * A simple Partitioner that uses the map name hash to
23 - * pick a partition.
24 - * <p>
25 - * This class uses a md5 hash based hashing scheme for hashing the map name to
26 - * a partition. This partitioner maps all keys for a map to the same database
27 - * partition.
28 - */
29 -public class SimpleTableHashPartitioner extends DatabasePartitioner {
30 -
31 - public SimpleTableHashPartitioner(List<Database> partitions) {
32 - super(partitions);
33 - }
34 -
35 - @Override
36 - public Database getPartition(String mapName, String key) {
37 - return partitions.get(hash(mapName) % partitions.size());
38 - }
39 -}
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.primitives.impl;
17 -
18 -import static com.google.common.base.MoreObjects.toStringHelper;
19 -
20 -/**
21 - * Representation of a state machine update.
22 - */
23 -public class StateMachineUpdate {
24 -
25 - /**
26 - * Target data structure type this update is for.
27 - */
28 - enum Target {
29 - /**
30 - * Update is for a map.
31 - */
32 - MAP_UPDATE,
33 -
34 - /**
35 - * Update is a transaction commit.
36 - */
37 - TX_COMMIT,
38 -
39 - /**
40 - * Update is a queue push.
41 - */
42 - QUEUE_PUSH,
43 -
44 - /**
45 - * Update is for some other operation.
46 - */
47 - OTHER
48 - }
49 -
50 - private final String operationName;
51 - private final Object input;
52 - private final Object output;
53 -
54 - public StateMachineUpdate(String operationName, Object input, Object output) {
55 - this.operationName = operationName;
56 - this.input = input;
57 - this.output = output;
58 - }
59 -
60 - public Target target() {
61 - // FIXME: This check is brittle
62 - if (operationName.contains("mapUpdate")) {
63 - return Target.MAP_UPDATE;
64 - } else if (operationName.contains("commit") || operationName.contains("prepareAndCommit")) {
65 - return Target.TX_COMMIT;
66 - } else if (operationName.contains("queuePush")) {
67 - return Target.QUEUE_PUSH;
68 - } else {
69 - return Target.OTHER;
70 - }
71 - }
72 -
73 - @SuppressWarnings("unchecked")
74 - public <T> T input() {
75 - return (T) input;
76 - }
77 -
78 - @SuppressWarnings("unchecked")
79 - public <T> T output() {
80 - return (T) output;
81 - }
82 -
83 - @Override
84 - public String toString() {
85 - return toStringHelper(this)
86 - .add("name", operationName)
87 - .add("input", input)
88 - .add("output", output)
89 - .toString();
90 - }
91 -}
...\ 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.primitives.impl;
17 -
18 -import static com.google.common.base.Preconditions.checkNotNull;
19 -
20 -import java.util.Collection;
21 -import java.util.concurrent.CompletableFuture;
22 -import java.util.stream.Collectors;
23 -
24 -import org.onosproject.store.primitives.TransactionId;
25 -import org.onosproject.store.primitives.resources.impl.CommitResult;
26 -import org.onosproject.store.service.AsyncConsistentMap;
27 -
28 -import static org.onosproject.store.primitives.impl.Transaction.State.COMMITTED;
29 -import static org.onosproject.store.primitives.impl.Transaction.State.COMMITTING;
30 -import static org.onosproject.store.primitives.impl.Transaction.State.ROLLEDBACK;
31 -import static org.onosproject.store.primitives.impl.Transaction.State.ROLLINGBACK;
32 -
33 -/**
34 - * Agent that runs the two phase commit protocol.
35 - */
36 -public class TransactionManager {
37 -
38 - private final Database database;
39 - private final AsyncConsistentMap<TransactionId, Transaction> transactions;
40 -
41 - public TransactionManager(Database database, AsyncConsistentMap<TransactionId, Transaction> transactions) {
42 - this.database = checkNotNull(database, "database cannot be null");
43 - this.transactions = transactions;
44 - }
45 -
46 - /**
47 - * Executes the specified transaction by employing a two phase commit protocol.
48 - *
49 - * @param transaction transaction to commit
50 - * @return transaction commit result
51 - */
52 - public CompletableFuture<CommitResult> execute(Transaction transaction) {
53 - // short-circuit if there is only a single update
54 - if (transaction.updates().size() <= 1) {
55 - return database.prepareAndCommit(transaction)
56 - .thenApply(response -> response.success()
57 - ? CommitResult.OK : CommitResult.FAILURE_DURING_COMMIT);
58 - }
59 - // clean up if this transaction in already in a terminal state.
60 - if (transaction.state() == COMMITTED || transaction.state() == ROLLEDBACK) {
61 - return transactions.remove(transaction.id()).thenApply(v -> CommitResult.OK);
62 - } else if (transaction.state() == COMMITTING) {
63 - return commit(transaction);
64 - } else if (transaction.state() == ROLLINGBACK) {
65 - return rollback(transaction).thenApply(v -> CommitResult.FAILURE_TO_PREPARE);
66 - } else {
67 - return prepare(transaction).thenCompose(v -> v ? commit(transaction) : rollback(transaction));
68 - }
69 - }
70 -
71 - /**
72 - * Returns all pending transaction identifiers.
73 - *
74 - * @return future for a collection of transaction identifiers.
75 - */
76 - public CompletableFuture<Collection<TransactionId>> getPendingTransactionIds() {
77 - return transactions.values().thenApply(c -> c.stream()
78 - .map(v -> v.value())
79 - .filter(v -> v.state() != COMMITTED && v.state() != ROLLEDBACK)
80 - .map(Transaction::id)
81 - .collect(Collectors.toList()));
82 - }
83 -
84 - private CompletableFuture<Boolean> prepare(Transaction transaction) {
85 - return transactions.put(transaction.id(), transaction)
86 - .thenCompose(v -> database.prepare(transaction))
87 - .thenCompose(status -> transactions.put(
88 - transaction.id(),
89 - transaction.transition(status ? COMMITTING : ROLLINGBACK))
90 - .thenApply(v -> status));
91 - }
92 -
93 - private CompletableFuture<CommitResult> commit(Transaction transaction) {
94 - return database.commit(transaction)
95 - .thenCompose(r -> {
96 - if (r.success()) {
97 - return transactions.put(transaction.id(), transaction.transition(COMMITTED))
98 - .thenApply(v -> CommitResult.OK);
99 - } else {
100 - return CompletableFuture.completedFuture(CommitResult.FAILURE_DURING_COMMIT);
101 - }
102 - });
103 - }
104 -
105 - private CompletableFuture<CommitResult> rollback(Transaction transaction) {
106 - return database.rollback(transaction)
107 - .thenCompose(v -> transactions.put(transaction.id(), transaction.transition(ROLLEDBACK)))
108 - .thenApply(v -> CommitResult.FAILURE_TO_PREPARE);
109 - }
110 -}
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.primitives.impl;
17 -
18 -import java.util.function.Function;
19 -
20 -import org.onosproject.store.service.MapEvent;
21 -import org.onosproject.store.service.Versioned;
22 -
23 -/**
24 - * Result of a update operation.
25 - * <p>
26 - * Both old and new values are accessible along with a flag that indicates if the
27 - * the value was updated. If flag is false, oldValue and newValue both
28 - * point to the same unmodified value.
29 - * @param <V> result type
30 - */
31 -public class UpdateResult<K, V> {
32 -
33 - private final boolean updated;
34 - private final String mapName;
35 - private final K key;
36 - private final Versioned<V> oldValue;
37 - private final Versioned<V> newValue;
38 -
39 - public UpdateResult(boolean updated, String mapName, K key, Versioned<V> oldValue, Versioned<V> newValue) {
40 - this.updated = updated;
41 - this.mapName = mapName;
42 - this.key = key;
43 - this.oldValue = oldValue;
44 - this.newValue = newValue;
45 - }
46 -
47 - public boolean updated() {
48 - return updated;
49 - }
50 -
51 - public String mapName() {
52 - return mapName;
53 - }
54 -
55 - public K key() {
56 - return key;
57 - }
58 -
59 - public Versioned<V> oldValue() {
60 - return oldValue;
61 - }
62 -
63 - public Versioned<V> newValue() {
64 - return newValue;
65 - }
66 -
67 - public <K1, V1> UpdateResult<K1, V1> map(Function<K, K1> keyTransform, Function<V, V1> valueMapper) {
68 - return new UpdateResult<>(updated,
69 - mapName,
70 - keyTransform.apply(key),
71 - oldValue == null ? null : oldValue.map(valueMapper),
72 - newValue == null ? null : newValue.map(valueMapper));
73 - }
74 -
75 - public MapEvent<K, V> toMapEvent() {
76 - if (!updated) {
77 - return null;
78 - } else {
79 - return new MapEvent<>(mapName(), key(), newValue, oldValue);
80 - }
81 - }
82 -}
...\ 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.primitives.impl;
17 -
18 -import static java.util.Collections.unmodifiableCollection;
19 -import static java.util.Collections.unmodifiableSet;
20 -import static org.hamcrest.Matchers.is;
21 -import static org.junit.Assert.assertEquals;
22 -import static org.junit.Assert.assertThat;
23 -
24 -import java.util.Collection;
25 -import java.util.Map;
26 -import java.util.Map.Entry;
27 -import java.util.Objects;
28 -import java.util.Set;
29 -import java.util.concurrent.CompletableFuture;
30 -import java.util.concurrent.ConcurrentHashMap;
31 -import java.util.function.Consumer;
32 -
33 -import net.kuujo.copycat.Task;
34 -import net.kuujo.copycat.cluster.Cluster;
35 -import net.kuujo.copycat.resource.ResourceState;
36 -
37 -import org.junit.After;
38 -import org.junit.Before;
39 -import org.junit.Test;
40 -import org.onlab.util.Match;
41 -import org.onosproject.core.ApplicationId;
42 -import org.onosproject.core.DefaultApplicationId;
43 -import org.onosproject.store.service.Serializer;
44 -import org.onosproject.store.service.Versioned;
45 -
46 -import com.google.common.base.MoreObjects;
47 -import com.google.common.collect.ImmutableMap;
48 -import com.google.common.collect.ImmutableSet;
49 -import com.google.common.collect.Maps;
50 -
51 -/**
52 - *
53 - */
54 -public class DefaultAsyncConsistentMapTest {
55 -
56 - private static final ApplicationId APP_ID = new DefaultApplicationId(42, "what");
57 -
58 - private static final TestData KEY1A = new TestData("One", "a");
59 - private static final TestData KEY1B = new TestData("One", "b");
60 -
61 - private static final TestData VALUE2A = new TestData("Two", "a");
62 - private static final TestData VALUE2B = new TestData("Two", "b");
63 -
64 - @Before
65 - public void setUp() throws Exception {
66 - }
67 -
68 - @After
69 - public void tearDown() throws Exception {
70 - }
71 -
72 - @Test
73 - public void testKeySet() throws Exception {
74 - DefaultAsyncConsistentMap<TestData, TestData> map;
75 - String name = "map_name";
76 - Database database = new TestDatabase();
77 - Serializer serializer = Serializer.forTypes(TestData.class);
78 -
79 - map = new DefaultAsyncConsistentMap<>(name, APP_ID, database, serializer,
80 - false, false, false);
81 - map.put(KEY1A, VALUE2A);
82 - map.put(KEY1B, VALUE2A);
83 -
84 - Set<TestData> set = map.keySet().get();
85 - assertEquals("Should contain 2 keys",
86 - 2, set.size());
87 - assertThat(set.contains(KEY1A), is(true));
88 - assertThat(set.contains(KEY1B), is(true));
89 - assertThat(set.contains(new TestData("One", "a")), is(true));
90 - }
91 -
92 - @Test
93 - public void testEntrySet() throws Exception {
94 - DefaultAsyncConsistentMap<TestData, TestData> map;
95 - String name = "map_name";
96 - Database database = new TestDatabase();
97 - Serializer serializer = Serializer.forTypes(TestData.class);
98 -
99 - map = new DefaultAsyncConsistentMap<>(name, APP_ID, database, serializer,
100 - false, false, false);
101 - map.put(KEY1A, VALUE2A);
102 - map.put(KEY1B, VALUE2A);
103 -
104 - assertEquals("Should contain 2 entry",
105 - 2,
106 - map.entrySet().get().size());
107 - }
108 -
109 - /**
110 - * Object to be used as a test data.
111 - *
112 - * {@link Object#equals(Object)} use only part of it's fields.
113 - *
114 - * As a result there can be 2 instances which the
115 - * serialized bytes are not-equal but
116 - * {@link Object#equals(Object)}-wise they are equal.
117 - */
118 - public static class TestData {
119 -
120 - private final String theKey;
121 -
122 - @SuppressWarnings("unused")
123 - private final String notUsedForEquals;
124 -
125 - public TestData(String theKey, String notUsedForEquals) {
126 - this.theKey = theKey;
127 - this.notUsedForEquals = notUsedForEquals;
128 - }
129 -
130 - @Override
131 - public int hashCode() {
132 - return Objects.hashCode(theKey);
133 - }
134 -
135 - @Override
136 - public boolean equals(Object obj) {
137 - if (obj instanceof TestData) {
138 - TestData that = (TestData) obj;
139 - return Objects.equals(this.theKey, that.theKey);
140 - }
141 - return false;
142 - }
143 -
144 - @Override
145 - public String toString() {
146 - return MoreObjects.toStringHelper(this)
147 - .add("theKey", theKey)
148 - .add("notUsedForEquals", notUsedForEquals)
149 - .toString();
150 - }
151 - }
152 -
153 - /**
154 - * {@link Database} implementation for testing.
155 - *
156 - * There is only 1 backing Map, {@code mapName} will be ignored.
157 - */
158 - public class TestDatabase implements Database {
159 -
160 - Map<String, Versioned<byte[]>> map = new ConcurrentHashMap<>();
161 -
162 - @Override
163 - public CompletableFuture<Set<String>> maps() {
164 - return CompletableFuture.completedFuture(ImmutableSet.of());
165 - }
166 -
167 - @Override
168 - public CompletableFuture<Map<String, Long>> counters() {
169 - return CompletableFuture.completedFuture(ImmutableMap.of());
170 - }
171 -
172 - @Override
173 - public CompletableFuture<Integer> mapSize(String mapName) {
174 - return CompletableFuture.completedFuture(map.size());
175 - }
176 -
177 - @Override
178 - public CompletableFuture<Boolean> mapIsEmpty(String mapName) {
179 - return CompletableFuture.completedFuture(map.isEmpty());
180 - }
181 -
182 - @Override
183 - public CompletableFuture<Boolean> mapContainsKey(String mapName,
184 - String key) {
185 - return CompletableFuture.completedFuture(map.containsKey(key));
186 - }
187 -
188 - @Override
189 - public CompletableFuture<Boolean> mapContainsValue(String mapName,
190 - byte[] value) {
191 - return CompletableFuture.completedFuture(Maps.transformValues(map, Versioned::value)
192 - .containsValue(value));
193 - }
194 -
195 - @Override
196 - public CompletableFuture<Versioned<byte[]>> mapGet(String mapName,
197 - String key) {
198 - return CompletableFuture.completedFuture(map.get(key));
199 - }
200 -
201 - @Override
202 - public synchronized CompletableFuture<Result<UpdateResult<String, byte[]>>> mapUpdate(String mapName,
203 - String key,
204 - Match<byte[]> valueMatch,
205 - Match<Long> versionMatch,
206 - byte[] value) {
207 -
208 - boolean updated = false;
209 - final Versioned<byte[]> oldValue;
210 - final Versioned<byte[]> newValue;
211 -
212 - Versioned<byte[]> old = map.getOrDefault(key, new Versioned<byte[]>(null, 0));
213 - if (valueMatch.matches(old.value()) && versionMatch.matches(old.version())) {
214 - updated = true;
215 - oldValue = old;
216 - newValue = new Versioned<>(value, old.version() + 1);
217 - map.put(key, newValue);
218 - } else {
219 - updated = false;
220 - oldValue = old;
221 - newValue = old;
222 - }
223 - return CompletableFuture.completedFuture(
224 - Result.ok(new UpdateResult<String, byte[]>(updated,
225 - mapName, key, oldValue, newValue)));
226 - }
227 -
228 - @Override
229 - public CompletableFuture<Result<Void>> mapClear(String mapName) {
230 - throw new UnsupportedOperationException();
231 - }
232 -
233 - @Override
234 - public CompletableFuture<Set<String>> mapKeySet(String mapName) {
235 - return CompletableFuture.completedFuture(unmodifiableSet(map.keySet()));
236 - }
237 -
238 - @Override
239 - public CompletableFuture<Collection<Versioned<byte[]>>> mapValues(String mapName) {
240 - return CompletableFuture.completedFuture(unmodifiableCollection(map.values()));
241 - }
242 -
243 - @Override
244 - public CompletableFuture<Set<Entry<String, Versioned<byte[]>>>> mapEntrySet(String mapName) {
245 - return CompletableFuture.completedFuture(unmodifiableSet(map.entrySet()));
246 - }
247 -
248 - @Override
249 - public CompletableFuture<Long> counterAddAndGet(String counterName,
250 - long delta) {
251 - throw new UnsupportedOperationException();
252 - }
253 -
254 - @Override
255 - public CompletableFuture<Long> counterGetAndAdd(String counterName,
256 - long delta) {
257 - throw new UnsupportedOperationException();
258 - }
259 -
260 - @Override
261 - public CompletableFuture<Void> counterSet(String counterName,
262 - long value) {
263 - throw new UnsupportedOperationException();
264 - }
265 -
266 - @Override
267 - public CompletableFuture<Boolean> counterCompareAndSet(String counterName,
268 - long expectedValue,
269 - long update) {
270 - throw new UnsupportedOperationException();
271 - }
272 -
273 - @Override
274 - public CompletableFuture<Long> counterGet(String counterName) {
275 - throw new UnsupportedOperationException();
276 - }
277 -
278 - @Override
279 - public CompletableFuture<Long> queueSize(String queueName) {
280 - throw new UnsupportedOperationException();
281 - }
282 -
283 - @Override
284 - public CompletableFuture<Void> queuePush(String queueName,
285 - byte[] entry) {
286 - throw new UnsupportedOperationException();
287 - }
288 -
289 - @Override
290 - public CompletableFuture<byte[]> queuePop(String queueName) {
291 - throw new UnsupportedOperationException();
292 - }
293 -
294 - @Override
295 - public CompletableFuture<byte[]> queuePeek(String queueName) {
296 - throw new UnsupportedOperationException();
297 - }
298 -
299 - @Override
300 - public CompletableFuture<CommitResponse> prepareAndCommit(Transaction transaction) {
301 - throw new UnsupportedOperationException();
302 - }
303 -
304 - @Override
305 - public CompletableFuture<Boolean> prepare(Transaction transaction) {
306 - throw new UnsupportedOperationException();
307 - }
308 -
309 - @Override
310 - public CompletableFuture<CommitResponse> commit(Transaction transaction) {
311 - throw new UnsupportedOperationException();
312 - }
313 -
314 - @Override
315 - public CompletableFuture<Boolean> rollback(Transaction transaction) {
316 - throw new UnsupportedOperationException();
317 - }
318 -
319 - @Override
320 - public String name() {
321 - return "name";
322 - }
323 -
324 - @Override
325 - public ResourceState state() {
326 - return ResourceState.HEALTHY;
327 - }
328 -
329 - @Override
330 - public Cluster cluster() {
331 - throw new UnsupportedOperationException();
332 - }
333 -
334 - @Override
335 - public Database addStartupTask(Task<CompletableFuture<Void>> task) {
336 - throw new UnsupportedOperationException();
337 - }
338 -
339 - @Override
340 - public Database addShutdownTask(Task<CompletableFuture<Void>> task) {
341 - throw new UnsupportedOperationException();
342 - }
343 -
344 - @Override
345 - public CompletableFuture<Database> open() {
346 - return CompletableFuture.completedFuture(this);
347 - }
348 -
349 - @Override
350 - public boolean isOpen() {
351 - return true;
352 - }
353 -
354 - @Override
355 - public CompletableFuture<Void> close() {
356 - return CompletableFuture.completedFuture(null);
357 - }
358 -
359 - @Override
360 - public boolean isClosed() {
361 - return false;
362 - }
363 -
364 - @Override
365 - public void registerConsumer(Consumer<StateMachineUpdate> consumer) {
366 - }
367 -
368 - @Override
369 - public void unregisterConsumer(Consumer<StateMachineUpdate> consumer) {
370 - }
371 - }
372 -
373 -}
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.primitives.impl;
17 -
18 -import static junit.framework.TestCase.assertEquals;
19 -import static junit.framework.TestCase.assertFalse;
20 -import static junit.framework.TestCase.assertNull;
21 -import static junit.framework.TestCase.assertTrue;
22 -
23 -import org.junit.Test;
24 -
25 -/**
26 - * Unit tests for Result.
27 - */
28 -public class ResultTest {
29 -
30 - @Test
31 - public void testLocked() {
32 - Result<String> r = Result.locked();
33 - assertFalse(r.success());
34 - assertNull(r.value());
35 - assertEquals(Result.Status.LOCKED, r.status());
36 - }
37 -
38 - @Test
39 - public void testOk() {
40 - Result<String> r = Result.ok("foo");
41 - assertTrue(r.success());
42 - assertEquals("foo", r.value());
43 - assertEquals(Result.Status.OK, r.status());
44 - }
45 -
46 - @Test
47 - public void testEquality() {
48 - Result<String> r1 = Result.ok("foo");
49 - Result<String> r2 = Result.locked();
50 - Result<String> r3 = Result.ok("bar");
51 - Result<String> r4 = Result.ok("foo");
52 - assertTrue(r1.equals(r4));
53 - assertFalse(r1.equals(r2));
54 - assertFalse(r1.equals(r3));
55 - assertFalse(r2.equals(r3));
56 - }
57 -}
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.primitives.impl;
17 -
18 -import static junit.framework.TestCase.assertEquals;
19 -import static junit.framework.TestCase.assertNull;
20 -import static junit.framework.TestCase.assertTrue;
21 -
22 -import org.junit.Test;
23 -import org.onosproject.store.service.MapEvent;
24 -import org.onosproject.store.service.Versioned;
25 -
26 -/**
27 - * Unit tests for UpdateResult.
28 - */
29 -public class UpdateResultTest {
30 -
31 - @Test
32 - public void testGetters() {
33 - Versioned<String> oldValue = new Versioned<>("a", 1);
34 - Versioned<String> newValue = new Versioned<>("b", 2);
35 - UpdateResult<String, String> ur =
36 - new UpdateResult<>(true, "foo", "k", oldValue, newValue);
37 -
38 - assertTrue(ur.updated());
39 - assertEquals("foo", ur.mapName());
40 - assertEquals("k", ur.key());
41 - assertEquals(oldValue, ur.oldValue());
42 - assertEquals(newValue, ur.newValue());
43 - }
44 -
45 - @Test
46 - public void testToMapEvent() {
47 - Versioned<String> oldValue = new Versioned<>("a", 1);
48 - Versioned<String> newValue = new Versioned<>("b", 2);
49 - UpdateResult<String, String> ur1 =
50 - new UpdateResult<>(true, "foo", "k", oldValue, newValue);
51 - MapEvent<String, String> event1 = ur1.toMapEvent();
52 - assertEquals(MapEvent.Type.UPDATE, event1.type());
53 - assertEquals("k", event1.key());
54 - assertEquals(newValue, event1.value());
55 -
56 - UpdateResult<String, String> ur2 =
57 - new UpdateResult<>(true, "foo", "k", null, newValue);
58 - MapEvent<String, String> event2 = ur2.toMapEvent();
59 - assertEquals(MapEvent.Type.INSERT, event2.type());
60 - assertEquals("k", event2.key());
61 - assertEquals(newValue, event2.value());
62 -
63 - UpdateResult<String, String> ur3 =
64 - new UpdateResult<>(true, "foo", "k", oldValue, null);
65 - MapEvent<String, String> event3 = ur3.toMapEvent();
66 - assertEquals(MapEvent.Type.REMOVE, event3.type());
67 - assertEquals("k", event3.key());
68 - assertEquals(oldValue, event3.value());
69 -
70 - UpdateResult<String, String> ur4 =
71 - new UpdateResult<>(false, "foo", "k", oldValue, oldValue);
72 - assertNull(ur4.toMapEvent());
73 - }
74 -
75 - @Test
76 - public void testMap() {
77 - Versioned<String> oldValue = new Versioned<>("a", 1);
78 - Versioned<String> newValue = new Versioned<>("b", 2);
79 - UpdateResult<String, String> ur1 =
80 - new UpdateResult<>(true, "foo", "k", oldValue, newValue);
81 - UpdateResult<Integer, Integer> ur2 = ur1.map(s -> s.length(), s -> s.length());
82 -
83 - assertEquals(ur2.updated(), ur1.updated());
84 - assertEquals(ur1.mapName(), ur2.mapName());
85 - assertEquals(new Integer(1), ur2.key());
86 - assertEquals(oldValue.map(s -> s.length()), ur2.oldValue());
87 - assertEquals(newValue.map(s -> s.length()), ur2.newValue());
88 -
89 - UpdateResult<String, String> ur3 =
90 - new UpdateResult<>(true, "foo", "k", null, newValue);
91 - UpdateResult<Integer, Integer> ur4 = ur3.map(s -> s.length(), s -> s.length());
92 -
93 - assertEquals(ur3.updated(), ur4.updated());
94 - assertEquals(ur3.mapName(), ur4.mapName());
95 - assertEquals(new Integer(1), ur4.key());
96 - assertNull(ur4.oldValue());
97 - assertEquals(newValue.map(s -> s.length()), ur4.newValue());
98 - }
99 -}
...@@ -80,8 +80,7 @@ ...@@ -80,8 +80,7 @@
80 <!-- TODO: replace with final release version when it is out --> 80 <!-- TODO: replace with final release version when it is out -->
81 <catalyst.version>1.0.6</catalyst.version> 81 <catalyst.version>1.0.6</catalyst.version>
82 <atomix.version>1.0.0-rc3</atomix.version> 82 <atomix.version>1.0.0-rc3</atomix.version>
83 - <atomix.copycat.version>1.0.0-rc6</atomix.copycat.version> 83 + <copycat.version>1.0.0-rc6</copycat.version>
84 - <copycat.version>0.5.1.onos</copycat.version>
85 <openflowj.version>0.9.3.onos-SNAPSHOT</openflowj.version> 84 <openflowj.version>0.9.3.onos-SNAPSHOT</openflowj.version>
86 <onos-maven-plugin.version>1.9</onos-maven-plugin.version> 85 <onos-maven-plugin.version>1.9</onos-maven-plugin.version>
87 <osgi.version>4.3.1</osgi.version> 86 <osgi.version>4.3.1</osgi.version>
......
...@@ -53,28 +53,15 @@ ...@@ -53,28 +53,15 @@
53 <dependency> 53 <dependency>
54 <groupId>io.atomix.copycat</groupId> 54 <groupId>io.atomix.copycat</groupId>
55 <artifactId>copycat-client</artifactId> 55 <artifactId>copycat-client</artifactId>
56 - <version>${atomix.copycat.version}</version> 56 + <version>${copycat.version}</version>
57 </dependency> 57 </dependency>
58 58
59 <dependency> 59 <dependency>
60 <groupId>io.atomix.copycat</groupId> 60 <groupId>io.atomix.copycat</groupId>
61 <artifactId>copycat-server</artifactId> 61 <artifactId>copycat-server</artifactId>
62 - <version>${atomix.copycat.version}</version>
63 - </dependency>
64 -
65 - <dependency>
66 - <!-- FIXME once fixes get merged to upstream -->
67 - <groupId>org.onosproject</groupId>
68 - <artifactId>copycat-api</artifactId>
69 <version>${copycat.version}</version> 62 <version>${copycat.version}</version>
70 </dependency> 63 </dependency>
71 64
72 - <dependency>
73 - <!-- FIXME once fixes get merged to upstream -->
74 - <groupId>org.onosproject</groupId>
75 - <artifactId>copycat-core</artifactId>
76 - <version>${copycat.version}</version>
77 - </dependency>
78 </dependencies> 65 </dependencies>
79 66
80 <build> 67 <build>
...@@ -99,16 +86,6 @@ ...@@ -99,16 +86,6 @@
99 86
100 <filters> 87 <filters>
101 <filter> 88 <filter>
102 - <artifact>org.onosproject:copycat*</artifact>
103 - <includes>
104 - <include>**</include>
105 - </includes>
106 - <excludes>
107 - <exclude>net/kuujo/copycat/**</exclude>
108 - </excludes>
109 - </filter>
110 -
111 - <filter>
112 <artifact>io.atomix:atomix-all</artifact> 89 <artifact>io.atomix:atomix-all</artifact>
113 <includes> 90 <includes>
114 <include>**</include> 91 <include>**</include>
...@@ -132,7 +109,7 @@ ...@@ -132,7 +109,7 @@
132 <configuration> 109 <configuration>
133 <instructions> 110 <instructions>
134 <Export-Package> 111 <Export-Package>
135 - net.kuujo.copycat.*;io.atomix.* 112 + io.atomix.*
136 </Export-Package> 113 </Export-Package>
137 <Import-Package> 114 <Import-Package>
138 !sun.nio.ch,!sun.misc,* 115 !sun.nio.ch,!sun.misc,*
......