Exemple #1
0
  public static void testDetermineMergeParticipantsAndMergeCoords4() {
    Address a = Util.createRandomAddress(),
        b = Util.createRandomAddress(),
        c = Util.createRandomAddress(),
        d = Util.createRandomAddress();
    org.jgroups.util.UUID.add(a, "A");
    org.jgroups.util.UUID.add(b, "B");
    org.jgroups.util.UUID.add(c, "C");
    org.jgroups.util.UUID.add(d, "D");

    View v1 = View.create(a, 1, a, b);
    View v2 = View.create(c, 1, c, d);

    Map<Address, View> map = new HashMap<>();
    map.put(a, v1);
    map.put(b, v1);
    map.put(d, v2);

    StringBuilder sb = new StringBuilder("map:\n");
    for (Map.Entry<Address, View> entry : map.entrySet())
      sb.append(entry.getKey() + ": " + entry.getValue() + "\n");
    System.out.println(sb);

    Collection<Address> merge_participants = Util.determineMergeParticipants(map);
    System.out.println("merge_participants = " + merge_participants);
    assert merge_participants.size() == 3;
    assert merge_participants.contains(a)
        && merge_participants.contains(c)
        && merge_participants.contains(d);

    Collection<Address> merge_coords = Util.determineMergeCoords(map);
    System.out.println("merge_coords = " + merge_coords);
    assert merge_coords.size() == 2;
    assert merge_coords.contains(a) && merge_coords.contains(c);
  }
Exemple #2
0
  public static void testGetBits() {
    SeqnoRange range = new SeqnoRange(1, 100);
    System.out.println("range = " + range);
    assert range.size() == 100;

    Collection<Range> bits = range.getBits(false);
    assert bits.size() == 1;
    Range tmp = bits.iterator().next();
    assert tmp.low == 1 && tmp.high == 100;

    range.set(1, 2);
    assert range.size() == 100;

    bits = range.getBits(true);
    assert bits != null && bits.size() == 1; // 1 range: [1-2]
    tmp = bits.iterator().next();
    assert tmp.low == 1 && tmp.high == 2;

    for (int i = 1; i < 100; i++) range.set(i);

    bits = range.getBits(false);
    assert bits.size() == 1;
    tmp = bits.iterator().next();
    assert tmp.low == 100 && tmp.high == 100;

    for (int i = 1; i <= range.size(); i++) range.clear(i);

    for (int i = 2; i <= 99; i++) range.set(i);

    bits = range.getBits(true);
    assert bits.size() == 1;
    tmp = bits.iterator().next();
    assert tmp.low == 2 && tmp.high == 99;

    bits = range.getBits(false);
    assert bits.size() == 2;

    tmp = bits.iterator().next();
    assert tmp.low == 1 && tmp.high == 1;

    Iterator<Range> it = bits.iterator();
    it.next();
    tmp = it.next();
    assert tmp.low == 100 && tmp.high == 100;
  }
Exemple #3
0
  /**
   * Invoked upon receiving a MERGE event from the MERGE layer. Starts the merge protocol. See
   * description of protocol in DESIGN.
   *
   * @param views A List of <em>different</em> views detected by the merge protocol
   */
  public void merge(Map<Address, View> views) {
    if (isMergeInProgress()) {
      if (log.isTraceEnabled())
        log.trace(gms.local_addr + ": merge is already running (merge_id=" + merge_id + ")");
      return;
    }

    // we need the merge *coordinators* not merge participants because not everyone can lead a merge
    // !
    Collection<Address> coords = Util.determineActualMergeCoords(views);
    if (coords.isEmpty()) {
      log.error(
          gms.local_addr
              + ": unable to determine merge leader from "
              + views
              + "; not starting a merge");
      return;
    }

    Membership tmp =
        new Membership(coords); // establish a deterministic order, so that coords can elect leader
    tmp.sort();
    Address merge_leader = tmp.elementAt(0);
    if (merge_leader.equals(gms.local_addr)) {
      if (log.isDebugEnabled()) {
        Collection<Address> merge_participants = Util.determineMergeParticipants(views);
        log.debug(
            "I ("
                + gms.local_addr
                + ") will be the leader. Starting the merge task for "
                + merge_participants.size()
                + " coords");
      }
      merge_task.start(views);
    } else {
      if (log.isTraceEnabled())
        log.trace(
            "I ("
                + gms.local_addr
                + ") am not the merge leader, "
                + "waiting for merge leader ("
                + merge_leader
                + ") to initiate merge");
    }
  }
