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 | -} |
core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/Database.java
deleted
100644 → 0
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 | -} |
core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/DatabaseProxy.java
deleted
100644 → 0
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 |
core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/DatabaseState.java
deleted
100644 → 0
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 | -} |
core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/MappingSet.java
deleted
100644 → 0
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 | - |
core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/Partitioner.java
deleted
100644 → 0
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 | -} |
core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/Result.java
deleted
100644 → 0
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 | -} |
core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/UpdateResult.java
deleted
100644 → 0
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 | -} |
core/store/primitives/src/test/java/org/onosproject/store/primitives/impl/ResultTest.java
deleted
100644 → 0
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,* | ... | ... |
-
Please register or login to post a comment