Exemple #1
0
  /**
   * 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
    }
  }
Exemple #2
0
  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();
  }
Exemple #3
0
  /**
   * 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);
      }
    }
  }
Exemple #4
0
 @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();
 }
Exemple #5
0
 @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();
 }
Exemple #6
0
    /**
     * 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);
    }
Exemple #7
0
 private void process(List<Request> requests) {
   if (requests.isEmpty()) return;
   Request firstReq = requests.get(0);
   switch (firstReq.type) {
     case Request.JOIN:
     case Request.JOIN_WITH_STATE_TRANSFER:
     case Request.LEAVE:
     case Request.SUSPECT:
       impl.handleMembershipChange(requests);
       break;
     case Request.MERGE:
       impl.merge(firstReq.views);
       break;
     default:
       log.error("request " + firstReq.type + " is unknown; discarded");
   }
 }
Exemple #8
0
  /**
   * 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;
    }
  }
Exemple #9
0
  public static void testPickNextN() {
    List<Integer> list = Arrays.asList(1, 2, 3, 4);
    List<Integer> result = Util.pickNext(list, 0, 1);
    assert result.isEmpty();

    result = Util.pickNext(list, 1, 1);
    System.out.println("result = " + result);
    assert result.size() == 1;
    assert result.contains(2);

    result = Util.pickNext(list, 3, 2);
    System.out.println("result = " + result);
    assert result.size() == 2;
    assert result.contains(4) && result.contains(1);

    result = Util.pickNext(list, 4, 5);
    System.out.println("result = " + result);
    assert result.size() == 3;
    assert result.contains(1) && result.contains(2) && result.contains(3);
  }
Exemple #10
0
  public static void testLeftMembers2() {
    final Address a = Util.createRandomAddress(),
        b = Util.createRandomAddress(),
        c = Util.createRandomAddress(),
        d = Util.createRandomAddress();

    List<Address> v1 = new ArrayList<>();
    v1.add(a);
    v1.add(b);
    v1.add(c);
    v1.add(d);

    List<Address> v2 = new ArrayList<>();
    v2.add(c);
    v2.add(d);
    v2.add(a);
    v2.add(b);

    View one = new View(new ViewId(a, 1), v1), two = new View(new ViewId(b, 2), v2);
    List<Address> left = View.leftMembers(one, two);
    System.out.println("left = " + left);
    assert left != null;
    assert left.isEmpty();
  }
  protected <T> GroupRequest<T> cast(
      final Collection<Address> dests,
      Message msg,
      RequestOptions options,
      boolean block_for_results,
      FutureListener<RspList<T>> listener)
      throws Exception {
    if (msg.getDest() != null && !(msg.getDest() instanceof AnycastAddress))
      throw new IllegalArgumentException("message destination is non-null, cannot send message");

    if (options != null) {
      msg.setFlag(options.getFlags()).setTransientFlag(options.getTransientFlags());
      if (options.getScope() > 0) msg.setScope(options.getScope());
    }

    List<Address> real_dests;
    // we need to clone because we don't want to modify the original
    if (dests != null) {
      real_dests = new ArrayList<Address>();
      for (Address dest : dests) {
        if (dest instanceof SiteAddress || this.members.contains(dest)) {
          if (!real_dests.contains(dest)) real_dests.add(dest);
        }
      }
    } else real_dests = new ArrayList<Address>(members);

    // if local delivery is off, then we should not wait for the message from the local member.
    // therefore remove it from the membership
    Channel tmp = channel;
    if ((tmp != null && tmp.getDiscardOwnMessages())
        || msg.isTransientFlagSet(Message.TransientFlag.DONT_LOOPBACK)) {
      if (local_addr == null) local_addr = tmp != null ? tmp.getAddress() : null;
      if (local_addr != null) real_dests.remove(local_addr);
    }

    if (options != null && options.hasExclusionList()) {
      Address[] exclusion_list = options.exclusionList();
      for (Address excluding : exclusion_list) real_dests.remove(excluding);
    }

    // don't even send the message if the destination list is empty
    if (log.isTraceEnabled()) log.trace("real_dests=" + real_dests);

    if (real_dests.isEmpty()) {
      if (log.isTraceEnabled()) log.trace("destination list is empty, won't send message");
      return null;
    }

    if (options != null) {
      boolean async = options.getMode() == ResponseMode.GET_NONE;
      if (options.getAnycasting()) {
        if (async) async_anycasts.incrementAndGet();
        else sync_anycasts.incrementAndGet();
      } else {
        if (async) async_multicasts.incrementAndGet();
        else sync_multicasts.incrementAndGet();
      }
    }

    GroupRequest<T> req = new GroupRequest<T>(msg, corr, real_dests, options);
    if (listener != null) req.setListener(listener);
    if (options != null) {
      req.setResponseFilter(options.getRspFilter());
      req.setAnycasting(options.getAnycasting());
    }
    req.setBlockForResults(block_for_results);
    req.execute();
    return req;
  }
Exemple #12
0
  /**
   * Check whether the hashmap contains an entry e for <code>sender</code> (create if not). If
   * e.received_msgs is null and <code>first</code> is true: create a new AckReceiverWindow(seqno)
   * and add message. Set e.received_msgs to the new window. Else just add the message.
   */
  protected void handleDataReceived(
      Address sender, long seqno, short conn_id, boolean first, Message msg, Event evt) {
    if (log.isTraceEnabled()) {
      StringBuilder sb = new StringBuilder();
      sb.append(local_addr).append(" <-- DATA(").append(sender).append(": #").append(seqno);
      if (conn_id != 0) sb.append(", conn_id=").append(conn_id);
      if (first) sb.append(", first");
      sb.append(')');
      log.trace(sb);
    }

    ReceiverEntry entry = getReceiverEntry(sender, seqno, first, conn_id);
    if (entry == null) return;
    if (conn_expiry_timeout > 0) entry.update();
    Table<Message> win = entry.received_msgs;
    boolean added = win.add(seqno, msg); // win is guaranteed to be non-null if we get here
    num_msgs_received++;

    if (added) {
      int len = msg.getLength();
      if (len > 0 && entry.incrementStable(len))
        sendStableMessage(
            sender, entry.recv_conn_id, win.getHighestDelivered(), win.getHighestReceived());
    }

    // An OOB message is passed up immediately. Later, when remove() is called, we discard it. This
    // affects ordering !
    // http://jira.jboss.com/jira/browse/JGRP-377
    if (msg.isFlagSet(Message.OOB) && added) {
      try {
        up_prot.up(evt);
      } catch (Throwable t) {
        log.error("couldn't deliver OOB message " + msg, t);
      }
    }

    final AtomicBoolean processing = win.getProcessing();
    if (!processing.compareAndSet(false, true)) {
      return;
    }

    // Try to remove as many messages as possible and pass them up.
    // Prevents concurrent passing up of messages by different threads
    // (http://jira.jboss.com/jira/browse/JGRP-198);
    // this is all the more important once we have a concurrent stack
    // (http://jira.jboss.com/jira/browse/JGRP-181),
    // where lots of threads can come up to this point concurrently, but only 1 is allowed to pass
    // at a time
    // We *can* deliver messages from *different* senders concurrently, e.g. reception of P1, Q1,
    // P2, Q2 can result in
    // delivery of P1, Q1, Q2, P2: FIFO (implemented by UNICAST) says messages need to be delivered
    // only in the
    // order in which they were sent by their senders
    boolean released_processing = false;
    try {
      while (true) {
        List<Message> msgs =
            win.removeMany(processing, true, max_msg_batch_size); // remove my own messages
        if (msgs == null || msgs.isEmpty()) {
          released_processing = true;
          return;
        }

        for (Message m : msgs) {
          // discard OOB msg: it has already been delivered
          // (http://jira.jboss.com/jira/browse/JGRP-377)
          if (m.isFlagSet(Message.OOB)) continue;
          try {
            up_prot.up(new Event(Event.MSG, m));
          } catch (Throwable t) {
            log.error("couldn't deliver message " + m, t);
          }
        }
      }
    } finally {
      // processing is always set in win.remove(processing) above and never here ! This code is just
      // a
      // 2nd line of defense should there be an exception before win.remove(processing) sets
      // processing
      if (!released_processing) processing.set(false);
    }
  }
