/** * 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); }
/** * Processes a packet read from either the multicast or unicast socket. Needs to be synchronized * because mcast or unicast socket reads can be concurrent */ void handleIncomingUdpPacket(byte[] data) { ByteArrayInputStream inp_stream; ObjectInputStream inp; Message msg = null; List l; // used if bundling is enabled try { // skip the first n bytes (default: 4), this is the version info inp_stream = new ByteArrayInputStream(data, VERSION_LENGTH, data.length - VERSION_LENGTH); inp = new ObjectInputStream(inp_stream); if (enable_bundling) { l = new List(); l.readExternal(inp); for (Enumeration en = l.elements(); en.hasMoreElements(); ) { msg = (Message) en.nextElement(); try { handleMessage(msg); } catch (Throwable t) { Trace.error("UDP.handleIncomingUdpPacket()", "failure: " + t.toString()); } } } else { msg = new Message(); msg.readExternal(inp); handleMessage(msg); } } catch (Throwable e) { Trace.error("UDP.handleIncomingUdpPacket()", "exception=" + Trace.getStackTrace(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 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); }
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); }
protected Address generateAddress() { if (address_generators == null || address_generators.isEmpty()) return UUID.randomUUID(); if (address_generators.size() == 1) return address_generators.get(0).generateAddress(); // at this point we have multiple AddressGenerators installed Address[] addrs = new Address[address_generators.size()]; for (int i = 0; i < addrs.length; i++) addrs[i] = address_generators.get(i).generateAddress(); for (int i = 0; i < addrs.length; i++) { if (!(addrs[i] instanceof ExtendedUUID)) { log.error( "address generator %s does not subclass %s which is required if multiple address generators " + "are installed, removing it", addrs[i].getClass().getSimpleName(), ExtendedUUID.class.getSimpleName()); addrs[i] = null; } } ExtendedUUID uuid = null; for (int i = 0; i < addrs.length; i++) { // we only have ExtendedUUIDs in addrs if (addrs[i] != null) { if (uuid == null) uuid = (ExtendedUUID) addrs[i]; else uuid.addContents((ExtendedUUID) addrs[i]); } } return uuid != null ? uuid : UUID.randomUUID(); }
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; }
/** * 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); } } }
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); } }
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); }
protected final void init(ProtocolStackConfigurator configurator) throws Exception { List<ProtocolConfiguration> configs = configurator.getProtocolStack(); // replace vars with system props configs.forEach(ProtocolConfiguration::substituteVariables); prot_stack = new ProtocolStack(this); prot_stack.setup(configs); // Setup protocol stack (creates protocol, calls init() on them) }
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 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 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(); }
/** * 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 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)); }
@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(); }
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 handleViewChange(View view) { List<Address> new_mbrs = view.getMembers(); List<Address> left_mbrs = Util.determineLeftMembers(members, new_mbrs); members.clear(); members.addAll(new_mbrs); for (Address mbr : left_mbrs) { // the new view doesn't contain the sender, it must have left, // hence we will clear all of itsfragmentation tables fragment_list.remove(mbr); if (log.isTraceEnabled()) log.trace("[VIEW_CHANGE] removed " + mbr + " from fragmentation table"); } }
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(); }
String dumpMessages(HashMap map) { StringBuffer sb = new StringBuffer(); Map.Entry entry; List l; if (map != null) { synchronized (map) { for (Iterator it = map.entrySet().iterator(); it.hasNext(); ) { entry = (Map.Entry) it.next(); l = (List) entry.getValue(); sb.append(entry.getKey()).append(": "); sb.append(l.size()).append(" msgs\n"); } } } return sb.toString(); }
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; }
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; }
void bundleAndSend() { Map.Entry entry; IpAddress dest; ObjectOutputStream out; InetAddress addr; int port; byte[] data; List l; if (Trace.trace) { Trace.info( "UDP.BundlingOutgoingPacketHandler.bundleAndSend()", "\nsending msgs:\n" + dumpMessages(msgs)); } synchronized (msgs) { stopTimer(); if (msgs.size() == 0) { return; } for (Iterator it = msgs.entrySet().iterator(); it.hasNext(); ) { entry = (Map.Entry) it.next(); dest = (IpAddress) entry.getKey(); addr = dest.getIpAddress(); port = dest.getPort(); l = (List) entry.getValue(); try { out_stream.reset(); // BufferedOutputStream bos=new BufferedOutputStream(out_stream); out_stream.write(Version.version_id, 0, Version.version_id.length); // write the version // bos.write(Version.version_id, 0, Version.version_id.length); // write the version out = new ObjectOutputStream(out_stream); // out=new ObjectOutputStream(bos); l.writeExternal(out); out.close(); // needed if out buffers its output to out_stream data = out_stream.toByteArray(); doSend(data, addr, port); } catch (IOException e) { Trace.error( "UDP.BundlingOutgoingPacketHandle.bundleAndSend()", "exception sending msg (to dest=" + dest + "): " + e); } } msgs.clear(); } }
@ManagedOperation(description = "Reads data from local caches and dumps them to a file") public void dumpCache(String output_filename) throws Exception { Map<Address, PhysicalAddress> cache_contents = (Map<Address, PhysicalAddress>) down_prot.down(new Event(Event.GET_LOGICAL_PHYSICAL_MAPPINGS, false)); List<PingData> list = new ArrayList<>(cache_contents.size()); for (Map.Entry<Address, PhysicalAddress> entry : cache_contents.entrySet()) { Address addr = entry.getKey(); PhysicalAddress phys_addr = entry.getValue(); PingData data = new PingData(addr, true, UUID.get(addr), phys_addr).coord(addr.equals(local_addr)); list.add(data); } OutputStream out = new FileOutputStream(output_filename); write(list, out); }