/** * If merge_id is not equal to this.merge_id then discard. Else cast the view/digest to all * members of this group. */ public void handleMergeView(final MergeData data, final MergeId merge_id) { if (!matchMergeId(merge_id)) { if (log.isErrorEnabled()) log.error("merge_ids don't match (or are null); merge view discarded"); return; } // only send to our *current* members, if we have A and B being merged (we are B), then we would // *not* // receive a VIEW_ACK from A because A doesn't see us in the pre-merge view yet and discards the // view // [JGRP-700] - FLUSH: flushing should span merge // we have to send new view only to current members and we should not wait // for view acks from newly merged mebers List<Address> newViewMembers = new Vector<Address>(data.view.getMembers()); newViewMembers.removeAll(gms.members.getMembers()); gms.castViewChangeWithDest(data.view, data.digest, null, newViewMembers); // if we have flush in stack send ack back to merge coordinator if (gms.flushProtocolInStack) { Message ack = new Message(data.getSender(), null, null); ack.setFlag(Message.OOB); GMS.GmsHeader ack_hdr = new GMS.GmsHeader(GMS.GmsHeader.INSTALL_MERGE_VIEW_OK); ack.putHeader(gms.getId(), ack_hdr); gms.getDownProtocol().down(new Event(Event.MSG, ack)); } cancelMerge(merge_id); }
protected void handleViewChange(View v) { Address old_coord; List<Address> new_members = v.getMembers(); boolean send_up_exception = false; this.view = v; synchronized (members) { old_coord = (!members.isEmpty() ? members.get(0) : null); members.clear(); members.addAll(new_members); // this handles the case where a coord dies during a state transfer; prevents clients from // hanging forever // Note this only takes a coordinator crash into account, a getState(target, timeout), where // target is not // null is not handled ! (Usually we get the state from the coordinator) // http://jira.jboss.com/jira/browse/JGRP-148 if (waiting_for_state_response && old_coord != null && !members.contains(old_coord)) send_up_exception = true; } if (send_up_exception) { log.warn("%s: discovered that the state provider (%s) left", local_addr, old_coord); waiting_for_state_response = false; Exception ex = new EOFException("state provider " + old_coord + " left"); up_prot.up(new Event(Event.GET_STATE_OK, new StateTransferResult(ex))); openBarrierAndResumeStable(); } // remove non members from list of members requesting state state_requesters.retainAll(new_members); }
public void up(MessageBatch batch) { if (batch.dest() == null) { // not a unicast batch up_prot.up(batch); return; } int size = batch.size(); Map<Short, List<Message>> msgs = new TreeMap<Short, List<Message>>(); // map of messages, keyed by conn-id for (Message msg : batch) { if (msg == null || msg.isFlagSet(Message.Flag.NO_RELIABILITY)) continue; UnicastHeader hdr = (UnicastHeader) msg.getHeader(id); if (hdr == null) continue; batch.remove(msg); // remove the message from the batch, so it won't be passed up the stack if (hdr.type != UnicastHeader.DATA) { try { handleUpEvent(msg.getSrc(), hdr); } catch (Throwable t) { // we cannot let an exception terminate the processing of this batch log.error(local_addr + ": failed handling event", t); } continue; } List<Message> list = msgs.get(hdr.conn_id); if (list == null) msgs.put(hdr.conn_id, list = new ArrayList<Message>(size)); list.add(msg); } if (!msgs.isEmpty()) handleBatchReceived(batch.sender(), msgs); // process msgs: if (!batch.isEmpty()) up_prot.up(batch); }
@ManagedOperation(description = "Unlocks all currently held locks") public void unlockAll() { List<ClientLock> lock_list = new ArrayList<ClientLock>(); Collection<Map<Owner, ClientLock>> maps = client_locks.values(); for (Map<Owner, ClientLock> map : maps) lock_list.addAll(map.values()); for (ClientLock lock : lock_list) lock.unlock(); }
public static void testWriteView() throws Exception { List<Address> members = new ArrayList<>(); View v; Address a1 = Util.createRandomAddress(); Address a2 = Util.createRandomAddress(); Address a4 = Util.createRandomAddress(); ViewId vid = new ViewId(a1, 12345); members.add(a1); members.add(a2); members.add(a4); v = new View(vid, members); ByteArrayOutputStream outstream = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(outstream); Util.writeGenericStreamable(v, dos); Util.writeStreamable(v, dos); dos.close(); byte[] buf = outstream.toByteArray(); ByteArrayInputStream instream = new ByteArrayInputStream(buf); DataInputStream dis = new DataInputStream(instream); View v2 = (View) Util.readGenericStreamable(dis); Assert.assertEquals(v, v2); v2 = (View) Util.readStreamable(View.class, dis); Assert.assertEquals(v, v2); }
public List<Integer> providedUpServices() { List<Integer> ret = new ArrayList<Integer>(3); ret.add(Event.FIND_INITIAL_MBRS); ret.add(Event.FIND_ALL_VIEWS); ret.add(Event.GET_PHYSICAL_ADDRESS); return ret; }
protected List<PingData> read(InputStream in) { List<PingData> retval = null; try { while (true) { try { String name_str = Util.readToken(in); String uuid_str = Util.readToken(in); String addr_str = Util.readToken(in); String coord_str = Util.readToken(in); if (name_str == null || uuid_str == null || addr_str == null || coord_str == null) break; UUID uuid = null; try { long tmp = Long.valueOf(uuid_str); uuid = new UUID(0, tmp); } catch (Throwable t) { uuid = UUID.fromString(uuid_str); } PhysicalAddress phys_addr = new IpAddress(addr_str); boolean is_coordinator = coord_str.trim().equals("T") || coord_str.trim().equals("t"); if (retval == null) retval = new ArrayList<>(); retval.add(new PingData(uuid, true, name_str, phys_addr).coord(is_coordinator)); } catch (Throwable t) { log.error(Util.getMessage("FailedReadingLineOfInputStream"), t); } } return retval; } finally { Util.close(in); } }
/** * Disseminates cache information (UUID/IP adddress/port/name) to the given members * * @param current_mbrs The current members. Guaranteed to be non-null. This is a copy and can be * modified. * @param left_mbrs The members which left. These are excluded from dissemination. Can be null if * no members left * @param new_mbrs The new members that we need to disseminate the information to. Will be all * members if null. */ protected void disseminateDiscoveryInformation( List current_mbrs, List<Address> left_mbrs, List<Address> new_mbrs) { if (new_mbrs == null || new_mbrs.isEmpty()) return; if (local_addr != null) current_mbrs.remove(local_addr); if (left_mbrs != null) current_mbrs.removeAll(left_mbrs); // 1. Send information about <everyone - self - left_mbrs> to new_mbrs Set<Address> info = new HashSet<>(current_mbrs); for (Address addr : info) { PhysicalAddress phys_addr = (PhysicalAddress) down_prot.down(new Event(Event.GET_PHYSICAL_ADDRESS, addr)); if (phys_addr == null) continue; boolean is_coordinator = isCoord(addr); for (Address target : new_mbrs) sendDiscoveryResponse(addr, phys_addr, UUID.get(addr), target, is_coordinator); } // 2. Send information about new_mbrs to <everyone - self - left_mbrs - new_mbrs> Set<Address> targets = new HashSet<>(current_mbrs); targets.removeAll(new_mbrs); if (!targets.isEmpty()) { for (Address addr : new_mbrs) { PhysicalAddress phys_addr = (PhysicalAddress) down_prot.down(new Event(Event.GET_PHYSICAL_ADDRESS, addr)); if (phys_addr == null) continue; boolean is_coordinator = isCoord(addr); for (Address target : targets) sendDiscoveryResponse(addr, phys_addr, UUID.get(addr), target, is_coordinator); } } }
/** * Tests A|6, A|7, A|8 and B|7, B|8, B|9 -> we should have a subviews in MergeView consisting of * only 2 elements: A|5 and B|5 */ public void testMultipleViewsBySameMembers() throws Exception { View a1 = View.create( a.getAddress(), 6, a.getAddress(), b.getAddress(), c.getAddress(), d.getAddress()); // {A,B,C,D} View a2 = View.create(a.getAddress(), 7, a.getAddress(), b.getAddress(), c.getAddress()); // {A,B,C} View a3 = View.create(a.getAddress(), 8, a.getAddress(), b.getAddress()); // {A,B} View a4 = View.create(a.getAddress(), 9, a.getAddress()); // {A} View b1 = View.create(b.getAddress(), 7, b.getAddress(), c.getAddress(), d.getAddress()); View b2 = View.create(b.getAddress(), 8, b.getAddress(), c.getAddress()); View b3 = View.create(b.getAddress(), 9, b.getAddress()); Util.close(c, d); // not interested in those... // A and B cannot communicate: discard(true, a, b); // inject view A|6={A} into A and B|5={B} into B injectView(a4, a); injectView(b3, b); assert a.getView().equals(a4); assert b.getView().equals(b3); List<Event> merge_events = new ArrayList<>(); for (View view : Arrays.asList(a3, a4, a2, a1)) { MERGE3.MergeHeader hdr = MERGE3.MergeHeader.createInfo(view.getViewId(), null, null); Message msg = new Message(null, a.getAddress(), null).putHeader(merge_id, hdr); merge_events.add(new Event(Event.MSG, msg)); } for (View view : Arrays.asList(b2, b3, b1)) { MERGE3.MergeHeader hdr = MERGE3.MergeHeader.createInfo(view.getViewId(), null, null); Message msg = new Message(null, b.getAddress(), null).putHeader(merge_id, hdr); merge_events.add(new Event(Event.MSG, msg)); } // A and B can communicate again discard(false, a, b); injectMergeEvents(merge_events, a, b); checkInconsistencies(a, b); // merge will happen between A and B Util.waitUntilAllChannelsHaveSameSize(10000, 500, a, b); System.out.println("A's view: " + a.getView() + "\nB's view: " + b.getView()); assert a.getView().size() == 2; assert a.getView().containsMember(a.getAddress()); assert a.getView().containsMember(b.getAddress()); assert a.getView().equals(b.getView()); for (View merge_view : Arrays.asList(getViewFromGMS(a), getViewFromGMS(b))) { System.out.println(merge_view); assert merge_view instanceof MergeView; List<View> subviews = ((MergeView) merge_view).getSubgroups(); assert subviews.size() == 2; } }
public static void testNewMembers() { final Address a = Util.createRandomAddress(), b = Util.createRandomAddress(), c = Util.createRandomAddress(), d = Util.createRandomAddress(), e = Util.createRandomAddress(); List<Address> old = new ArrayList<>(); List<Address> new_list = new ArrayList<>(); old.add(a); old.add(b); old.add(c); new_list.add(b); new_list.add(a); new_list.add(c); new_list.add(d); new_list.add(e); System.out.println("old: " + old); System.out.println("new: " + new_list); List<Address> new_nodes = Util.newMembers(old, new_list); System.out.println("new_nodes = " + new_nodes); assert new_nodes.size() == 2 : "list should have d and e"; assert new_nodes.contains(d); assert new_nodes.contains(e); }
/** * An event is to be sent down the stack. The layer may want to examine its type and perform some * action on it, depending on the event's type. If the event is a message MSG, then the layer may * need to add a header to it (or do nothing at all) before sending it down the stack using <code> * PassDown</code>. In case of a GET_ADDRESS event (which tries to retrieve the stack's address * from one of the bottom layers), the layer may need to send a new response event back up the * stack using <code>up_prot.up()</code>. The PING protocol is interested in several different * down events, Event.FIND_INITIAL_MBRS - sent by the GMS layer and expecting a GET_MBRS_OK * Event.TMP_VIEW and Event.VIEW_CHANGE - a view change event Event.BECOME_SERVER - called after * client has joined and is fully working group member Event.CONNECT, Event.DISCONNECT. */ @SuppressWarnings("unchecked") public Object down(Event evt) { switch (evt.getType()) { case Event.FIND_INITIAL_MBRS: // sent by GMS layer case Event.FIND_ALL_VIEWS: // sends the GET_MBRS_REQ to all members, waits 'timeout' ms or until 'num_initial_members' // have been retrieved long start = System.currentTimeMillis(); boolean find_all_views = evt.getType() == Event.FIND_ALL_VIEWS; Promise<JoinRsp> promise = (Promise<JoinRsp>) evt.getArg(); List<PingData> rsps = find_all_views ? findAllViews(promise) : findInitialMembers(promise); long diff = System.currentTimeMillis() - start; if (log.isTraceEnabled()) log.trace("discovery took " + diff + " ms: responses: " + Util.printPingData(rsps)); return rsps; case Event.TMP_VIEW: case Event.VIEW_CHANGE: List<Address> tmp; view = (View) evt.getArg(); if ((tmp = view.getMembers()) != null) { synchronized (members) { members.clear(); members.addAll(tmp); } } current_coord = !members.isEmpty() ? members.get(0) : null; is_coord = current_coord != null && local_addr != null && current_coord.equals(local_addr); return down_prot.down(evt); case Event.BECOME_SERVER: // called after client has joined and is fully working group member down_prot.down(evt); is_server = true; return null; case Event.SET_LOCAL_ADDRESS: local_addr = (Address) evt.getArg(); return down_prot.down(evt); case Event.CONNECT: case Event.CONNECT_WITH_STATE_TRANSFER: case Event.CONNECT_USE_FLUSH: case Event.CONNECT_WITH_STATE_TRANSFER_USE_FLUSH: is_leaving = false; group_addr = (String) evt.getArg(); Object ret = down_prot.down(evt); handleConnect(); return ret; case Event.DISCONNECT: is_leaving = true; handleDisconnect(); return down_prot.down(evt); default: return down_prot.down(evt); // Pass on to the layer below us } }
public String dumpQueue() { StringBuilder sb = new StringBuilder(); List v = queue.values(); for (Iterator it = v.iterator(); it.hasNext(); ) { sb.append(it.next() + "\n"); } return sb.toString(); }
public static void testParseSemicolonDelimitedString2() { String input = " myID1::subID1 ; myID2::mySubID2; myID3 ;myID4::blaSubID4"; List list = Util.parseStringList(input, ";"); System.out.println("list: " + list); Assert.assertEquals(4, list.size()); Assert.assertEquals("myID1::subID1", list.get(0)); Assert.assertEquals("myID4::blaSubID4", list.get(list.size() - 1)); }
public static void testParseSemicolonDelimitedString() { String input = "one;two ; three; four ; five;six"; List list = Util.parseStringList(input, ";"); System.out.println("list: " + list); Assert.assertEquals(6, list.size()); Assert.assertEquals("one", list.get(0)); Assert.assertEquals("six", list.get(list.size() - 1)); }
public static void testParseCommaDelimitedString() { String input = "1,2,3,4,5,6,7,8,9,10 , 11, 12 ,13"; List list = Util.parseCommaDelimitedStrings(input); System.out.println("list: " + list); Assert.assertEquals(13, list.size()); Assert.assertEquals("1", list.get(0)); Assert.assertEquals("13", list.get(list.size() - 1)); }
/** * Add a new channel listener to be notified on the channel's state change. * * @return true if the listener was added or false if the listener was already in the list. */ public boolean addChannelListener(ChannelListener l) { synchronized (additionalChannelListeners) { if (additionalChannelListeners.contains(l)) { return false; } additionalChannelListeners.add(l); return true; } }
public void testMergeWithAsymetricViewsCoordIsolated() { // Isolate the coord Address coord = a.getView().getCreator(); System.out.println("Isolating coord: " + coord); List<Address> members = new ArrayList<>(); members.add(coord); View coord_view = new View(coord, 4, members); System.out.println("coord_view: " + coord_view); Channel coord_channel = findChannel(coord); System.out.println("coord_channel: " + coord_channel.getAddress()); MutableDigest digest = new MutableDigest(coord_view.getMembersRaw()); NAKACK2 nakack = (NAKACK2) coord_channel.getProtocolStack().findProtocol(NAKACK2.class); digest.merge(nakack.getDigest(coord)); GMS gms = (GMS) coord_channel.getProtocolStack().findProtocol(GMS.class); gms.installView(coord_view, digest); System.out.println("gms.getView() " + gms.getView()); System.out.println("Views are:"); for (JChannel ch : Arrays.asList(a, b, c, d)) System.out.println(ch.getAddress() + ": " + ch.getView()); JChannel merge_leader = findChannel(coord); MyReceiver receiver = new MyReceiver(); merge_leader.setReceiver(receiver); System.out.println("merge_leader: " + merge_leader.getAddressAsString()); System.out.println("Injecting MERGE event into merge leader " + merge_leader.getAddress()); Map<Address, View> merge_views = new HashMap<>(4); merge_views.put(a.getAddress(), a.getView()); merge_views.put(b.getAddress(), b.getView()); merge_views.put(c.getAddress(), c.getView()); merge_views.put(d.getAddress(), d.getView()); gms = (GMS) merge_leader.getProtocolStack().findProtocol(GMS.class); gms.up(new Event(Event.MERGE, merge_views)); Util.waitUntilAllChannelsHaveSameSize(10000, 1000, a, b, c, d); System.out.println("Views are:"); for (JChannel ch : Arrays.asList(a, b, c, d)) { View view = ch.getView(); System.out.println(ch.getAddress() + ": " + view); assert view.size() == 4; } MergeView merge_view = receiver.getView(); System.out.println("merge_view = " + merge_view); assert merge_view.size() == 4; assert merge_view.getSubgroups().size() == 2; for (View view : merge_view.getSubgroups()) assert contains(view, a.getAddress()) || contains(view, b.getAddress(), c.getAddress(), d.getAddress()); }
@ManagedOperation(description = "Runs the discovery protocol to find initial members") public String findInitialMembersAsString() { List<PingData> results = findInitialMembers(null); if (results == null || results.isEmpty()) return "<empty>"; StringBuilder sb = new StringBuilder(); for (PingData rsp : results) { sb.append(rsp).append("\n"); } return sb.toString(); }
public static void testAll() { List<String> l = new ArrayList<>(); l.add("one"); l.add("two"); l.add("one"); System.out.println("-- list is " + l); assert !(Util.all(l, "one")); l.remove("two"); System.out.println("-- list is " + l); assert Util.all(l, "one"); }
@ManagedOperation(description = "Runs the discovery protocol to find all views") public String findAllViewsAsString() { List<PingData> rsps = findAllViews(null); if (rsps == null || rsps.isEmpty()) return "<empty>"; StringBuilder sb = new StringBuilder(); for (PingData data : rsps) { View v = data.getView(); if (v != null) sb.append(v).append("\n"); } return sb.toString(); }
protected void processQueue() { if (current_owner == null) { while (!queue.isEmpty()) { Request req = queue.remove(0); if (req.type == Type.GRANT_LOCK) { setOwner(req.owner); sendLockResponse(Type.LOCK_GRANTED, req.owner, req.lock_name); break; } } } }
public static void testPickRandomElement() { List<Integer> v = new ArrayList<>(); for (int i = 0; i < 10; i++) { v.add(i); } Integer el; for (int i = 0; i < 10000; i++) { el = Util.pickRandomElement(v); assert el >= 0 && el < 10; } }
protected void _handleMergeRequest( Address sender, MergeId merge_id, Collection<? extends Address> mbrs) throws Exception { boolean success = matchMergeId(merge_id) || setMergeId(null, merge_id); if (!success) throw new Exception( "merge " + this.merge_id + " is already in progress, received merge-id=" + merge_id); /* Clears the view handler queue and discards all JOIN/LEAVE/MERGE requests until after the MERGE */ // gms.getViewHandler().suspend(); if (log.isTraceEnabled()) log.trace( gms.local_addr + ": got merge request from " + sender + ", merge_id=" + merge_id + ", mbrs=" + mbrs); // merge the membership of the current view with mbrs List<Address> members = new LinkedList<Address>(); if (mbrs != null) { // didn't use a set because we didn't want to change the membership order at this // time (although not incorrect) for (Address mbr : mbrs) { if (!members.contains(mbr)) members.add(mbr); } } ViewId tmp_vid = gms.getViewId(); if (tmp_vid != null) tmp_vid = tmp_vid.copy(); if (tmp_vid == null) throw new Exception("view ID is null; cannot return merge response"); View view = new View(tmp_vid, new ArrayList<Address>(members)); // [JGRP-524] - FLUSH and merge: flush doesn't wrap entire merge process // [JGRP-770] - Concurrent startup of many channels doesn't stabilize // [JGRP-700] - FLUSH: flushing should span merge /*if flush is in stack, let this coordinator flush its cluster island */ if (gms.flushProtocolInStack && !gms.startFlush(view)) throw new Exception("flush failed"); // we still need to fetch digests from all members, and not just return our own digest // (https://issues.jboss.org/browse/JGRP-948) Digest digest = fetchDigestsFromAllMembersInSubPartition(members, merge_id); if (digest == null || digest.size() == 0) throw new Exception( "failed fetching digests from subpartition members; dropping merge response"); sendMergeResponse(sender, view, digest, merge_id); }
public static void testReadLine() throws IOException { final String input = " hello world\nthis is \r\n just an example\r\nthis is line 2 \r\n"; String line; InputStream in = new BufferedInputStream(new ByteArrayInputStream(input.getBytes())); List<String> list = new ArrayList<>(4); for (int i = 0; i < 4; i++) { line = Util.readLine(in); System.out.println("line = \"" + line + "\""); list.add(line); } assert list.size() == 4; }
private void send(Address dest) throws Exception { final CountDownLatch latch = new CountDownLatch(1); final BlockingReceiver receiver = new BlockingReceiver(latch); final int NUM = 10; b.setReceiver(receiver); a.send(dest, 1); // the only regular message for (int i = 2; i <= NUM; i++) a.send(new Message(dest, i).setFlag(Message.Flag.OOB)); sendStableMessages(a, b); List<Integer> list = receiver.getMsgs(); for (int i = 0; i < 20; i++) { if (list.size() == NUM - 1) break; sendStableMessages(a, b); Util.sleep(500); // give the asynchronous msgs some time to be received } System.out.println("list = " + list); assert list.size() == NUM - 1 : "list is " + list; assert list.contains(2) && list.contains(10); System.out.println("[" + Thread.currentThread().getName() + "]: releasing latch"); latch.countDown(); for (int i = 0; i < 20; i++) { if (list.size() == NUM) break; sendStableMessages(a, b); Util.sleep(1000); // give the asynchronous msgs some time to be received } System.out.println("list = " + list); assert list.size() == NUM : "list is " + list; for (int i = 1; i <= NUM; i++) assert list.contains(i); }
/** * Creates a list of randomly generated partitions, each having a max size of max_partition_size */ protected List<View> createPartitions(int max_partition_size, JChannel... channels) { long view_id = 1; for (JChannel ch : channels) view_id = Math.max(view_id, ch.getView().getViewId().getId()); List<View> partitions = new ArrayList<>(); List<Address> tmp = new ArrayList<>(); for (JChannel ch : channels) tmp.add(ch.getAddress()); while (!tmp.isEmpty()) { int num_to_remove = (int) Util.random(max_partition_size); List<Address> part = new ArrayList<>(max_partition_size); for (int x = 0; x < num_to_remove && !tmp.isEmpty(); x++) part.add(tmp.remove(0)); partitions.add(new View(part.get(0), view_id + 1, part)); } return partitions; }
protected String printMessageList(List<Message> list) { StringBuilder sb = new StringBuilder(); int size = list.size(); Message first = size > 0 ? list.get(0) : null, second = size > 1 ? list.get(size - 1) : first; UnicastHeader hdr; if (first != null) { hdr = (UnicastHeader) first.getHeader(id); if (hdr != null) sb.append("#" + hdr.seqno); } if (second != null) { hdr = (UnicastHeader) second.getHeader(id); if (hdr != null) sb.append(" - #" + hdr.seqno); } return sb.toString(); }
public List<PingData> get(long timeout) throws InterruptedException { long start_time = System.currentTimeMillis(), time_to_wait = timeout; promise.getLock().lock(); try { while (time_to_wait > 0 && !promise.hasResult()) { // if num_expected_srv_rsps > 0, then it overrides num_expected_rsps if (num_expected_srv_rsps > 0) { int received_srv_rsps = getNumServerResponses(ping_rsps); if (received_srv_rsps >= num_expected_srv_rsps) return new LinkedList<PingData>(ping_rsps); } else if (ping_rsps.size() >= num_expected_rsps) { return new LinkedList<PingData>(ping_rsps); } if (break_on_coord_rsp && containsCoordinatorResponse(ping_rsps)) return new LinkedList<PingData>(ping_rsps); promise.getCond().await(time_to_wait, TimeUnit.MILLISECONDS); time_to_wait = timeout - (System.currentTimeMillis() - start_time); } return new LinkedList<PingData>(ping_rsps); } finally { promise.getLock().unlock(); } }
public Responses findMembers( final List<Address> members, final boolean initial_discovery, boolean async) { num_discovery_requests++; int num_expected = members != null ? members.size() : 0; int capacity = members != null ? members.size() : 16; final Responses rsps = new Responses(num_expected, initial_discovery && break_on_coord_rsp, capacity); synchronized (ping_responses) { ping_responses.put(System.nanoTime(), rsps); } if (async || async_discovery) timer.execute(() -> findMembers(members, initial_discovery, rsps)); else findMembers(members, initial_discovery, rsps); weedOutCompletedDiscoveryResponses(); return rsps; }
public static void testPickNext() { List<Integer> list = new ArrayList<>(10); for (int i = 0; i < 10; i++) list.add(i); Integer num = Util.pickNext(list, 5); System.out.println("number next to 5: " + num); assert num != null; assert num.equals(6); num = Util.pickNext(list, 9); System.out.println("number next to 9: " + num); assert num != null; assert num.equals(0); num = Util.pickNext(list, 11); assert num == null; }