Exemple #4
0
  public void handleMembershipChange(Collection<Request> requests) {
    boolean joinAndStateTransferInitiated = false;
    boolean useFlushIfPresent = gms.use_flush_if_present;
    Collection<Address> new_mbrs = new LinkedHashSet<>(requests.size());
    Collection<Address> suspected_mbrs = new LinkedHashSet<>(requests.size());
    Collection<Address> leaving_mbrs = new LinkedHashSet<>(requests.size());

    boolean self_leaving = false; // is the coord leaving

    for (Request req : requests) {
      switch (req.type) {
        case Request.JOIN:
          new_mbrs.add(req.mbr);
          if (req.useFlushIfPresent) useFlushIfPresent = true;
          break;
        case Request.JOIN_WITH_STATE_TRANSFER:
          new_mbrs.add(req.mbr);
          joinAndStateTransferInitiated = true;
          if (req.useFlushIfPresent) useFlushIfPresent = true;
          break;
        case Request.LEAVE:
          if (req.suspected) suspected_mbrs.add(req.mbr);
          else {
            leaving_mbrs.add(req.mbr);
            if (gms.local_addr != null && gms.local_addr.equals(req.mbr)) self_leaving = true;
          }
          break;
        case Request.SUSPECT:
          suspected_mbrs.add(req.mbr);
          break;
      }
    }

    new_mbrs.remove(gms.local_addr); // remove myself - cannot join myself (already joined)

    if (gms.getViewId() == null) {
      // we're probably not the coord anymore (we just left ourselves), let someone else do it
      // (client will retry when it doesn't get a response)
      log.debug(
          "gms.view_id is null, I'm not the coordinator anymore (leaving=%b); "
              + "the new coordinator will handle the leave request",
          self_leaving);
      return;
    }

    List<Address> current_members = gms.members.getMembers();
    leaving_mbrs.retainAll(
        current_members); // remove all elements of leaving_mbrs which are not current members
    if (suspected_mbrs.remove(gms.local_addr))
      log.warn("I am the coord and I'm being suspected -- will probably leave shortly");

    suspected_mbrs.retainAll(
        current_members); // remove all elements of suspected_mbrs which are not current members

    // for the members that have already joined, return the current digest and membership
    for (Iterator<Address> it = new_mbrs.iterator(); it.hasNext(); ) {
      Address mbr = it.next();
      if (gms.members.contains(mbr)) { // already joined: return current digest and membership
        log.trace(
            "%s: %s already present; returning existing view %s", gms.local_addr, mbr, gms.view);
        Tuple<View, Digest> tuple = gms.getViewAndDigest();
        if (tuple != null) gms.sendJoinResponse(new JoinRsp(tuple.getVal1(), tuple.getVal2()), mbr);
        else
          log.warn(
              "%s: did not find a digest matching view %s; dropping JOIN-RSP",
              gms.local_addr, gms.view);
        it
            .remove(); // remove it anyway, even if we didn't find a digest matching the view
                       // (joiner will retry)
      }
    }

    if (new_mbrs.isEmpty() && leaving_mbrs.isEmpty() && suspected_mbrs.isEmpty()) {
      log.trace("%s: found no members to add or remove, will not create new view", gms.local_addr);
      return;
    }

    View new_view = gms.getNextView(new_mbrs, leaving_mbrs, suspected_mbrs);

    if (new_view.size() == 0
        && gms.local_addr != null
        && gms.local_addr.equals(new_view.getCreator())) {
      if (self_leaving) gms.initState(); // in case connect() is called again
      return;
    }

    log.trace(
        "%s: joiners=%s, suspected=%s, leaving=%s, new view: %s",
        gms.local_addr, new_mbrs, suspected_mbrs, leaving_mbrs, new_view);

    JoinRsp join_rsp = null;
    boolean hasJoiningMembers = !new_mbrs.isEmpty();
    try {
      boolean successfulFlush =
          !useFlushIfPresent || !gms.flushProtocolInStack || gms.startFlush(new_view);
      if (!successfulFlush && hasJoiningMembers) {
        // Don't send a join response if the flush fails
        // (http://jira.jboss.org/jira/browse/JGRP-759)
        // The joiner should block until the previous FLUSH completed
        sendLeaveResponses(leaving_mbrs); // we still have to send potential leave responses
        // but let the joining client timeout and send another join request
        return;
      }

      // we cannot garbage collect during joining a new member *if* we're the only member
      // Example: {A}, B joins, after returning JoinRsp to B, A garbage collects messages higher
      // than those
      // in the digest returned to the client, so the client will *not* be able to ask for
      // retransmission
      // of those messages if he misses them
      if (hasJoiningMembers) {
        gms.getDownProtocol().down(new Event(Event.SUSPEND_STABLE, MAX_SUSPEND_TIMEOUT));
        // create a new digest, which contains the new members, minus left members
        MutableDigest join_digest =
            new MutableDigest(new_view.getMembersRaw()).set(gms.getDigest());
        for (Address member : new_mbrs)
          join_digest.set(member, 0, 0); // ... and set the new members. their first seqno will be 1

        // If the digest from NAKACK doesn't include all members of the view, we try once more; if
        // it is still
        // incomplete, we don't send a JoinRsp back to the joiner(s). This shouldn't be a problem as
        // they will retry
        if (join_digest.allSet() || join_digest.set(gms.getDigest()).allSet())
          join_rsp = new JoinRsp(new_view, join_digest);
        else
          log.warn(
              "%s: digest does not match view (missing seqnos for %s); dropping JOIN-RSP",
              gms.local_addr, Arrays.toString(join_digest.getNonSetMembers()));
      }

      sendLeaveResponses(leaving_mbrs); // no-op if no leaving members

      // we don't need to send the digest to existing members:
      // https://issues.jboss.org/browse/JGRP-1317
      gms.castViewChange(new_view, null, new_mbrs);
      gms.sendJoinResponses(join_rsp, new_mbrs);
    } finally {
      if (hasJoiningMembers) gms.getDownProtocol().down(new Event(Event.RESUME_STABLE));
      if (!joinAndStateTransferInitiated && useFlushIfPresent) gms.stopFlush();
      if (self_leaving) gms.initState(); // in case connect() is called again
    }
  }
