public List<PingData> findAllViews(Promise<JoinRsp> promise) { int num_expected_mbrs = Math.max( max_found_members, Math.max(num_initial_members, view != null ? view.size() : num_initial_members)); max_found_members = Math.max(max_found_members, num_expected_mbrs); return findMembers(promise, num_expected_mbrs, false, getViewId()); }
/** * Merge all MergeData. All MergeData elements should be disjunct (both views and digests). * However, this method is prepared to resolve duplicate entries (for the same member). * Resolution strategy for views is to merge only 1 of the duplicate members. Resolution * strategy for digests is to take the higher seqnos for duplicate digests. * * <p>After merging all members into a Membership and subsequent sorting, the first member of * the sorted membership will be the new coordinator. This method has a lock on merge_rsps. * * @param merge_rsps A list of MergeData items. Elements with merge_rejected=true were removed * before. Is guaranteed not to be null and to contain at least 1 member. */ private MergeData consolidateMergeData(Vector<MergeData> merge_rsps) { long logical_time = 0; // for new_vid Membership new_mbrs = new Membership(); Vector<View> subgroups = new Vector<View>(11); // contains a list of Views, each View is a subgroup for (MergeData tmp_data : merge_rsps) { View tmp_view = tmp_data.getView(); if (tmp_view != null) { ViewId tmp_vid = tmp_view.getVid(); if (tmp_vid != null) { // compute the new view id (max of all vids +1) logical_time = Math.max(logical_time, tmp_vid.getId()); } // merge all membership lists into one (prevent duplicates) new_mbrs.add(tmp_view.getMembers()); subgroups.addElement((View) tmp_view.clone()); } } // the new coordinator is the first member of the consolidated & sorted membership list new_mbrs.sort(); Address new_coord = new_mbrs.size() > 0 ? new_mbrs.elementAt(0) : null; if (new_coord == null) { if (log.isErrorEnabled()) log.error("new_coord == null"); return null; } // should be the highest view ID seen up to now plus 1 ViewId new_vid = new ViewId(new_coord, logical_time + 1); // determine the new view MergeView new_view = new MergeView(new_vid, new_mbrs.getMembers(), subgroups); // determine the new digest Digest new_digest = consolidateDigests(merge_rsps, new_mbrs.size()); if (new_digest == null) { if (log.isErrorEnabled()) log.error("Merge leader " + gms.local_addr + ": could not consolidate digest for merge"); return null; } if (log.isDebugEnabled()) log.debug( "Merge leader " + gms.local_addr + ": consolidated view=" + new_view + "\nconsolidated digest=" + new_digest); return new MergeData(gms.local_addr, new_view, new_digest); }
/** * Merge all MergeData. All MergeData elements should be disjunct (both views and digests). * However, this method is prepared to resolve duplicate entries (for the same member). * Resolution strategy for views is to merge only 1 of the duplicate members. Resolution * strategy for digests is to take the higher seqnos for duplicate digests. * * <p>After merging all members into a Membership and subsequent sorting, the first member of * the sorted membership will be the new coordinator. This method has a lock on merge_rsps. * * @param merge_rsps A list of MergeData items. Elements with merge_rejected=true were removed * before. Is guaranteed not to be null and to contain at least 1 member. */ private MergeData consolidateMergeData(List<MergeData> merge_rsps) { long logical_time = 0; // for new_vid List<View> subgroups = new ArrayList<View>(11); // contains a list of Views, each View is a subgroup Collection<Collection<Address>> sub_mbrships = new ArrayList<Collection<Address>>(); for (MergeData tmp_data : merge_rsps) { View tmp_view = tmp_data.getView(); if (tmp_view != null) { ViewId tmp_vid = tmp_view.getVid(); if (tmp_vid != null) { // compute the new view id (max of all vids +1) logical_time = Math.max(logical_time, tmp_vid.getId()); } // merge all membership lists into one (prevent duplicates) sub_mbrships.add(new ArrayList<Address>(tmp_view.getMembers())); subgroups.add(tmp_view.copy()); } } // determine the new digest Digest new_digest = consolidateDigests(merge_rsps, merge_rsps.size()); if (new_digest == null) return null; // remove all members from the new member list that are not in the digest Collection<Address> digest_mbrs = new_digest.getMembers(); for (Collection<Address> coll : sub_mbrships) coll.retainAll(digest_mbrs); List<Address> merged_mbrs = gms.computeNewMembership(sub_mbrships); // the new coordinator is the first member of the consolidated & sorted membership list Address new_coord = merged_mbrs.isEmpty() ? null : merged_mbrs.get(0); if (new_coord == null) return null; // should be the highest view ID seen up to now plus 1 ViewId new_vid = new ViewId(new_coord, logical_time + 1); // determine the new view MergeView new_view = new MergeView(new_vid, merged_mbrs, subgroups); if (log.isTraceEnabled()) log.trace( gms.local_addr + ": consolidated view=" + new_view + "\nconsolidated digest=" + new_digest); return new MergeData(gms.local_addr, new_view, new_digest); }
/** * 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; }
/** * Computes the next view. Returns a copy that has <code>old_mbrs</code> and <code>suspected_mbrs * </code> removed and <code>new_mbrs</code> added. */ public View getNextView( Collection<Address> new_mbrs, Collection<Address> old_mbrs, Collection<Address> suspected_mbrs) { synchronized (members) { ViewId view_id = view != null ? view.getViewId() : null; if (view_id == null) { log.error("view_id is null"); return null; // this should *never* happen ! } long vid = Math.max(view_id.getId(), ltime) + 1; ltime = vid; Membership tmp_mbrs = tmp_members.copy(); // always operate on the temporary membership tmp_mbrs.remove(suspected_mbrs); tmp_mbrs.remove(old_mbrs); tmp_mbrs.add(new_mbrs); List<Address> mbrs = tmp_mbrs.getMembers(); Address new_coord = local_addr; if (!mbrs.isEmpty()) new_coord = mbrs.get(0); View v = new View(new_coord, vid, mbrs); // Update membership (see DESIGN for explanation): tmp_members.set(mbrs); // Update joining list (see DESIGN for explanation) if (new_mbrs != null) { for (Address tmp_mbr : new_mbrs) { if (!joining.contains(tmp_mbr)) joining.add(tmp_mbr); } } // Update leaving list (see DESIGN for explanations) if (old_mbrs != null) { for (Address addr : old_mbrs) { if (!leaving.contains(addr)) leaving.add(addr); } } if (suspected_mbrs != null) { for (Address addr : suspected_mbrs) { if (!leaving.contains(addr)) leaving.add(addr); } } return v; } }
/** * Computes the next view. Returns a copy that has <code>old_mbrs</code> and <code>suspected_mbrs * </code> removed and <code>new_mbrs</code> added. */ public View getNextView(Vector new_mbrs, Vector old_mbrs, Vector suspected_mbrs) { Vector mbrs; long vid = 0; View v; Membership tmp_mbrs; Vector mbrs_to_remove = new Vector(); if (old_mbrs != null && old_mbrs.size() > 0) for (int i = 0; i < old_mbrs.size(); i++) mbrs_to_remove.addElement(old_mbrs.elementAt(i)); if (suspected_mbrs != null && suspected_mbrs.size() > 0) for (int i = 0; i < suspected_mbrs.size(); i++) if (!mbrs_to_remove.contains(suspected_mbrs.elementAt(i))) mbrs_to_remove.addElement(suspected_mbrs.elementAt(i)); synchronized (view_mutex) { vid = Math.max(view_id.getId(), ltime) + 1; ltime = vid; tmp_mbrs = members.copy(); tmp_mbrs.merge(new_mbrs, mbrs_to_remove); mbrs = (Vector) tmp_mbrs.getMembers().clone(); v = new View(local_addr, vid, mbrs); return v; } }
public Dimension getPreferredSize() { Dimension layoutSize = super.getPreferredSize(); int max = Math.max(layoutSize.width, layoutSize.height); return new Dimension(max + 20, max + 20); }
public void run() { Object tmp; Message msg = null; int counter = 0; Vector v = new Vector(); while (running) { Util.sleep(10); try { tmp = channel.receive(0); if (tmp == null) continue; if (tmp instanceof View) { View vw = (View) tmp; control.viewNumber.setText(String.valueOf(vw.getVid().getId())); control.numMessagesInLastView.setText(String.valueOf(counter)); counter = 0; v.clear(); continue; } if (!(tmp instanceof Message)) continue; msg = (Message) tmp; measureThrougput(msg.size()); TotalPayload p = null; p = (TotalPayload) msg.getObject(); v.addElement(new Integer(p.getRandomSequence())); int size = v.size(); if (size % 50 == 0) { int value = 0; int i = 0; Iterator iter = v.iterator(); while (iter.hasNext()) { i++; int seq = ((Integer) iter.next()).intValue(); if (i % 2 == 0) { value *= seq; } else if (i % 3 == 0) { value -= seq; } else value += seq; } v.clear(); value = Math.abs(value); int r = value % 85; int g = value % 170; int b = value % 255; colorPanel.setSeq(r, g, b); } counter++; } catch (ChannelNotConnectedException e) { e.printStackTrace(); } catch (ChannelClosedException e) { e.printStackTrace(); } catch (TimeoutException e) { e.printStackTrace(); } } }
public Object down(Event evt) { switch (evt.getType()) { case ExecutorEvent.TASK_SUBMIT: Runnable runnable = evt.getArg(); // We are limited to a number of concurrent request id's // equal to 2^63-1. This is quite large and if it // overflows it will still be positive long requestId = Math.abs(counter.getAndIncrement()); if (requestId == Long.MIN_VALUE) { // TODO: need to fix this it isn't safe for concurrent modifications counter.set(0); requestId = Math.abs(counter.getAndIncrement()); } // Need to make sure to put the requestId in our map before // adding the runnable to awaiting consumer in case if // coordinator sent a consumer found and their original task // is no longer around // see https://issues.jboss.org/browse/JGRP-1744 _requestId.put(runnable, requestId); _awaitingConsumer.add(runnable); sendToCoordinator(RUN_REQUEST, requestId, local_addr); break; case ExecutorEvent.CONSUMER_READY: Thread currentThread = Thread.currentThread(); long threadId = currentThread.getId(); _consumerId.put(threadId, PRESENT); try { for (; ; ) { CyclicBarrier barrier = new CyclicBarrier(2); _taskBarriers.put(threadId, barrier); // We only send to the coordinator that we are ready after // making the barrier, wait for request to come and let // us free sendToCoordinator(Type.CONSUMER_READY, threadId, local_addr); try { barrier.await(); break; } catch (BrokenBarrierException e) { if (log.isDebugEnabled()) log.debug( "Producer timed out before we picked up" + " the task, have to tell coordinator" + " we are still good."); } } // This should always be non nullable since the latch // was freed runnable = _tasks.remove(threadId); _runnableThreads.put(runnable, currentThread); return runnable; } catch (InterruptedException e) { if (log.isDebugEnabled()) log.debug("Consumer " + threadId + " stopped via interrupt"); sendToCoordinator(Type.CONSUMER_UNREADY, threadId, local_addr); Thread.currentThread().interrupt(); } finally { // Make sure the barriers are cleaned up as well _taskBarriers.remove(threadId); _consumerId.remove(threadId); } break; case ExecutorEvent.TASK_COMPLETE: Object arg = evt.getArg(); Throwable throwable = null; if (arg instanceof Object[]) { Object[] array = (Object[]) arg; runnable = (Runnable) array[0]; throwable = (Throwable) array[1]; } else { runnable = (Runnable) arg; } Owner owner = _running.remove(runnable); // This won't remove anything if owner doesn't come back _runnableThreads.remove(runnable); Object value = null; boolean exception = false; if (throwable != null) { // InterruptedException is special telling us that // we interrupted the thread while waiting but still got // a task therefore we have to reject it. if (throwable instanceof InterruptedException) { if (log.isDebugEnabled()) log.debug("Run rejected due to interrupted exception returned"); sendRequest(owner.address, Type.RUN_REJECTED, owner.requestId, null); break; } value = throwable; exception = true; } else if (runnable instanceof RunnableFuture<?>) { RunnableFuture<?> future = (RunnableFuture<?>) runnable; boolean interrupted = false; boolean gotValue = false; // We have the value, before we interrupt at least get it! while (!gotValue) { try { value = future.get(); gotValue = true; } catch (InterruptedException e) { interrupted = true; } catch (ExecutionException e) { value = e.getCause(); exception = true; gotValue = true; } } if (interrupted) { Thread.currentThread().interrupt(); } } if (owner != null) { final Type type; final Object valueToSend; if (value == null) { type = Type.RESULT_SUCCESS; valueToSend = value; } // Both serializable values and exceptions would go in here else if (value instanceof Serializable || value instanceof Externalizable || value instanceof Streamable) { type = exception ? Type.RESULT_EXCEPTION : Type.RESULT_SUCCESS; valueToSend = value; } // This would happen if the value wasn't serializable, // so we have to send back to the client that the class // wasn't serializable else { type = Type.RESULT_EXCEPTION; valueToSend = new NotSerializableException(value.getClass().getName()); } if (local_addr.equals(owner.getAddress())) { if (log.isTraceEnabled()) log.trace( "[redirect] <--> [" + local_addr + "] " + type.name() + " [" + value + (owner.requestId != -1 ? " request id: " + owner.requestId : "") + "]"); if (type == Type.RESULT_SUCCESS) { handleValueResponse(local_addr, owner.requestId, valueToSend); } else if (type == Type.RESULT_EXCEPTION) { handleExceptionResponse(local_addr, owner.requestId, (Throwable) valueToSend); } } else { sendRequest(owner.getAddress(), type, owner.requestId, valueToSend); } } else { if (log.isTraceEnabled()) { log.trace("Could not return result - most likely because it was interrupted"); } } break; case ExecutorEvent.TASK_CANCEL: Object[] array = evt.getArg(); runnable = (Runnable) array[0]; if (_awaitingConsumer.remove(runnable)) { _requestId.remove(runnable); ExecutorNotification notification = notifiers.remove(runnable); if (notification != null) { notification.interrupted(runnable); } if (log.isTraceEnabled()) log.trace("Cancelled task " + runnable + " before it was picked up"); return Boolean.TRUE; } // This is guaranteed to not be null so don't take cost of auto unboxing else if (array[1] == Boolean.TRUE) { owner = removeKeyForValue(_awaitingReturn, runnable); if (owner != null) { Long requestIdValue = _requestId.remove(runnable); // We only cancel if the requestId is still available // this means the result hasn't been returned yet and // we still have a chance to interrupt if (requestIdValue != null) { if (requestIdValue != owner.getRequestId()) { log.warn("Cancelling requestId didn't match waiting"); } sendRequest(owner.getAddress(), Type.INTERRUPT_RUN, owner.getRequestId(), null); } } else { if (log.isTraceEnabled()) log.warn("Couldn't interrupt server task: " + runnable); } ExecutorNotification notification = notifiers.remove(runnable); if (notification != null) { notification.interrupted(runnable); } return Boolean.TRUE; } else { return Boolean.FALSE; } case ExecutorEvent.ALL_TASK_CANCEL: array = evt.getArg(); // This is a RunnableFuture<?> so this cast is okay @SuppressWarnings("unchecked") Set<Runnable> runnables = (Set<Runnable>) array[0]; Boolean booleanValue = (Boolean) array[1]; List<Runnable> notRan = new ArrayList<>(); for (Runnable cancelRunnable : runnables) { // Removed from the consumer if (!_awaitingConsumer.remove(cancelRunnable) && booleanValue == Boolean.TRUE) { synchronized (_awaitingReturn) { owner = removeKeyForValue(_awaitingReturn, cancelRunnable); if (owner != null) { Long requestIdValue = _requestId.remove(cancelRunnable); if (requestIdValue != owner.getRequestId()) { log.warn("Cancelling requestId didn't match waiting"); } sendRequest(owner.getAddress(), Type.INTERRUPT_RUN, owner.getRequestId(), null); } ExecutorNotification notification = notifiers.remove(cancelRunnable); if (notification != null) { log.trace("Notifying listener"); notification.interrupted(cancelRunnable); } } } else { _requestId.remove(cancelRunnable); notRan.add(cancelRunnable); } } return notRan; case Event.SET_LOCAL_ADDRESS: local_addr = evt.getArg(); break; case Event.VIEW_CHANGE: handleView(evt.getArg()); break; } return down_prot.down(evt); }
public Object down(Event evt) { switch (evt.getType()) { case Event.MSG: // Add UnicastHeader, add to AckSenderWindow and pass down Message msg = (Message) evt.getArg(); Address dst = msg.getDest(); /* only handle unicast messages */ if (dst == null || msg.isFlagSet(Message.NO_RELIABILITY)) break; if (!running) { if (log.isTraceEnabled()) log.trace("discarded message as start() has not yet been called, message: " + msg); return null; } SenderEntry entry = send_table.get(dst); if (entry == null) { entry = new SenderEntry(getNewConnectionId()); SenderEntry existing = send_table.putIfAbsent(dst, entry); if (existing != null) entry = existing; else { if (log.isTraceEnabled()) log.trace( local_addr + ": created connection to " + dst + " (conn_id=" + entry.send_conn_id + ")"); if (cache != null && !members.contains(dst)) cache.add(dst); } } short send_conn_id = entry.send_conn_id; long seqno = entry.sent_msgs_seqno.getAndIncrement(); long sleep = 10; while (running) { try { msg.putHeader( this.id, Unicast2Header.createDataHeader(seqno, send_conn_id, seqno == DEFAULT_FIRST_SEQNO)); entry.sent_msgs.add(seqno, msg); // add *including* UnicastHeader, adds to retransmitter if (conn_expiry_timeout > 0) entry.update(); break; } catch (Throwable t) { if (!running) break; if (log.isWarnEnabled()) log.warn("failed sending message", t); Util.sleep(sleep); sleep = Math.min(5000, sleep * 2); } } if (log.isTraceEnabled()) { StringBuilder sb = new StringBuilder(); sb.append(local_addr) .append(" --> DATA(") .append(dst) .append(": #") .append(seqno) .append(", conn_id=") .append(send_conn_id); if (seqno == DEFAULT_FIRST_SEQNO) sb.append(", first"); sb.append(')'); log.trace(sb); } try { down_prot.down(evt); num_msgs_sent++; } catch (Throwable t) { log.warn("failed sending the message", t); } return null; // we already passed the msg down case Event.VIEW_CHANGE: // remove connections to peers that are not members anymore ! View view = (View) evt.getArg(); List<Address> new_members = view.getMembers(); Set<Address> non_members = new HashSet<Address>(send_table.keySet()); non_members.addAll(recv_table.keySet()); members = new_members; non_members.removeAll(new_members); if (cache != null) cache.removeAll(new_members); if (!non_members.isEmpty()) { if (log.isTraceEnabled()) log.trace("removing non members " + non_members); for (Address non_mbr : non_members) removeConnection(non_mbr); } break; case Event.SET_LOCAL_ADDRESS: local_addr = (Address) evt.getArg(); break; } return down_prot.down(evt); // Pass on to the layer below us }
/** * Generate Random Color * * @return */ private Color selectColor() { int red = Math.abs(random.nextInt()) % 255; int green = Math.abs(random.nextInt()) % 255; int blue = Math.abs(random.nextInt()) % 255; return new Color(red, blue, blue); }
/** * Sets the new view and sends a VIEW_CHANGE event up and down the stack. If the view is a * MergeView (subclass of View), then digest will be non-null and has to be set before installing * the view. */ public void installView(View new_view, Digest digest) { ViewId vid = new_view.getVid(); List<Address> mbrs = new_view.getMembers(); ltime = Math.max( vid.getId(), ltime); // compute the logical time, regardless of whether the view is accepted // Discards view with id lower than or equal to our own. Will be installed without check if it // is the first view if (view != null) { ViewId view_id = view.getViewId(); int rc = vid.compareToIDs(view_id); if (rc <= 0) { if (log.isWarnEnabled() && rc < 0 && log_view_warnings) { // only scream if view is smaller, silently discard same views log.warn( local_addr + ": received view < current view;" + " discarding it (current vid: " + view_id + ", new vid: " + vid + ')'); } return; } } /* Check for self-inclusion: if I'm not part of the new membership, I just discard it. This ensures that messages sent in view V1 are only received by members of V1 */ if (!mbrs.contains(local_addr)) { if (log.isWarnEnabled() && log_view_warnings) log.warn(local_addr + ": not member of view " + new_view.getViewId() + "; discarding it"); return; } if (digest != null) { if (new_view instanceof MergeView) mergeDigest(digest); else setDigest(digest); } if (log.isDebugEnabled()) log.debug(local_addr + ": installing view " + new_view); Event view_event; synchronized (members) { view = new View(new_view.getVid(), new_view.getMembers()); view_event = new Event(Event.VIEW_CHANGE, new_view); // Set the membership. Take into account joining members if (!mbrs.isEmpty()) { members.set(mbrs); tmp_members.set(members); joining.removeAll(mbrs); // remove all members in mbrs from joining // remove all elements from 'leaving' that are not in 'mbrs' leaving.retainAll(mbrs); tmp_members.add(joining); // add members that haven't yet shown up in the membership tmp_members.remove( leaving); // remove members that haven't yet been removed from the membership // add to prev_members for (Address addr : mbrs) { if (!prev_members.contains(addr)) prev_members.add(addr); } } Address coord = determineCoordinator(); if (coord != null && coord.equals(local_addr) && !haveCoordinatorRole()) { becomeCoordinator(); } else { if (haveCoordinatorRole() && !local_addr.equals(coord)) { becomeParticipant(); merge_ack_collector.reset(null); // we don't need this one anymore } } } // - Changed order of passing view up and down (http://jira.jboss.com/jira/browse/JGRP-347) // - Changed it back (bela Sept 4 2007): http://jira.jboss.com/jira/browse/JGRP-564 // - Moved sending up view_event out of the synchronized block (bela Nov 2011) down_prot.down(view_event); // needed e.g. by failure detector or UDP up_prot.up(view_event); List<Address> tmp_mbrs = new_view.getMembers(); ack_collector.retainAll(tmp_mbrs); merge_ack_collector.retainAll(tmp_mbrs); if (new_view instanceof MergeView) merger.forceCancelMerge(); if (stats) { num_views++; prev_views.add(new Tuple<View, Long>(new_view, System.currentTimeMillis())); } }
/** * Assigns the new ltime. Installs view and view_id. Changes role to coordinator if necessary. * Sends VIEW_CHANGE event up and down the stack. */ public void installView(ViewId new_view, Vector mbrs) { Object coord; int rc; synchronized (view_mutex) { // serialize access to views ltime = Math.max(new_view.getId(), ltime); // compute Lamport logical time if (Trace.trace) Trace.info("GMS.installView()", "received view change, vid=" + new_view); /* Check for self-inclusion: if I'm not part of the new membership, I just discard it. This ensures that messages sent in view V1 are only received by members of V1 */ if (checkSelfInclusion(mbrs) == false) { if (Trace.trace) Trace.warn("GMS.installView()", "I'm not member of " + mbrs + ", discarding"); return; } if (view_id == null) { if (new_view == null) { Trace.error("GMS.installView()", "view_id and new_view are null !"); return; } else { // view_id is null, new_view not: just install new_view (we're still a client) view_id = (ViewId) new_view.clone(); } } else { if (new_view == null) { // this should never happen though ! Trace.error("GMS.installView()", "new_view is null !"); return; } else { // both view_id and new_view are not null rc = new_view.compareTo(view_id); // rc should always be a positive number if (rc <= 0) { // don't accept view id lower than our own if (Trace.trace) { Trace.warn( "GMS.installView()", "received view <= current view; discarding it ! " + "(view_id: " + view_id + ", new_view: " + new_view + ")"); } return; } else { // the check for vid equality was okay, assign new_view to view_id if (new_view.getCoordAddress() != null) { view_id = new ViewId(new_view.getCoordAddress(), new_view.getId()); } else { view_id = new ViewId(view_id.getCoordAddress(), new_view.getId()); } } } } if (mbrs != null && mbrs.size() > 0) members.set(mbrs); // Send VIEW_CHANGE event up and down the stack: Event view_event = new Event(Event.VIEW_CHANGE, makeView(members.getMembers())); passDown(view_event); // needed e.g. by failure detector or UDP passUp(view_event); coord = determineCoordinator(); if (coord != null && coord.equals(local_addr) && !(coord.equals(new_view.getCoordAddress()))) { becomeCoordinator(); } } }