Exemple #13
0
  /**
   * Broadcasts the new view and digest, and waits for acks from all members in the list given as
   * argument. If the list is null, we take the members who are part of new_view
   */
  public void castViewChange(
      View new_view, Digest digest, JoinRsp jr, Collection<Address> newMembers) {
    if (log.isTraceEnabled())
      log.trace(local_addr + ": mcasting view " + new_view + " (" + new_view.size() + " mbrs)\n");

    // Send down a local TMP_VIEW event. This is needed by certain layers (e.g. NAKACK) to compute
    // correct digest
    // in case client's next request (e.g. getState()) reaches us *before* our own view change
    // multicast.
    // Check NAKACK's TMP_VIEW handling for details
    down_prot.up(new Event(Event.TMP_VIEW, new_view));
    down_prot.down(new Event(Event.TMP_VIEW, new_view));

    List<Address> ackMembers = new ArrayList<Address>(new_view.getMembers());
    if (newMembers != null && !newMembers.isEmpty()) ackMembers.removeAll(newMembers);

    Message view_change_msg = new Message(); // bcast to all members
    GmsHeader hdr = new GmsHeader(GmsHeader.VIEW, new_view);
    hdr.my_digest = digest;
    view_change_msg.putHeader(this.id, hdr);

    // If we're the only member the VIEW is broadcast to, let's simply install the view directly,
    // without
    // sending the VIEW multicast ! Or else N-1 members drop the multicast anyway...
    if (local_addr != null && ackMembers.size() == 1 && ackMembers.get(0).equals(local_addr)) {
      // we need to add the message to the retransmit window (e.g. in NAKACK), so (1) it can be
      // retransmitted and
      // (2) we increment the seqno (otherwise, we'd return an incorrect digest)
      down_prot.down(new Event(Event.ADD_TO_XMIT_TABLE, view_change_msg));
      impl.handleViewChange(new_view, digest);
    } else {
      if (!ackMembers.isEmpty()) ack_collector.reset(ackMembers);

      down_prot.down(new Event(Event.MSG, view_change_msg));
      try {
        if (!ackMembers.isEmpty()) {
          ack_collector.waitForAllAcks(view_ack_collection_timeout);
          if (log.isTraceEnabled())
            log.trace(
                local_addr
                    + ": received all "
                    + ack_collector.expectedAcks()
                    + " ACKs from members for view "
                    + new_view.getVid());
        }
      } catch (TimeoutException e) {
        if (log_collect_msgs && log.isWarnEnabled()) {
          log.warn(
              local_addr
                  + ": failed to collect all ACKs (expected="
                  + ack_collector.expectedAcks()
                  + ") for view "
                  + new_view.getViewId()
                  + " after "
                  + view_ack_collection_timeout
                  + "ms, missing ACKs from "
                  + ack_collector.printMissing());
        }
      }
    }

    if (jr != null && (newMembers != null && !newMembers.isEmpty())) {
      ack_collector.reset(new ArrayList<Address>(newMembers));
      for (Address joiner : newMembers) {
        sendJoinResponse(jr, joiner);
      }
      try {
        ack_collector.waitForAllAcks(view_ack_collection_timeout);
        if (log.isTraceEnabled())
          log.trace(
              local_addr
                  + ": received all ACKs ("
                  + ack_collector.expectedAcks()
                  + ") from joiners for view "
                  + new_view.getVid());
      } catch (TimeoutException e) {
        if (log_collect_msgs && log.isWarnEnabled()) {
          log.warn(
              local_addr
                  + ": failed to collect all ACKs (expected="
                  + ack_collector.expectedAcks()
                  + ") for unicast view "
                  + new_view
                  + " after "
                  + view_ack_collection_timeout
                  + "ms, missing ACKs from "
                  + ack_collector.printMissing());
        }
      }
    }
  }
