blob: 2a29114296b8990732270676362ccb1af200b139 [file] [log] [blame]
Madan Jampani15b8ef52016-02-02 17:35:05 -08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Madan Jampani15b8ef52016-02-02 17:35:05 -08003 *
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 */
16package org.onosproject.store.primitives.impl;
17
Madan Jampani15b8ef52016-02-02 17:35:05 -080018import java.io.File;
19import java.util.Collection;
Jordan Halterman2bf177c2017-06-29 01:49:08 -070020import java.util.Map;
Madan Jampani15b8ef52016-02-02 17:35:05 -080021import java.util.Optional;
Madan Jampanif172d402016-03-04 00:56:38 -080022import java.util.Set;
Madan Jampani15b8ef52016-02-02 17:35:05 -080023import java.util.concurrent.CompletableFuture;
24import java.util.concurrent.atomic.AtomicBoolean;
Jordan Halterman2bf177c2017-06-29 01:49:08 -070025import java.util.function.Supplier;
Madan Jampanif172d402016-03-04 00:56:38 -080026import java.util.stream.Collectors;
Madan Jampani15b8ef52016-02-02 17:35:05 -080027
Jordan Halterman2bf177c2017-06-29 01:49:08 -070028import com.google.common.collect.Collections2;
29import com.google.common.collect.ImmutableMap;
30import io.atomix.protocols.raft.cluster.MemberId;
31import io.atomix.protocols.raft.service.RaftService;
Jordan Halterman28183ee2017-10-17 17:29:10 -070032import org.onosproject.cluster.ClusterService;
Madan Jampani15b8ef52016-02-02 17:35:05 -080033import org.onosproject.cluster.NodeId;
34import org.onosproject.cluster.Partition;
Madan Jampani33547452016-02-29 16:45:04 -080035import org.onosproject.cluster.PartitionId;
Jordan Halterman980a8c12017-09-22 18:01:19 -070036import org.onosproject.core.Version;
Jordan Halterman28183ee2017-10-17 17:29:10 -070037import org.onosproject.store.cluster.messaging.ClusterCommunicationService;
Jordan Halterman2bf177c2017-06-29 01:49:08 -070038import org.onosproject.store.primitives.resources.impl.AtomixAtomicCounterMapService;
39import org.onosproject.store.primitives.resources.impl.AtomixConsistentMapService;
40import org.onosproject.store.primitives.resources.impl.AtomixConsistentSetMultimapService;
41import org.onosproject.store.primitives.resources.impl.AtomixConsistentTreeMapService;
42import org.onosproject.store.primitives.resources.impl.AtomixCounterService;
Jordan Halterman47432582018-01-25 16:56:45 -080043import org.onosproject.store.primitives.resources.impl.AtomixDistributedLockService;
Jordan Halterman2bf177c2017-06-29 01:49:08 -070044import org.onosproject.store.primitives.resources.impl.AtomixDocumentTreeService;
45import org.onosproject.store.primitives.resources.impl.AtomixLeaderElectorService;
46import org.onosproject.store.primitives.resources.impl.AtomixWorkQueueService;
47import org.onosproject.store.service.DistributedPrimitive;
Jordan Haltermand0d80352017-08-10 15:08:27 -070048import org.onosproject.store.service.Ordering;
Madan Jampanie14a09c2016-02-11 10:43:21 -080049import org.onosproject.store.service.PartitionInfo;
Jordan Halterman2bf177c2017-06-29 01:49:08 -070050import org.onosproject.store.service.Serializer;
Madan Jampani15b8ef52016-02-02 17:35:05 -080051
52/**
53 * Storage partition.
54 */
Jordan Haltermana57a4722018-03-19 15:44:24 -070055public class StoragePartition implements Managed<StoragePartition> {
Madan Jampani15b8ef52016-02-02 17:35:05 -080056
Jordan Halterman07f052b2017-10-08 14:22:41 -070057 static final String PARTITIONS_DIR =
58 System.getProperty("karaf.data") + "/db/partitions/";
59
60 protected final AtomicBoolean isOpened = new AtomicBoolean(false);
61 protected final ClusterCommunicationService clusterCommunicator;
62 protected Partition partition;
63 protected NodeId localNodeId;
64 protected StoragePartitionServer server;
65 protected StoragePartitionClient client;
Madan Jampani15b8ef52016-02-02 17:35:05 -080066
Jordan Halterman2bf177c2017-06-29 01:49:08 -070067 public static final Map<String, Supplier<RaftService>> RAFT_SERVICES =
68 ImmutableMap.<String, Supplier<RaftService>>builder()
69 .put(DistributedPrimitive.Type.CONSISTENT_MAP.name(), AtomixConsistentMapService::new)
70 .put(DistributedPrimitive.Type.CONSISTENT_TREEMAP.name(), AtomixConsistentTreeMapService::new)
71 .put(DistributedPrimitive.Type.CONSISTENT_MULTIMAP.name(), AtomixConsistentSetMultimapService::new)
72 .put(DistributedPrimitive.Type.COUNTER_MAP.name(), AtomixAtomicCounterMapService::new)
73 .put(DistributedPrimitive.Type.COUNTER.name(), AtomixCounterService::new)
74 .put(DistributedPrimitive.Type.LEADER_ELECTOR.name(), AtomixLeaderElectorService::new)
75 .put(DistributedPrimitive.Type.WORK_QUEUE.name(), AtomixWorkQueueService::new)
Jordan Haltermand0d80352017-08-10 15:08:27 -070076 .put(DistributedPrimitive.Type.DOCUMENT_TREE.name(),
77 () -> new AtomixDocumentTreeService(Ordering.NATURAL))
78 .put(String.format("%s-%s", DistributedPrimitive.Type.DOCUMENT_TREE.name(), Ordering.NATURAL),
79 () -> new AtomixDocumentTreeService(Ordering.NATURAL))
80 .put(String.format("%s-%s", DistributedPrimitive.Type.DOCUMENT_TREE.name(), Ordering.INSERTION),
81 () -> new AtomixDocumentTreeService(Ordering.INSERTION))
Jordan Halterman47432582018-01-25 16:56:45 -080082 .put(DistributedPrimitive.Type.LOCK.name(), AtomixDistributedLockService::new)
Jordan Halterman2bf177c2017-06-29 01:49:08 -070083 .build();
Madan Jampani65f24bb2016-03-15 15:16:18 -070084
Jordan Halterman980a8c12017-09-22 18:01:19 -070085 public StoragePartition(
86 Partition partition,
Jordan Halterman28183ee2017-10-17 17:29:10 -070087 ClusterCommunicationService clusterCommunicator,
Jordan Halterman07f052b2017-10-08 14:22:41 -070088 ClusterService clusterService) {
Madan Jampani33547452016-02-29 16:45:04 -080089 this.partition = partition;
Jordan Halterman2bf177c2017-06-29 01:49:08 -070090 this.clusterCommunicator = clusterCommunicator;
Madan Jampani15b8ef52016-02-02 17:35:05 -080091 this.localNodeId = clusterService.getLocalNode().id();
Madan Jampani15b8ef52016-02-02 17:35:05 -080092 }
93
Madan Jampani3a9911c2016-02-21 11:25:45 -080094 /**
95 * Returns the partition client instance.
96 * @return client
97 */
Madan Jampani15b8ef52016-02-02 17:35:05 -080098 public StoragePartitionClient client() {
99 return client;
100 }
101
102 @Override
103 public CompletableFuture<Void> open() {
Jordan Halterman07f052b2017-10-08 14:22:41 -0700104 if (partition.getMembers().contains(localNodeId)) {
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700105 return openServer()
106 .thenCompose(v -> openClient())
107 .thenAccept(v -> isOpened.set(true))
108 .thenApply(v -> null);
Madan Jampanif172d402016-03-04 00:56:38 -0800109 }
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700110 return openClient()
111 .thenAccept(v -> isOpened.set(true))
112 .thenApply(v -> null);
Madan Jampani15b8ef52016-02-02 17:35:05 -0800113 }
114
115 @Override
116 public CompletableFuture<Void> close() {
Madan Jampani33547452016-02-29 16:45:04 -0800117 // We do not explicitly close the server and instead let the cluster
118 // deal with this as an unclean exit.
Madan Jampani65f24bb2016-03-15 15:16:18 -0700119 return closeClient();
Madan Jampani15b8ef52016-02-02 17:35:05 -0800120 }
121
Madan Jampani33547452016-02-29 16:45:04 -0800122 /**
Jordan Halterman07f052b2017-10-08 14:22:41 -0700123 * Deletes the partition.
124 *
125 * @return future to be completed once the partition has been deleted
126 */
127 public CompletableFuture<Void> delete() {
128 return closeServer().thenCompose(v -> closeClient()).thenRun(() -> deleteServer());
129 }
130
131 /**
132 * Returns the partition data folder.
133 *
134 * @return the partition data folder
135 */
Jordan Haltermana57a4722018-03-19 15:44:24 -0700136 public File getDataFolder() {
137 return new File(PARTITIONS_DIR + partition.getId());
138 }
Jordan Halterman07f052b2017-10-08 14:22:41 -0700139
140 /**
Jordan Halterman980a8c12017-09-22 18:01:19 -0700141 * Returns the partition name.
142 *
143 * @return the partition name
144 */
Jordan Haltermana57a4722018-03-19 15:44:24 -0700145 public String getName() {
146 return partition.getId().toString();
147 }
Jordan Halterman980a8c12017-09-22 18:01:19 -0700148
149 /**
Jordan Halterman07f052b2017-10-08 14:22:41 -0700150 * Returns the identifier of the {@link Partition partition} associated with this instance.
Jordan Halterman980a8c12017-09-22 18:01:19 -0700151 *
Jordan Halterman07f052b2017-10-08 14:22:41 -0700152 * @return partition identifier
Jordan Halterman980a8c12017-09-22 18:01:19 -0700153 */
Jordan Halterman07f052b2017-10-08 14:22:41 -0700154 public PartitionId getId() {
155 return partition.getId();
Jordan Halterman980a8c12017-09-22 18:01:19 -0700156 }
157
158 /**
159 * Returns the partition version.
160 *
161 * @return the partition version
162 */
163 public Version getVersion() {
Jordan Halterman07f052b2017-10-08 14:22:41 -0700164 return partition.getVersion();
Madan Jampani15b8ef52016-02-02 17:35:05 -0800165 }
166
Madan Jampani33547452016-02-29 16:45:04 -0800167 /**
168 * Returns the identifiers of partition members.
169 * @return partition member instance ids
170 */
171 public Collection<NodeId> getMembers() {
172 return partition.getMembers();
173 }
174
175 /**
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700176 * Returns the {@link MemberId identifiers} of partition members.
177 * @return partition member identifiers
Madan Jampani33547452016-02-29 16:45:04 -0800178 */
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700179 public Collection<MemberId> getMemberIds() {
Jordan Halterman07f052b2017-10-08 14:22:41 -0700180 return Collections2.transform(getMembers(), n -> MemberId.from(n.id()));
Madan Jampani33547452016-02-29 16:45:04 -0800181 }
182
Madan Jampanif172d402016-03-04 00:56:38 -0800183 /**
184 * Attempts to rejoin the partition.
185 * @return future that is completed after the operation is complete
186 */
Jordan Haltermana57a4722018-03-19 15:44:24 -0700187 protected CompletableFuture<Void> openServer() {
188 StoragePartitionServer server = new StoragePartitionServer(
189 this,
190 MemberId.from(localNodeId.id()),
191 clusterCommunicator);
192 return server.open().thenRun(() -> this.server = server);
193 }
Jordan Halterman980a8c12017-09-22 18:01:19 -0700194
195 /**
Madan Jampanif172d402016-03-04 00:56:38 -0800196 * Attempts to join the partition as a new member.
197 * @return future that is completed after the operation is complete
198 */
199 private CompletableFuture<Void> joinCluster() {
200 Set<NodeId> otherMembers = partition.getMembers()
201 .stream()
202 .filter(nodeId -> !nodeId.equals(localNodeId))
203 .collect(Collectors.toSet());
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700204 StoragePartitionServer server = new StoragePartitionServer(this,
205 MemberId.from(localNodeId.id()),
Jordan Halterman980a8c12017-09-22 18:01:19 -0700206 clusterCommunicator);
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700207 return server.join(Collections2.transform(otherMembers, n -> MemberId.from(n.id())))
208 .thenRun(() -> this.server = server);
Madan Jampanif172d402016-03-04 00:56:38 -0800209 }
210
Madan Jampani15b8ef52016-02-02 17:35:05 -0800211 private CompletableFuture<StoragePartitionClient> openClient() {
212 client = new StoragePartitionClient(this,
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700213 MemberId.from(localNodeId.id()),
214 new RaftClientCommunicator(
Jordan Halterman07f052b2017-10-08 14:22:41 -0700215 String.format("partition-%s-%s", partition.getId(), partition.getVersion()),
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700216 Serializer.using(StorageNamespaces.RAFT_PROTOCOL),
217 clusterCommunicator));
Madan Jampani15b8ef52016-02-02 17:35:05 -0800218 return client.open().thenApply(v -> client);
219 }
220
Madan Jampani33547452016-02-29 16:45:04 -0800221 /**
222 * Closes the partition server if it was previously opened.
223 * @return future that is completed when the operation completes
224 */
Madan Jampanif172d402016-03-04 00:56:38 -0800225 public CompletableFuture<Void> leaveCluster() {
Jordan Halterman07f052b2017-10-08 14:22:41 -0700226 return server != null
227 ? server.closeAndExit().thenRun(() -> server.delete())
228 : CompletableFuture.completedFuture(null);
Madan Jampani33547452016-02-29 16:45:04 -0800229 }
230
231 @Override
232 public boolean isOpen() {
Madan Jampani65f24bb2016-03-15 15:16:18 -0700233 return isOpened.get();
Madan Jampani15b8ef52016-02-02 17:35:05 -0800234 }
235
Jordan Halterman07f052b2017-10-08 14:22:41 -0700236 private CompletableFuture<Void> closeServer() {
237 if (server != null) {
238 return server.close();
239 }
240 return CompletableFuture.completedFuture(null);
241 }
242
243 private void deleteServer() {
244 if (server != null) {
245 server.delete();
246 }
247 }
248
Madan Jampani15b8ef52016-02-02 17:35:05 -0800249 private CompletableFuture<Void> closeClient() {
250 if (client != null) {
251 return client.close();
252 }
253 return CompletableFuture.completedFuture(null);
254 }
255
Madan Jampanie14a09c2016-02-11 10:43:21 -0800256 /**
257 * Returns the partition information if this partition is locally managed i.e.
258 * this node is a active member of the partition.
259 * @return partition info
260 */
261 public Optional<PartitionInfo> info() {
Madan Jampani65f24bb2016-03-15 15:16:18 -0700262 return server != null && server.isOpen() ? Optional.of(server.info()) : Optional.empty();
Madan Jampani33547452016-02-29 16:45:04 -0800263 }
264
Jon Hall1195afb2016-06-28 18:54:07 -0700265 /**
266 * Process updates to partitions and handles joining or leaving a partition.
267 * @param newValue new Partition
268 */
Jordan Halterman07f052b2017-10-08 14:22:41 -0700269 void onUpdate(Partition newValue) {
Jon Hall1195afb2016-06-28 18:54:07 -0700270 boolean wasPresent = partition.getMembers().contains(localNodeId);
271 boolean isPresent = newValue.getMembers().contains(localNodeId);
Madan Jampanif172d402016-03-04 00:56:38 -0800272 this.partition = newValue;
Jon Hall1195afb2016-06-28 18:54:07 -0700273 if ((wasPresent && isPresent) || (!wasPresent && !isPresent)) {
274 // no action needed
275 return;
276 }
Jordan Halterman07f052b2017-10-08 14:22:41 -0700277 // Only need to do action if our membership changed
Jon Hall1195afb2016-06-28 18:54:07 -0700278 if (wasPresent) {
Madan Jampanif172d402016-03-04 00:56:38 -0800279 leaveCluster();
Ray Milkeyfe0e0852018-01-18 11:14:05 -0800280 } else {
Jon Hall1195afb2016-06-28 18:54:07 -0700281 joinCluster();
Madan Jampani33547452016-02-29 16:45:04 -0800282 }
Madan Jampanie14a09c2016-02-11 10:43:21 -0800283 }
Madan Jampani15b8ef52016-02-02 17:35:05 -0800284}