Added ability to properly register/deregister new connections and have the node …
…status properly reflected.
Showing
5 changed files
with
59 additions
and
28 deletions
| ... | @@ -233,7 +233,7 @@ public class IOLoopTestClient { | ... | @@ -233,7 +233,7 @@ public class IOLoopTestClient { |
| 233 | } | 233 | } |
| 234 | 234 | ||
| 235 | @Override | 235 | @Override |
| 236 | - protected void connect(SelectionKey key) { | 236 | + protected void connect(SelectionKey key) throws IOException { |
| 237 | super.connect(key); | 237 | super.connect(key); |
| 238 | TestMessageStream b = (TestMessageStream) key.attachment(); | 238 | TestMessageStream b = (TestMessageStream) key.attachment(); |
| 239 | Worker w = ((CustomIOLoop) b.loop()).worker; | 239 | Worker w = ((CustomIOLoop) b.loop()).worker; | ... | ... |
| ... | @@ -30,6 +30,7 @@ import java.nio.channels.SocketChannel; | ... | @@ -30,6 +30,7 @@ import java.nio.channels.SocketChannel; |
| 30 | import java.util.ArrayList; | 30 | import java.util.ArrayList; |
| 31 | import java.util.List; | 31 | import java.util.List; |
| 32 | import java.util.Map; | 32 | import java.util.Map; |
| 33 | +import java.util.Objects; | ||
| 33 | import java.util.Set; | 34 | import java.util.Set; |
| 34 | import java.util.Timer; | 35 | import java.util.Timer; |
| 35 | import java.util.TimerTask; | 36 | import java.util.TimerTask; |
| ... | @@ -129,6 +130,7 @@ public class DistributedClusterStore | ... | @@ -129,6 +130,7 @@ public class DistributedClusterStore |
| 129 | if (self == null) { | 130 | if (self == null) { |
| 130 | self = new DefaultControllerNode(new NodeId(ip.toString()), ip); | 131 | self = new DefaultControllerNode(new NodeId(ip.toString()), ip); |
| 131 | nodes.put(self.id(), self); | 132 | nodes.put(self.id(), self); |
| 133 | + states.put(self.id(), State.ACTIVE); | ||
| 132 | } | 134 | } |
| 133 | } | 135 | } |
| 134 | 136 | ||
| ... | @@ -219,7 +221,10 @@ public class DistributedClusterStore | ... | @@ -219,7 +221,10 @@ public class DistributedClusterStore |
| 219 | @Override | 221 | @Override |
| 220 | public void removeNode(NodeId nodeId) { | 222 | public void removeNode(NodeId nodeId) { |
| 221 | nodes.remove(nodeId); | 223 | nodes.remove(nodeId); |
| 222 | - streams.remove(nodeId); | 224 | + TLVMessageStream stream = streams.remove(nodeId); |
| 225 | + if (stream != null) { | ||
| 226 | + stream.close(); | ||
| 227 | + } | ||
| 223 | } | 228 | } |
| 224 | 229 | ||
| 225 | // Listens and accepts inbound connections from other cluster nodes. | 230 | // Listens and accepts inbound connections from other cluster nodes. |
| ... | @@ -256,12 +261,13 @@ public class DistributedClusterStore | ... | @@ -256,12 +261,13 @@ public class DistributedClusterStore |
| 256 | protected void processMessages(List<TLVMessage> messages, MessageStream<TLVMessage> stream) { | 261 | protected void processMessages(List<TLVMessage> messages, MessageStream<TLVMessage> stream) { |
| 257 | TLVMessageStream tlvStream = (TLVMessageStream) stream; | 262 | TLVMessageStream tlvStream = (TLVMessageStream) stream; |
| 258 | for (TLVMessage message : messages) { | 263 | for (TLVMessage message : messages) { |
| 259 | - // TODO: add type-based dispatching here... | 264 | + // TODO: add type-based dispatching here... this is just a hack to get going |
| 260 | - log.info("Got message {}", message.type()); | ||
| 261 | - | ||
| 262 | - // FIXME: hack to get going | ||
| 263 | if (message.type() == HELLO_MSG) { | 265 | if (message.type() == HELLO_MSG) { |
| 264 | processHello(message, tlvStream); | 266 | processHello(message, tlvStream); |
| 267 | + } else if (message.type() == ECHO_MSG) { | ||
| 268 | + processEcho(message, tlvStream); | ||
| 269 | + } else { | ||
| 270 | + log.info("Deal with other messages"); | ||
| 265 | } | 271 | } |
| 266 | } | 272 | } |
| 267 | } | 273 | } |
| ... | @@ -271,7 +277,7 @@ public class DistributedClusterStore | ... | @@ -271,7 +277,7 @@ public class DistributedClusterStore |
| 271 | TLVMessageStream stream = super.acceptStream(channel); | 277 | TLVMessageStream stream = super.acceptStream(channel); |
| 272 | try { | 278 | try { |
| 273 | InetSocketAddress sa = (InetSocketAddress) channel.getRemoteAddress(); | 279 | InetSocketAddress sa = (InetSocketAddress) channel.getRemoteAddress(); |
| 274 | - log.info("Accepted a new connection from node {}", IpPrefix.valueOf(sa.getAddress().getAddress())); | 280 | + log.info("Accepted connection from node {}", valueOf(sa.getAddress().getAddress())); |
| 275 | stream.write(createHello(self)); | 281 | stream.write(createHello(self)); |
| 276 | 282 | ||
| 277 | } catch (IOException e) { | 283 | } catch (IOException e) { |
| ... | @@ -285,31 +291,55 @@ public class DistributedClusterStore | ... | @@ -285,31 +291,55 @@ public class DistributedClusterStore |
| 285 | TLVMessageStream stream = super.connectStream(channel); | 291 | TLVMessageStream stream = super.connectStream(channel); |
| 286 | DefaultControllerNode node = nodesByChannel.get(channel); | 292 | DefaultControllerNode node = nodesByChannel.get(channel); |
| 287 | if (node != null) { | 293 | if (node != null) { |
| 288 | - log.info("Opened connection to node {}", node.id()); | 294 | + log.debug("Opened connection to node {}", node.id()); |
| 289 | nodesByChannel.remove(channel); | 295 | nodesByChannel.remove(channel); |
| 290 | } | 296 | } |
| 291 | return stream; | 297 | return stream; |
| 292 | } | 298 | } |
| 293 | 299 | ||
| 294 | @Override | 300 | @Override |
| 295 | - protected void connect(SelectionKey key) { | 301 | + protected void connect(SelectionKey key) throws IOException { |
| 296 | - super.connect(key); | 302 | + try { |
| 297 | - TLVMessageStream stream = (TLVMessageStream) key.attachment(); | 303 | + super.connect(key); |
| 298 | - send(stream, createHello(self)); | 304 | + TLVMessageStream stream = (TLVMessageStream) key.attachment(); |
| 305 | + send(stream, createHello(self)); | ||
| 306 | + } catch (IOException e) { | ||
| 307 | + if (!Objects.equals(e.getMessage(), "Connection refused")) { | ||
| 308 | + throw e; | ||
| 309 | + } | ||
| 310 | + } | ||
| 311 | + } | ||
| 312 | + | ||
| 313 | + @Override | ||
| 314 | + protected void removeStream(MessageStream<TLVMessage> stream) { | ||
| 315 | + DefaultControllerNode node = ((TLVMessageStream) stream).node(); | ||
| 316 | + if (node != null) { | ||
| 317 | + log.info("Closed connection to node {}", node.id()); | ||
| 318 | + states.put(node.id(), State.INACTIVE); | ||
| 319 | + streams.remove(node.id()); | ||
| 320 | + } | ||
| 321 | + super.removeStream(stream); | ||
| 299 | } | 322 | } |
| 300 | } | 323 | } |
| 301 | 324 | ||
| 302 | - // FIXME: pure hack for now | 325 | + // Processes a HELLO message from a peer controller node. |
| 303 | private void processHello(TLVMessage message, TLVMessageStream stream) { | 326 | private void processHello(TLVMessage message, TLVMessageStream stream) { |
| 327 | + // FIXME: pure hack for now | ||
| 304 | String data = new String(message.data()); | 328 | String data = new String(message.data()); |
| 305 | - log.info("Processing hello with data [{}]", data); | 329 | + String[] fields = data.split(":"); |
| 306 | - String[] fields = new String(data).split(":"); | ||
| 307 | DefaultControllerNode node = new DefaultControllerNode(new NodeId(fields[0]), | 330 | DefaultControllerNode node = new DefaultControllerNode(new NodeId(fields[0]), |
| 308 | - IpPrefix.valueOf(fields[1]), | 331 | + valueOf(fields[1]), |
| 309 | Integer.parseInt(fields[2])); | 332 | Integer.parseInt(fields[2])); |
| 310 | stream.setNode(node); | 333 | stream.setNode(node); |
| 311 | nodes.put(node.id(), node); | 334 | nodes.put(node.id(), node); |
| 312 | streams.put(node.id(), stream); | 335 | streams.put(node.id(), stream); |
| 336 | + states.put(node.id(), State.ACTIVE); | ||
| 337 | + } | ||
| 338 | + | ||
| 339 | + // Processes an ECHO message from a peer controller node. | ||
| 340 | + private void processEcho(TLVMessage message, TLVMessageStream tlvStream) { | ||
| 341 | + // TODO: implement heart-beat refresh | ||
| 342 | + log.info("Dealing with echoes..."); | ||
| 313 | } | 343 | } |
| 314 | 344 | ||
| 315 | // Sends message to the specified stream. | 345 | // Sends message to the specified stream. |
| ... | @@ -321,6 +351,7 @@ public class DistributedClusterStore | ... | @@ -321,6 +351,7 @@ public class DistributedClusterStore |
| 321 | } | 351 | } |
| 322 | } | 352 | } |
| 323 | 353 | ||
| 354 | + // Creates a hello message to be sent to a peer controller node. | ||
| 324 | private TLVMessage createHello(DefaultControllerNode self) { | 355 | private TLVMessage createHello(DefaultControllerNode self) { |
| 325 | return new TLVMessage(HELLO_MSG, (self.id() + ":" + self.ip() + ":" + self.tcpPort()).getBytes()); | 356 | return new TLVMessage(HELLO_MSG, (self.id() + ":" + self.ip() + ":" + self.tcpPort()).getBytes()); |
| 326 | } | 357 | } |
| ... | @@ -335,7 +366,7 @@ public class DistributedClusterStore | ... | @@ -335,7 +366,7 @@ public class DistributedClusterStore |
| 335 | try { | 366 | try { |
| 336 | openConnection(node, findLeastUtilizedLoop()); | 367 | openConnection(node, findLeastUtilizedLoop()); |
| 337 | } catch (IOException e) { | 368 | } catch (IOException e) { |
| 338 | - log.warn("Unable to connect", e); | 369 | + log.debug("Unable to connect", e); |
| 339 | } | 370 | } |
| 340 | } | 371 | } |
| 341 | } | 372 | } | ... | ... |
| ... | @@ -93,14 +93,9 @@ public abstract class IOLoop<M extends Message, S extends MessageStream<M>> | ... | @@ -93,14 +93,9 @@ public abstract class IOLoop<M extends Message, S extends MessageStream<M>> |
| 93 | * | 93 | * |
| 94 | * @param key selection key holding the pending connect operation. | 94 | * @param key selection key holding the pending connect operation. |
| 95 | */ | 95 | */ |
| 96 | - protected void connect(SelectionKey key) { | 96 | + protected void connect(SelectionKey key) throws IOException { |
| 97 | - try { | 97 | + SocketChannel ch = (SocketChannel) key.channel(); |
| 98 | - SocketChannel ch = (SocketChannel) key.channel(); | 98 | + ch.finishConnect(); |
| 99 | - ch.finishConnect(); | ||
| 100 | - } catch (IOException | IllegalStateException e) { | ||
| 101 | - log.warn("Unable to complete connection", e); | ||
| 102 | - } | ||
| 103 | - | ||
| 104 | if (key.isValid()) { | 99 | if (key.isValid()) { |
| 105 | key.interestOps(SelectionKey.OP_READ); | 100 | key.interestOps(SelectionKey.OP_READ); |
| 106 | } | 101 | } |
| ... | @@ -124,7 +119,11 @@ public abstract class IOLoop<M extends Message, S extends MessageStream<M>> | ... | @@ -124,7 +119,11 @@ public abstract class IOLoop<M extends Message, S extends MessageStream<M>> |
| 124 | 119 | ||
| 125 | // If there is a pending connect operation, complete it. | 120 | // If there is a pending connect operation, complete it. |
| 126 | if (key.isConnectable()) { | 121 | if (key.isConnectable()) { |
| 127 | - connect(key); | 122 | + try { |
| 123 | + connect(key); | ||
| 124 | + } catch (IOException | IllegalStateException e) { | ||
| 125 | + log.warn("Unable to complete connection", e); | ||
| 126 | + } | ||
| 128 | } | 127 | } |
| 129 | 128 | ||
| 130 | // If there is a read operation, slurp as much data as possible. | 129 | // If there is a read operation, slurp as much data as possible. | ... | ... |
| ... | @@ -10,6 +10,7 @@ import java.nio.channels.ByteChannel; | ... | @@ -10,6 +10,7 @@ import java.nio.channels.ByteChannel; |
| 10 | import java.nio.channels.SelectionKey; | 10 | import java.nio.channels.SelectionKey; |
| 11 | import java.util.ArrayList; | 11 | import java.util.ArrayList; |
| 12 | import java.util.List; | 12 | import java.util.List; |
| 13 | +import java.util.Objects; | ||
| 13 | 14 | ||
| 14 | import static com.google.common.base.Preconditions.checkArgument; | 15 | import static com.google.common.base.Preconditions.checkArgument; |
| 15 | import static com.google.common.base.Preconditions.checkNotNull; | 16 | import static com.google.common.base.Preconditions.checkNotNull; |
| ... | @@ -262,7 +263,7 @@ public abstract class MessageStream<M extends Message> { | ... | @@ -262,7 +263,7 @@ public abstract class MessageStream<M extends Message> { |
| 262 | try { | 263 | try { |
| 263 | channel.write(outbound); | 264 | channel.write(outbound); |
| 264 | } catch (IOException e) { | 265 | } catch (IOException e) { |
| 265 | - if (!closed && !e.getMessage().equals("Broken pipe")) { | 266 | + if (!closed && !Objects.equals(e.getMessage(), "Broken pipe")) { |
| 266 | log.warn("Unable to write data", e); | 267 | log.warn("Unable to write data", e); |
| 267 | ioError = e; | 268 | ioError = e; |
| 268 | } | 269 | } | ... | ... |
| ... | @@ -230,7 +230,7 @@ public class IOLoopTestClient { | ... | @@ -230,7 +230,7 @@ public class IOLoopTestClient { |
| 230 | } | 230 | } |
| 231 | 231 | ||
| 232 | @Override | 232 | @Override |
| 233 | - protected void connect(SelectionKey key) { | 233 | + protected void connect(SelectionKey key) throws IOException { |
| 234 | super.connect(key); | 234 | super.connect(key); |
| 235 | TestMessageStream b = (TestMessageStream) key.attachment(); | 235 | TestMessageStream b = (TestMessageStream) key.attachment(); |
| 236 | Worker w = ((CustomIOLoop) b.loop()).worker; | 236 | Worker w = ((CustomIOLoop) b.loop()).worker; | ... | ... |
-
Please register or login to post a comment