Exemple #14
0
  /**
   * 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()));
    }
  }
Exemple #15
0
  @SuppressWarnings("unchecked")
  public Object down(Event evt) {
    switch (evt.getType()) {
      case Event.FIND_INITIAL_MBRS: // sent by GMS layer
        return findMembers(null, true, false); // triggered by JOIN process (ClientGmsImpl)

      case Event.FIND_MBRS:
        return findMembers(
            (List<Address>) evt.getArg(), false, false); // triggered by MERGE2/MERGE3

        // case Event.TMP_VIEW:
      case Event.VIEW_CHANGE:
        List<Address> tmp;
        View old_view = view;
        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);
        Object retval = down_prot.down(evt);
        if (send_cache_on_join && !isDynamic() && is_coord) {
          List<Address> curr_mbrs, left_mbrs, new_mbrs;
          synchronized (members) {
            curr_mbrs = new ArrayList<>(members);
            left_mbrs = old_view != null ? Util.leftMembers(old_view.getMembers(), members) : null;
            new_mbrs = old_view != null ? Util.newMembers(old_view.getMembers(), members) : null;
          }
          startCacheDissemination(curr_mbrs, left_mbrs, new_mbrs); // separate task
        }
        return retval;

      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;
        cluster_name = (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
    }
  }
Exemple #16
0
    /** Runs the merge protocol as a leader */
    protected void _run(MergeId new_merge_id, final Collection<Address> coordsCopy)
        throws Exception {
      boolean success = setMergeId(null, new_merge_id);
      if (!success) {
        log.warn("failed to set my own merge_id (" + merge_id + ") to " + new_merge_id);
        return;
      }

      if (log.isDebugEnabled())
        log.debug(
            gms.local_addr
                + ": merge task "
                + merge_id
                + " started with "
                + coords.keySet().size()
                + " coords");

      /* 2. Fetch the current Views/Digests from all subgroup coordinators */
      success = getMergeDataFromSubgroupCoordinators(coords, new_merge_id, gms.merge_timeout);
      List<Address> missing = null;
      if (!success) {
        missing = merge_rsps.getMissing();
        if (log.isDebugEnabled())
          log.debug(
              "merge leader "
                  + gms.local_addr
                  + " did not get responses from all "
                  + coords.keySet().size()
                  + " partition coordinators; missing responses from "
                  + missing.size()
                  + " members, removing them from the merge");
        merge_rsps.remove(missing);
      }

      /* 3. Remove null or rejected merge responses from merge_rsp and coords (so we'll send the new view
       * only to members who accepted the merge request) */
      if (missing != null && !missing.isEmpty()) {
        coords.keySet().removeAll(missing);
        coordsCopy.removeAll(missing);
      }

      removeRejectedMergeRequests(coords.keySet());
      if (merge_rsps.size() == 0)
        throw new Exception("did not get any merge responses from partition coordinators");

      if (!coords
          .keySet()
          .contains(
              gms.local_addr)) // another member might have invoked a merge req on us before we got
        // there...
        throw new Exception("merge leader rejected merge request");

      /* 4. Combine all views and digests into 1 View/1 Digest */
      List<MergeData> merge_data = new ArrayList<MergeData>(merge_rsps.getResults().values());
      MergeData combined_merge_data = consolidateMergeData(merge_data);
      if (combined_merge_data == null) throw new Exception("could not consolidate merge");

      /* 4. Send the new View/Digest to all coordinators (including myself). On reception, they will
      install the digest and view in all of their subgroup members */
      if (log.isDebugEnabled())
        log.debug(
            gms.local_addr
                + ": installing merge view "
                + combined_merge_data.view.getViewId()
                + " ("
                + combined_merge_data.view.size()
                + " members) in "
                + coords.keySet().size()
                + " coords");
      sendMergeView(coords.keySet(), combined_merge_data, new_merge_id);
    }
Exemple #17
0
 Address determineCoordinator() {
   List<Address> mbrs = my_view != null ? my_view.getMembers() : null;
   if (mbrs == null) return null;
   if (!mbrs.isEmpty()) return mbrs.iterator().next();
   return null;
 }