Committed by
Madan Jampani
Added custom transport implementaion (for Catalyst Transport) for all copycat specific communication
Change-Id: I801d973b7c3412f6a8efcec77fe73fc480b2ce6e
Showing
9 changed files
with
657 additions
and
1 deletions
... | @@ -32,6 +32,7 @@ | ... | @@ -32,6 +32,7 @@ |
32 | <description>ONOS Core Store subsystem</description> | 32 | <description>ONOS Core Store subsystem</description> |
33 | 33 | ||
34 | <modules> | 34 | <modules> |
35 | + <module>primitives</module> | ||
35 | <module>dist</module> | 36 | <module>dist</module> |
36 | <module>persistence</module> | 37 | <module>persistence</module> |
37 | <module>serializers</module> | 38 | <module>serializers</module> | ... | ... |
core/store/primitives/pom.xml
0 → 100644
1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
2 | +<!-- | ||
3 | + ~ Copyright 2016 Open Networking Laboratory | ||
4 | + ~ | ||
5 | + ~ Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | + ~ you may not use this file except in compliance with the License. | ||
7 | + ~ You may obtain a copy of the License at | ||
8 | + ~ | ||
9 | + ~ http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | + ~ | ||
11 | + ~ Unless required by applicable law or agreed to in writing, software | ||
12 | + ~ distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | + ~ See the License for the specific language governing permissions and | ||
15 | + ~ limitations under the License. | ||
16 | + --> | ||
17 | +<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
18 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
19 | + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> | ||
20 | + <modelVersion>4.0.0</modelVersion> | ||
21 | + | ||
22 | + <parent> | ||
23 | + <groupId>org.onosproject</groupId> | ||
24 | + <artifactId>onos-core-store</artifactId> | ||
25 | + <version>1.5.0-SNAPSHOT</version> | ||
26 | + <relativePath>../pom.xml</relativePath> | ||
27 | + </parent> | ||
28 | + | ||
29 | + <artifactId>onos-core-primitives</artifactId> | ||
30 | + <packaging>bundle</packaging> | ||
31 | + | ||
32 | + <description>ONOS distributed state management primitives</description> | ||
33 | + | ||
34 | + <dependencies> | ||
35 | + | ||
36 | + <dependency> | ||
37 | + <groupId>org.onosproject</groupId> | ||
38 | + <artifactId>onos-api</artifactId> | ||
39 | + </dependency> | ||
40 | + | ||
41 | + <!-- for shaded atomix/copycat --> | ||
42 | + <dependency> | ||
43 | + <groupId>org.onosproject</groupId> | ||
44 | + <artifactId>onlab-thirdparty</artifactId> | ||
45 | + </dependency> | ||
46 | + </dependencies> | ||
47 | +</project> |
core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/CopycatTransport.java
0 → 100644
1 | +/* | ||
2 | + * Copyright 2016 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 org.onosproject.store.cluster.messaging.MessagingService; | ||
21 | + | ||
22 | +import io.atomix.catalyst.transport.Client; | ||
23 | +import io.atomix.catalyst.transport.Server; | ||
24 | +import io.atomix.catalyst.transport.Transport; | ||
25 | + | ||
26 | +/** | ||
27 | + * Custom {@link Transport transport} for Copycat interactions | ||
28 | + * built on top of {@link MessagingService}. | ||
29 | + * | ||
30 | + * @see CopycatTransportServer | ||
31 | + * @see CopycatTransportClient | ||
32 | + */ | ||
33 | +public class CopycatTransport implements Transport { | ||
34 | + | ||
35 | + /** | ||
36 | + * Transport Mode. | ||
37 | + */ | ||
38 | + public enum Mode { | ||
39 | + /** | ||
40 | + * Signifies transport for client -> server interaction. | ||
41 | + */ | ||
42 | + CLIENT, | ||
43 | + | ||
44 | + /** | ||
45 | + * Signified transport for server -> server interaction. | ||
46 | + */ | ||
47 | + SERVER | ||
48 | + } | ||
49 | + | ||
50 | + private final Mode mode; | ||
51 | + private final String clusterName; | ||
52 | + private final MessagingService messagingService; | ||
53 | + | ||
54 | + public CopycatTransport(Mode mode, String clusterName, MessagingService messagingService) { | ||
55 | + this.mode = checkNotNull(mode); | ||
56 | + this.clusterName = checkNotNull(clusterName); | ||
57 | + this.messagingService = checkNotNull(messagingService); | ||
58 | + } | ||
59 | + | ||
60 | + @Override | ||
61 | + public Client client() { | ||
62 | + return new CopycatTransportClient(clusterName, | ||
63 | + messagingService, | ||
64 | + mode); | ||
65 | + } | ||
66 | + | ||
67 | + @Override | ||
68 | + public Server server() { | ||
69 | + return new CopycatTransportServer(clusterName, | ||
70 | + messagingService); | ||
71 | + } | ||
72 | +} |
1 | +/* | ||
2 | + * Copyright 2016 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.Set; | ||
21 | +import java.util.concurrent.CompletableFuture; | ||
22 | +import org.apache.commons.lang.math.RandomUtils; | ||
23 | +import org.onosproject.store.cluster.messaging.MessagingService; | ||
24 | + | ||
25 | +import com.google.common.collect.Sets; | ||
26 | + | ||
27 | +import io.atomix.catalyst.transport.Address; | ||
28 | +import io.atomix.catalyst.transport.Client; | ||
29 | +import io.atomix.catalyst.transport.Connection; | ||
30 | +import io.atomix.catalyst.util.concurrent.ThreadContext; | ||
31 | + | ||
32 | +/** | ||
33 | + * {@link Client} implementation for {@link CopycatTransport}. | ||
34 | + */ | ||
35 | +public class CopycatTransportClient implements Client { | ||
36 | + | ||
37 | + private final String clusterName; | ||
38 | + private final MessagingService messagingService; | ||
39 | + private final CopycatTransport.Mode mode; | ||
40 | + private final ThreadContext context; | ||
41 | + private final Set<CopycatTransportConnection> connections = Sets.newConcurrentHashSet(); | ||
42 | + | ||
43 | + CopycatTransportClient(String clusterName, MessagingService messagingService, CopycatTransport.Mode mode) { | ||
44 | + this.clusterName = checkNotNull(clusterName); | ||
45 | + this.messagingService = checkNotNull(messagingService); | ||
46 | + this.mode = checkNotNull(mode); | ||
47 | + this.context = ThreadContext.currentContextOrThrow(); | ||
48 | + } | ||
49 | + | ||
50 | + @Override | ||
51 | + public CompletableFuture<Connection> connect(Address remoteAddress) { | ||
52 | + CopycatTransportConnection connection = new CopycatTransportConnection( | ||
53 | + nextConnectionId(), | ||
54 | + CopycatTransport.Mode.CLIENT, | ||
55 | + clusterName, | ||
56 | + remoteAddress, | ||
57 | + messagingService, | ||
58 | + context); | ||
59 | + if (mode == CopycatTransport.Mode.CLIENT) { | ||
60 | + connection.setBidirectional(); | ||
61 | + } | ||
62 | + connections.add(connection); | ||
63 | + return CompletableFuture.supplyAsync(() -> connection, context.executor()); | ||
64 | + } | ||
65 | + | ||
66 | + @Override | ||
67 | + public CompletableFuture<Void> close() { | ||
68 | + return CompletableFuture.allOf(connections.stream().map(Connection::close).toArray(CompletableFuture[]::new)); | ||
69 | + } | ||
70 | + | ||
71 | + private long nextConnectionId() { | ||
72 | + return RandomUtils.nextLong(); | ||
73 | + } | ||
74 | + } |
1 | +/* | ||
2 | + * Copyright 2016 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.io.ByteArrayInputStream; | ||
19 | +import java.io.ByteArrayOutputStream; | ||
20 | +import java.io.DataInputStream; | ||
21 | +import java.io.DataOutputStream; | ||
22 | +import java.io.IOException; | ||
23 | +import java.io.InputStream; | ||
24 | +import java.net.InetAddress; | ||
25 | +import java.net.UnknownHostException; | ||
26 | +import java.util.Map; | ||
27 | +import java.util.Objects; | ||
28 | +import java.util.concurrent.CompletableFuture; | ||
29 | +import java.util.concurrent.atomic.AtomicInteger; | ||
30 | +import java.util.function.Consumer; | ||
31 | + | ||
32 | +import org.apache.commons.io.IOUtils; | ||
33 | +import org.onlab.packet.IpAddress; | ||
34 | +import org.onlab.util.Tools; | ||
35 | +import org.onosproject.store.cluster.messaging.Endpoint; | ||
36 | +import org.onosproject.store.cluster.messaging.MessagingService; | ||
37 | + | ||
38 | +import com.google.common.base.MoreObjects; | ||
39 | +import com.google.common.base.Throwables; | ||
40 | +import com.google.common.collect.Maps; | ||
41 | + | ||
42 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
43 | +import io.atomix.catalyst.transport.Address; | ||
44 | +import io.atomix.catalyst.transport.Connection; | ||
45 | +import io.atomix.catalyst.transport.MessageHandler; | ||
46 | +import io.atomix.catalyst.transport.TransportException; | ||
47 | +import io.atomix.catalyst.util.Assert; | ||
48 | +import io.atomix.catalyst.util.Listener; | ||
49 | +import io.atomix.catalyst.util.Listeners; | ||
50 | +import io.atomix.catalyst.util.ReferenceCounted; | ||
51 | +import io.atomix.catalyst.util.concurrent.ThreadContext; | ||
52 | + | ||
53 | +/** | ||
54 | + * {@link Connection} implementation for CopycatTransport. | ||
55 | + */ | ||
56 | +public class CopycatTransportConnection implements Connection { | ||
57 | + | ||
58 | + private final Listeners<Throwable> exceptionListeners = new Listeners<>(); | ||
59 | + private final Listeners<Connection> closeListeners = new Listeners<>(); | ||
60 | + | ||
61 | + static final byte SUCCESS = 0x03; | ||
62 | + static final byte FAILURE = 0x04; | ||
63 | + | ||
64 | + private final long connectionId; | ||
65 | + private CopycatTransport.Mode mode; | ||
66 | + private final Address remoteAddress; | ||
67 | + private final MessagingService messagingService; | ||
68 | + private final String outboundMessageSubject; | ||
69 | + private final String inboundMessageSubject; | ||
70 | + private final ThreadContext context; | ||
71 | + private final Map<Class<?>, InternalHandler> handlers = Maps.newConcurrentMap(); | ||
72 | + private final AtomicInteger messagesSent = new AtomicInteger(0); | ||
73 | + private final AtomicInteger sendFailures = new AtomicInteger(0); | ||
74 | + private final AtomicInteger messagesReceived = new AtomicInteger(0); | ||
75 | + private final AtomicInteger receiveFailures = new AtomicInteger(0); | ||
76 | + | ||
77 | + CopycatTransportConnection(long connectionId, | ||
78 | + CopycatTransport.Mode mode, | ||
79 | + String clusterName, | ||
80 | + Address address, | ||
81 | + MessagingService messagingService, | ||
82 | + ThreadContext context) { | ||
83 | + this.connectionId = connectionId; | ||
84 | + this.mode = checkNotNull(mode); | ||
85 | + this.remoteAddress = checkNotNull(address); | ||
86 | + this.messagingService = checkNotNull(messagingService); | ||
87 | + if (mode == CopycatTransport.Mode.CLIENT) { | ||
88 | + this.outboundMessageSubject = String.format("onos-copycat-%s", clusterName); | ||
89 | + this.inboundMessageSubject = String.format("onos-copycat-%s-%d", clusterName, connectionId); | ||
90 | + } else { | ||
91 | + this.outboundMessageSubject = String.format("onos-copycat-%s-%d", clusterName, connectionId); | ||
92 | + this.inboundMessageSubject = String.format("onos-copycat-%s", clusterName); | ||
93 | + } | ||
94 | + this.context = checkNotNull(context); | ||
95 | + } | ||
96 | + | ||
97 | + public void setBidirectional() { | ||
98 | + messagingService.registerHandler(inboundMessageSubject, (sender, payload) -> { | ||
99 | + try (DataInputStream input = new DataInputStream(new ByteArrayInputStream(payload))) { | ||
100 | + if (input.readLong() != connectionId) { | ||
101 | + throw new IllegalStateException("Invalid connection Id"); | ||
102 | + } | ||
103 | + return handle(IOUtils.toByteArray(input)); | ||
104 | + } catch (IOException e) { | ||
105 | + Throwables.propagate(e); | ||
106 | + return null; | ||
107 | + } | ||
108 | + }); | ||
109 | + } | ||
110 | + | ||
111 | + @Override | ||
112 | + public <T, U> CompletableFuture<U> send(T message) { | ||
113 | + ThreadContext context = ThreadContext.currentContextOrThrow(); | ||
114 | + CompletableFuture<U> result = new CompletableFuture<>(); | ||
115 | + try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { | ||
116 | + new DataOutputStream(baos).writeLong(connectionId); | ||
117 | + context.serializer().writeObject(message, baos); | ||
118 | + if (message instanceof ReferenceCounted) { | ||
119 | + ((ReferenceCounted<?>) message).release(); | ||
120 | + } | ||
121 | + messagingService.sendAndReceive(toEndpoint(remoteAddress), | ||
122 | + outboundMessageSubject, | ||
123 | + baos.toByteArray(), | ||
124 | + context.executor()) | ||
125 | + .whenComplete((r, e) -> { | ||
126 | + if (e == null) { | ||
127 | + messagesSent.incrementAndGet(); | ||
128 | + } else { | ||
129 | + sendFailures.incrementAndGet(); | ||
130 | + } | ||
131 | + handleResponse(r, e, result, context); | ||
132 | + }); | ||
133 | + } catch (Exception e) { | ||
134 | + result.completeExceptionally(new TransportException("Failed to send request", e)); | ||
135 | + } | ||
136 | + return result; | ||
137 | + } | ||
138 | + | ||
139 | + private <T> void handleResponse(byte[] response, | ||
140 | + Throwable error, | ||
141 | + CompletableFuture<T> future, | ||
142 | + ThreadContext context) { | ||
143 | + if (error != null) { | ||
144 | + context.execute(() -> future.completeExceptionally(error)); | ||
145 | + return; | ||
146 | + } | ||
147 | + checkNotNull(response); | ||
148 | + InputStream input = new ByteArrayInputStream(response); | ||
149 | + try { | ||
150 | + byte status = (byte) input.read(); | ||
151 | + if (status == FAILURE) { | ||
152 | + Throwable t = context.serializer().readObject(input); | ||
153 | + context.execute(() -> future.completeExceptionally(t)); | ||
154 | + } else { | ||
155 | + context.execute(() -> future.complete(context.serializer().readObject(input))); | ||
156 | + } | ||
157 | + } catch (IOException e) { | ||
158 | + context.execute(() -> future.completeExceptionally(e)); | ||
159 | + } | ||
160 | + } | ||
161 | + | ||
162 | + @Override | ||
163 | + public <T, U> Connection handler(Class<T> type, MessageHandler<T, U> handler) { | ||
164 | + Assert.notNull(type, "type"); | ||
165 | + handlers.put(type, new InternalHandler(handler, ThreadContext.currentContextOrThrow())); | ||
166 | + return null; | ||
167 | + } | ||
168 | + | ||
169 | + public CompletableFuture<byte[]> handle(byte[] message) { | ||
170 | + try { | ||
171 | + Object request = context.serializer().readObject(new ByteArrayInputStream(message)); | ||
172 | + InternalHandler handler = handlers.get(request.getClass()); | ||
173 | + if (handler == null) { | ||
174 | + return Tools.exceptionalFuture(new IllegalStateException( | ||
175 | + "No handler registered for " + request.getClass())); | ||
176 | + } | ||
177 | + return handler.handle(request).handle((result, error) -> { | ||
178 | + if (error == null) { | ||
179 | + messagesReceived.incrementAndGet(); | ||
180 | + } else { | ||
181 | + receiveFailures.incrementAndGet(); | ||
182 | + } | ||
183 | + try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { | ||
184 | + baos.write(error != null ? FAILURE : SUCCESS); | ||
185 | + context.serializer().writeObject(error != null ? error : result, baos); | ||
186 | + return baos.toByteArray(); | ||
187 | + } catch (IOException e) { | ||
188 | + Throwables.propagate(e); | ||
189 | + return null; | ||
190 | + } | ||
191 | + }); | ||
192 | + } catch (Exception e) { | ||
193 | + return Tools.exceptionalFuture(e); | ||
194 | + } | ||
195 | + } | ||
196 | + | ||
197 | + @Override | ||
198 | + public Listener<Throwable> exceptionListener(Consumer<Throwable> listener) { | ||
199 | + return exceptionListeners.add(listener); | ||
200 | + } | ||
201 | + | ||
202 | + @Override | ||
203 | + public Listener<Connection> closeListener(Consumer<Connection> listener) { | ||
204 | + return closeListeners.add(listener); | ||
205 | + } | ||
206 | + | ||
207 | + @Override | ||
208 | + public CompletableFuture<Void> close() { | ||
209 | + // TODO: need to unregister message handler | ||
210 | + closeListeners.forEach(listener -> listener.accept(this)); | ||
211 | + if (mode == CopycatTransport.Mode.CLIENT) { | ||
212 | + messagingService.unregisterHandler(inboundMessageSubject); | ||
213 | + } | ||
214 | + return CompletableFuture.completedFuture(null); | ||
215 | + } | ||
216 | + | ||
217 | + @Override | ||
218 | + public int hashCode() { | ||
219 | + return Objects.hash(connectionId); | ||
220 | + } | ||
221 | + | ||
222 | + @Override | ||
223 | + public boolean equals(Object other) { | ||
224 | + if (!(other instanceof CopycatTransportConnection)) { | ||
225 | + return false; | ||
226 | + } | ||
227 | + | ||
228 | + return connectionId == ((CopycatTransportConnection) other).connectionId; | ||
229 | + } | ||
230 | + | ||
231 | + @Override | ||
232 | + public String toString() { | ||
233 | + return MoreObjects.toStringHelper(getClass()) | ||
234 | + .add("id", connectionId) | ||
235 | + .add("sent", messagesSent.get()) | ||
236 | + .add("received", messagesReceived.get()) | ||
237 | + .add("sendFailures", sendFailures.get()) | ||
238 | + .add("receiveFailures", receiveFailures.get()) | ||
239 | + .toString(); | ||
240 | + } | ||
241 | + | ||
242 | + private Endpoint toEndpoint(Address address) { | ||
243 | + try { | ||
244 | + return new Endpoint(IpAddress.valueOf(InetAddress.getByName(address.host())), address.port()); | ||
245 | + } catch (UnknownHostException e) { | ||
246 | + Throwables.propagate(e); | ||
247 | + return null; | ||
248 | + } | ||
249 | + } | ||
250 | + | ||
251 | + @SuppressWarnings("rawtypes") | ||
252 | + private final class InternalHandler { | ||
253 | + | ||
254 | + private final MessageHandler handler; | ||
255 | + private final ThreadContext context; | ||
256 | + | ||
257 | + private InternalHandler(MessageHandler handler, ThreadContext context) { | ||
258 | + this.handler = handler; | ||
259 | + this.context = context; | ||
260 | + } | ||
261 | + | ||
262 | + @SuppressWarnings("unchecked") | ||
263 | + public CompletableFuture<Object> handle(Object message) { | ||
264 | + CompletableFuture<Object> answer = new CompletableFuture<>(); | ||
265 | + context.execute(() -> handler.handle(message).whenComplete((r, e) -> { | ||
266 | + if (e != null) { | ||
267 | + answer.completeExceptionally((Throwable) e); | ||
268 | + } else { | ||
269 | + answer.complete(r); | ||
270 | + } | ||
271 | + })); | ||
272 | + return answer; | ||
273 | + } | ||
274 | + } | ||
275 | +} |
1 | +/* | ||
2 | + * Copyright 2016 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.io.ByteArrayInputStream; | ||
21 | +import java.io.DataInputStream; | ||
22 | +import java.io.IOException; | ||
23 | +import java.net.InetAddress; | ||
24 | +import java.net.InetSocketAddress; | ||
25 | +import java.util.Map; | ||
26 | +import java.util.concurrent.CompletableFuture; | ||
27 | +import java.util.concurrent.atomic.AtomicBoolean; | ||
28 | +import java.util.function.Consumer; | ||
29 | + | ||
30 | +import org.apache.commons.io.IOUtils; | ||
31 | +import org.onlab.util.Tools; | ||
32 | +import org.onosproject.store.cluster.messaging.MessagingService; | ||
33 | + | ||
34 | +import com.google.common.collect.Maps; | ||
35 | + | ||
36 | +import io.atomix.catalyst.transport.Address; | ||
37 | +import io.atomix.catalyst.transport.Connection; | ||
38 | +import io.atomix.catalyst.transport.Server; | ||
39 | +import io.atomix.catalyst.util.concurrent.SingleThreadContext; | ||
40 | +import io.atomix.catalyst.util.concurrent.ThreadContext; | ||
41 | + | ||
42 | +/** | ||
43 | + * {@link Server} implementation for {@link CopycatTransport}. | ||
44 | + */ | ||
45 | +public class CopycatTransportServer implements Server { | ||
46 | + | ||
47 | + private final AtomicBoolean listening = new AtomicBoolean(false); | ||
48 | + private CompletableFuture<Void> listenFuture; | ||
49 | + private final String clusterName; | ||
50 | + private final MessagingService messagingService; | ||
51 | + private final String messageSubject; | ||
52 | + private final Map<Long, CopycatTransportConnection> connections = Maps.newConcurrentMap(); | ||
53 | + | ||
54 | + CopycatTransportServer(String clusterName, MessagingService messagingService) { | ||
55 | + this.clusterName = checkNotNull(clusterName); | ||
56 | + this.messagingService = checkNotNull(messagingService); | ||
57 | + this.messageSubject = String.format("onos-copycat-%s", clusterName); | ||
58 | + } | ||
59 | + | ||
60 | + @Override | ||
61 | + public CompletableFuture<Void> listen(Address address, Consumer<Connection> listener) { | ||
62 | + if (listening.get()) { | ||
63 | + return CompletableFuture.completedFuture(null); | ||
64 | + } | ||
65 | + ThreadContext context = ThreadContext.currentContextOrThrow(); | ||
66 | + synchronized (this) { | ||
67 | + if (listenFuture == null) { | ||
68 | + listenFuture = new CompletableFuture<>(); | ||
69 | + listen(address, listener, context); | ||
70 | + } | ||
71 | + } | ||
72 | + return listenFuture; | ||
73 | + } | ||
74 | + | ||
75 | + public void listen(Address address, Consumer<Connection> listener, ThreadContext context) { | ||
76 | + messagingService.registerHandler(messageSubject, (sender, payload) -> { | ||
77 | + try (DataInputStream input = new DataInputStream(new ByteArrayInputStream(payload))) { | ||
78 | + long connectionId = input.readLong(); | ||
79 | + InetAddress senderHost = InetAddress.getByAddress(sender.host().toOctets()); | ||
80 | + int senderPort = sender.port(); | ||
81 | + Address senderAddress = new Address(new InetSocketAddress(senderHost, senderPort)); | ||
82 | + AtomicBoolean newConnection = new AtomicBoolean(false); | ||
83 | + CopycatTransportConnection connection = connections.computeIfAbsent(connectionId, k -> { | ||
84 | + newConnection.set(true); | ||
85 | + return new CopycatTransportConnection(connectionId, | ||
86 | + CopycatTransport.Mode.SERVER, | ||
87 | + clusterName, | ||
88 | + senderAddress, | ||
89 | + messagingService, | ||
90 | + getOrCreateContext(context)); | ||
91 | + }); | ||
92 | + byte[] request = IOUtils.toByteArray(input); | ||
93 | + return CompletableFuture.supplyAsync( | ||
94 | + () -> { | ||
95 | + if (newConnection.get()) { | ||
96 | + listener.accept(connection); | ||
97 | + } | ||
98 | + return connection; | ||
99 | + }, context.executor()).thenCompose(c -> c.handle(request)); | ||
100 | + } catch (IOException e) { | ||
101 | + return Tools.exceptionalFuture(e); | ||
102 | + } | ||
103 | + }); | ||
104 | + listening.set(true); | ||
105 | + context.execute(() -> { | ||
106 | + listenFuture.complete(null); | ||
107 | + }); | ||
108 | + } | ||
109 | + | ||
110 | + @Override | ||
111 | + public CompletableFuture<Void> close() { | ||
112 | + messagingService.unregisterHandler(messageSubject); | ||
113 | + return CompletableFuture.completedFuture(null); | ||
114 | + } | ||
115 | + | ||
116 | + /** | ||
117 | + * Returns the current execution context or creates one. | ||
118 | + */ | ||
119 | + private ThreadContext getOrCreateContext(ThreadContext parentContext) { | ||
120 | + ThreadContext context = ThreadContext.currentContext(); | ||
121 | + if (context != null) { | ||
122 | + return context; | ||
123 | + } | ||
124 | + return new SingleThreadContext("copycat-transport-server-" + clusterName, parentContext.serializer().clone()); | ||
125 | + } | ||
126 | +} |
core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/package-info.java
0 → 100644
1 | +/* | ||
2 | + * Copyright 2016 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 | +/** | ||
18 | + * Implementation for distributed state management primitives. | ||
19 | + */ | ||
20 | +package org.onosproject.store.primitives.impl; |
... | @@ -77,6 +77,8 @@ | ... | @@ -77,6 +77,8 @@ |
77 | <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | 77 | <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
78 | <onos-build-conf.version>1.1</onos-build-conf.version> | 78 | <onos-build-conf.version>1.1</onos-build-conf.version> |
79 | <netty4.version>4.0.33.Final</netty4.version> | 79 | <netty4.version>4.0.33.Final</netty4.version> |
80 | + <!-- TODO: replace with final release version when it is out --> | ||
81 | + <atomix.version>0.1.0-beta4</atomix.version> | ||
80 | <copycat.version>0.5.1.onos</copycat.version> | 82 | <copycat.version>0.5.1.onos</copycat.version> |
81 | <openflowj.version>0.9.1.onos</openflowj.version> | 83 | <openflowj.version>0.9.1.onos</openflowj.version> |
82 | <onos-maven-plugin.version>1.8-SNAPSHOT</onos-maven-plugin.version> | 84 | <onos-maven-plugin.version>1.8-SNAPSHOT</onos-maven-plugin.version> |
... | @@ -87,6 +89,7 @@ | ... | @@ -87,6 +89,7 @@ |
87 | <codehaus.jackson.version>1.9.13</codehaus.jackson.version> | 89 | <codehaus.jackson.version>1.9.13</codehaus.jackson.version> |
88 | <slf4j.version>1.7.6</slf4j.version> | 90 | <slf4j.version>1.7.6</slf4j.version> |
89 | <guava.version>19.0</guava.version> | 91 | <guava.version>19.0</guava.version> |
92 | + <commons.io.version>2.4</commons.io.version> | ||
90 | <!-- TODO argLine was originally added maven-surfire-plugin configuration | 93 | <!-- TODO argLine was originally added maven-surfire-plugin configuration |
91 | to fix locale errors for non-US developers. However, it breaks | 94 | to fix locale errors for non-US developers. However, it breaks |
92 | SonarQube's test coverage, so moving here for now. --> | 95 | SonarQube's test coverage, so moving here for now. --> | ... | ... |
... | @@ -38,6 +38,18 @@ | ... | @@ -38,6 +38,18 @@ |
38 | </dependency> | 38 | </dependency> |
39 | 39 | ||
40 | <dependency> | 40 | <dependency> |
41 | + <groupId>commons-io</groupId> | ||
42 | + <artifactId>commons-io</artifactId> | ||
43 | + <version>${commons.io.version}</version> | ||
44 | + </dependency> | ||
45 | + | ||
46 | + <dependency> | ||
47 | + <groupId>io.atomix</groupId> | ||
48 | + <artifactId>atomix</artifactId> | ||
49 | + <version>${atomix.version}</version> | ||
50 | + </dependency> | ||
51 | + | ||
52 | + <dependency> | ||
41 | <!-- FIXME once fixes get merged to upstream --> | 53 | <!-- FIXME once fixes get merged to upstream --> |
42 | <groupId>org.onosproject</groupId> | 54 | <groupId>org.onosproject</groupId> |
43 | <artifactId>copycat-api</artifactId> | 55 | <artifactId>copycat-api</artifactId> |
... | @@ -57,6 +69,7 @@ | ... | @@ -57,6 +69,7 @@ |
57 | <plugin> | 69 | <plugin> |
58 | <groupId>org.apache.maven.plugins</groupId> | 70 | <groupId>org.apache.maven.plugins</groupId> |
59 | <artifactId>maven-shade-plugin</artifactId> | 71 | <artifactId>maven-shade-plugin</artifactId> |
72 | + <version>2.4.1</version> | ||
60 | <configuration> | 73 | <configuration> |
61 | <createSourcesJar>true</createSourcesJar> | 74 | <createSourcesJar>true</createSourcesJar> |
62 | 75 | ||
... | @@ -81,13 +94,35 @@ | ... | @@ -81,13 +94,35 @@ |
81 | </filter> | 94 | </filter> |
82 | 95 | ||
83 | <filter> | 96 | <filter> |
97 | + <artifact>commons-io:commons-io</artifact> | ||
98 | + <includes> | ||
99 | + <include>org/apache/commons/io/**</include> | ||
100 | + </includes> | ||
101 | + </filter> | ||
102 | + | ||
103 | + <filter> | ||
84 | <artifact>org.onosproject:copycat*</artifact> | 104 | <artifact>org.onosproject:copycat*</artifact> |
85 | <includes> | 105 | <includes> |
86 | <include>**</include> | 106 | <include>**</include> |
87 | </includes> | 107 | </includes> |
88 | </filter> | 108 | </filter> |
89 | 109 | ||
110 | + <filter> | ||
111 | + <artifact>io.atomix:atomix-all</artifact> | ||
112 | + <includes> | ||
113 | + <include>**</include> | ||
114 | + </includes> | ||
115 | + </filter> | ||
116 | + | ||
90 | </filters> | 117 | </filters> |
118 | + <transformers> | ||
119 | + <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer"> | ||
120 | + <resource>META-INF/services/io.atomix.catalyst.serializer.CatalystSerializable</resource> | ||
121 | + </transformer> | ||
122 | + <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer"> | ||
123 | + <resource>META-INF/services/io.atomix.resource.Resource</resource> | ||
124 | + </transformer> | ||
125 | + </transformers> | ||
91 | </configuration> | 126 | </configuration> |
92 | <executions> | 127 | <executions> |
93 | <execution> | 128 | <execution> |
... | @@ -104,8 +139,11 @@ | ... | @@ -104,8 +139,11 @@ |
104 | <configuration> | 139 | <configuration> |
105 | <instructions> | 140 | <instructions> |
106 | <Export-Package> | 141 | <Export-Package> |
107 | - com.googlecode.concurrenttrees.*;net.kuujo.copycat.* | 142 | + com.googlecode.concurrenttrees.*;net.kuujo.copycat.*;io.atomix.* |
108 | </Export-Package> | 143 | </Export-Package> |
144 | + <Import-Package> | ||
145 | + !sun.nio.ch,!sun.misc,* | ||
146 | + </Import-Package> | ||
109 | </instructions> | 147 | </instructions> |
110 | </configuration> | 148 | </configuration> |
111 | </plugin> | 149 | </plugin> | ... | ... |
-
Please register or login to post a comment