Exemple #5
0
  public static void testSet() {
    SeqnoRange range = new SeqnoRange(10, 15);
    range.set(11, 12, 13, 14);
    System.out.println("range=" + print(range));
    assert range.size() == 6;
    assert range.getNumberOfReceivedMessages() == 4;
    assert range.getNumberOfMissingMessages() == 2;
    Collection<Range> xmits = range.getMessagesToRetransmit();
    assert xmits.size() == 2;
    Iterator<Range> it = xmits.iterator();
    Range r = it.next();
    assert r.low == 10 && r.high == 10;
    r = it.next();
    assert r.low == 15 && r.high == 15;

    range = new SeqnoRange(10, 15);
    range.set(10, 11, 12, 13, 14);
    System.out.println("range=" + print(range));
    assert range.size() == 6;
    assert range.getNumberOfReceivedMessages() == 5;
    assert range.getNumberOfMissingMessages() == 1;
    xmits = range.getMessagesToRetransmit();
    assert xmits.size() == 1;
    it = xmits.iterator();
    r = it.next();
    assert r.low == 15 && r.high == 15;

    range = new SeqnoRange(10, 15);
    range.set(11, 12, 13, 14, 15);
    System.out.println("range=" + print(range));
    assert range.size() == 6;
    assert range.getNumberOfReceivedMessages() == 5;
    assert range.getNumberOfMissingMessages() == 1;
    xmits = range.getMessagesToRetransmit();
    assert xmits.size() == 1;
    it = xmits.iterator();
    r = it.next();
    assert r.low == 10 && r.high == 10;

    range = new SeqnoRange(10, 15);
    range.set(10, 11, 12, 13, 14, 15);
    System.out.println("range=" + print(range));
    assert range.size() == 6;
    assert range.getNumberOfReceivedMessages() == 6;
    assert range.getNumberOfMissingMessages() == 0;
    xmits = range.getMessagesToRetransmit();
    assert xmits.isEmpty();

    range = new SeqnoRange(10, 15);
    range.set(11, 12, 14, 15);
    System.out.println("range=" + print(range));
    assert range.size() == 6;
    assert range.getNumberOfReceivedMessages() == 4;
    assert range.getNumberOfMissingMessages() == 2;
    xmits = range.getMessagesToRetransmit();
    assert xmits.size() == 2;
    it = xmits.iterator();
    r = it.next();
    assert r.low == 10 && r.high == 10;
    r = it.next();
    assert r.low == 13 && r.high == 13;

    range.set(13);
    assert range.getNumberOfReceivedMessages() == 5;
    assert range.getNumberOfMissingMessages() == 1;
    xmits = range.getMessagesToRetransmit();
    it = xmits.iterator();
    r = it.next();
    assert r.low == 10 && r.high == 10;

    range.set(10);
    System.out.println("range=" + print(range));
    assert range.getNumberOfReceivedMessages() == 6;
    assert range.getNumberOfMissingMessages() == 0;
    xmits = range.getMessagesToRetransmit();
    assert xmits.isEmpty();
  }