Example #1
0
  public static void testSetAndGetWith5Seqnos() {
    SeqnoRange range = new SeqnoRange(10, 15);
    System.out.println("range=" + print(range));

    assert range.size() == 6;
    assert range.getNumberOfMissingMessages() == 6;
    assert range.getNumberOfReceivedMessages() == 0;

    range.set(10);
    assert range.getNumberOfMissingMessages() == 5;
    assert range.getNumberOfReceivedMessages() == 1;

    assert range.get(10);

    range.set(13);
    assert range.size() == 6;
    assert range.getNumberOfMissingMessages() == 4;
    assert range.getNumberOfReceivedMessages() == 2;

    range.set(13);
    assert range.size() == 6;
    assert range.getNumberOfMissingMessages() == 4;
    assert range.getNumberOfReceivedMessages() == 2;

    System.out.println("range=" + print(range));

    Collection<Range> xmits = range.getMessagesToRetransmit();
    Collection<Range> cleared_bits = range.getBits(false);

    System.out.println("xmits = " + xmits);
    System.out.println("cleared_bits = " + cleared_bits);

    assert xmits.equals(cleared_bits);
  }
Example #2
0
    /**
     * @param views Guaranteed to be non-null and to have >= 2 members, or else this thread would
     *     not be started
     */
    public synchronized void start(Map<Address, View> views) {
      if (thread == null || thread.isAlive()) {
        this.coords.clear();

        // now remove all members which don't have us in their view, so RPCs won't block (e.g.
        // FLUSH)
        // https://jira.jboss.org/browse/JGRP-1061
        sanitizeViews(views);

        // Add all different coordinators of the views into the hashmap and sets their members:
        Collection<Address> coordinators = Util.determineMergeCoords(views);
        for (Address coord : coordinators) {
          View view = views.get(coord);
          if (view != null) this.coords.put(coord, new ArrayList<Address>(view.getMembers()));
        }

        // For the merge participants which are not coordinator, we simply add them, and the
        // associated
        // membership list consists only of themselves
        Collection<Address> merge_participants = Util.determineMergeParticipants(views);
        merge_participants.removeAll(coordinators);
        for (Address merge_participant : merge_participants) {
          Collection<Address> tmp = new ArrayList<Address>();
          tmp.add(merge_participant);
          coords.putIfAbsent(merge_participant, tmp);
        }

        thread = gms.getThreadFactory().newThread(this, "MergeTask");
        thread.setDaemon(true);
        thread.start();
      }
    }
Example #3
0
 public void suspect(Address mbr) {
   if (mbr.equals(gms.local_addr)) {
     if (log.isWarnEnabled())
       log.warn("I am the coord and I'm suspected -- will probably leave shortly");
     return;
   }
   Collection<Request> suspected = new LinkedHashSet<>(1);
   suspected.add(new Request(Request.SUSPECT, mbr, true));
   handleMembershipChange(suspected);
 }
Example #4
0
  public void sendDiscoveryRequest(String cluster_name, Promise promise, ViewId view_id)
      throws Exception {
    PingData data = null;
    PhysicalAddress physical_addr =
        (PhysicalAddress) down(new Event(Event.GET_PHYSICAL_ADDRESS, local_addr));

    if (view_id == null) {
      List<PhysicalAddress> physical_addrs = Arrays.asList(physical_addr);
      data = new PingData(local_addr, null, false, UUID.get(local_addr), physical_addrs);
    }

    PingHeader hdr = new PingHeader(PingHeader.GET_MBRS_REQ, data, cluster_name);
    hdr.view_id = view_id;

    Collection<PhysicalAddress> cluster_members = fetchClusterMembers(cluster_name);
    if (cluster_members == null) {
      Message msg = new Message(null); // multicast msg
      msg.setFlag(Message.OOB);
      msg.putHeader(getId(), hdr);
      sendMcastDiscoveryRequest(msg);
    } else {
      if (cluster_members.isEmpty()) { // if we don't find any members, return immediately
        if (promise != null) promise.setResult(null);
      } else {
        for (final Address addr : cluster_members) {
          if (addr.equals(physical_addr)) // no need to send the request to myself
          continue;
          final Message msg = new Message(addr, null, null);
          msg.setFlag(Message.OOB);
          msg.putHeader(this.id, hdr);
          if (log.isTraceEnabled())
            log.trace("[FIND_INITIAL_MBRS] sending discovery request to " + msg.getDest());
          if (!sendDiscoveryRequestsInParallel()) {
            down_prot.down(new Event(Event.MSG, msg));
          } else {
            timer.execute(
                new Runnable() {
                  public void run() {
                    try {
                      down_prot.down(new Event(Event.MSG, msg));
                    } catch (Exception ex) {
                      if (log.isErrorEnabled())
                        log.error("failed sending discovery request to " + addr + ": " + ex);
                    }
                  }
                });
          }
        }
      }
    }
  }
Example #5
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);
  }
Example #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);
    }
Example #7
0
  /**
   * Invokes a method in all members and expects responses from members contained in dests (or all
   * members if dests is null).
   *
   * @param dests A list of addresses. If null, we'll wait for responses from all cluster members
   * @param method_call The method (plus args) to be invoked
   * @param options A collection of call options, e.g. sync versus async, timeout etc
   * @param listener A FutureListener which will be registered (if non null) with the future
   *     <em>before</em> the call is invoked
   * @return NotifyingFuture A future from which the results can be fetched
   * @throws Exception If the sending of the message threw an exception. Note that <em>no</em>
   *     exception will be thrown if any of the target members threw an exception; such an exception
   *     will be in the Rsp element for the particular member in the RspList
   */
  public <T> NotifyingFuture<RspList<T>> callRemoteMethodsWithFuture(
      Collection<Address> dests,
      MethodCall method_call,
      RequestOptions options,
      FutureListener<RspList<T>> listener)
      throws Exception {
    if (dests != null && dests.isEmpty()) { // don't send if dest list is empty
      if (log.isTraceEnabled())
        log.trace(
            "destination list of %s() is empty: no need to send message", method_call.getName());
      return new NullFuture<>(new RspList());
    }

    if (log.isTraceEnabled())
      log.trace("dests=%s, method_call=%s, options=%s", dests, method_call, options);

    Buffer buf =
        req_marshaller != null
            ? req_marshaller.objectToBuffer(method_call)
            : Util.objectToBuffer(method_call);
    Message msg = new Message().setBuffer(buf);

    NotifyingFuture<RspList<T>> retval = super.castMessageWithFuture(dests, msg, options, listener);
    if (log.isTraceEnabled()) log.trace("responses: %s", retval);
    return retval;
  }
Example #8
0
 private static boolean containsCoordinatorResponse(Collection<PingData> rsps) {
   if (rsps == null || rsps.isEmpty()) return false;
   for (PingData rsp : rsps) {
     if (rsp.isCoord()) return true;
   }
   return false;
 }
Example #9
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");
    }
  }
Example #10
0
 /**
  * Removed rejected merge requests from merge_rsps and coords. This method has a lock on
  * merge_rsps
  */
 private void removeRejectedMergeRequests(Collection<Address> coords) {
   for (Map.Entry<Address, MergeData> entry : merge_rsps.getResults().entrySet()) {
     Address member = entry.getKey();
     MergeData data = entry.getValue();
     if (data.merge_rejected) {
       if (data.getSender() != null) coords.remove(data.getSender());
       merge_rsps.remove(member);
     }
   }
 }
Example #11
0
 /**
  * Removes all members from a given view which don't have us in their view
  * (https://jira.jboss.org/browse/JGRP-1061). Example:
  *
  * <pre>
  * A: AB
  * B: AB
  * C: ABC
  * </pre>
  *
  * becomes
  *
  * <pre>
  * A: AB
  * B: AB
  * C: C // A and B don't have C in their views
  * </pre>
  *
  * @param map A map of members and their associated views
  */
 public static void sanitizeViews(Map<Address, View> map) {
   if (map == null) return;
   for (Map.Entry<Address, View> entry : map.entrySet()) {
     Address key = entry.getKey();
     Collection<Address> members = new ArrayList<Address>(entry.getValue().getMembers());
     boolean modified = false;
     for (Iterator<Address> it = members.iterator(); it.hasNext(); ) {
       Address val = it.next();
       if (val.equals(key)) // we can always talk to ourself !
       continue;
       View view = map.get(val);
       final Collection<Address> tmp_mbrs = view != null ? view.getMembers() : null;
       if (tmp_mbrs != null && !tmp_mbrs.contains(key)) {
         it.remove();
         modified = true;
       }
     }
     if (modified) {
       View old_view = entry.getValue();
       entry.setValue(new View(old_view.getVid(), members));
     }
   }
 }
Example #12
0
  /**
   * Invokes a method in all members contained in dests (or all members if dests is null).
   *
   * @param dests A list of addresses. If null, the method will be invoked on all cluster members
   * @param method_call The method (plus args) to be invoked
   * @param options A collection of call options, e.g. sync versus async, timeout etc
   * @return RspList A list of return values and flags (suspected, not received) per member
   * @since 2.9
   */
  public RspList callRemoteMethods(
      Collection<Address> dests, MethodCall method_call, RequestOptions options) {
    if (dests != null && dests.isEmpty()) { // don't send if dest list is empty
      if (log.isTraceEnabled())
        log.trace(
            new StringBuilder("destination list of ")
                .append(method_call.getName())
                .append("() is empty: no need to send message"));
      return RspList.EMPTY_RSP_LIST;
    }

    if (log.isTraceEnabled())
      log.trace(
          new StringBuilder("dests=")
              .append(dests)
              .append(", method_call=")
              .append(method_call)
              .append(", options=")
              .append(options));

    Object buf;
    try {
      buf =
          req_marshaller != null
              ? req_marshaller.objectToBuffer(method_call)
              : Util.objectToByteBuffer(method_call);
    } catch (Exception e) {
      // if(log.isErrorEnabled()) log.error("exception", e);
      // we will change this in 3.0 to add the exception to the signature
      // (see http://jira.jboss.com/jira/browse/JGRP-193). The reason for a RTE is that we cannot
      // change the
      // signature in 2.3, otherwise 2.3 would be *not* API compatible to prev releases
      throw new RuntimeException("failure to marshal argument(s)", e);
    }

    Message msg = new Message();
    if (buf instanceof Buffer) msg.setBuffer((Buffer) buf);
    else msg.setBuffer((byte[]) buf);

    msg.setFlag(options.getFlags());
    if (options.getScope() > 0) msg.setScope(options.getScope());

    RspList retval = super.castMessage(dests, msg, options);
    if (log.isTraceEnabled()) log.trace("responses: " + retval);
    return retval;
  }
Example #13
0
    /**
     * Removed rejected merge requests from merge_rsps and coords. This method has a lock on
     * merge_rsps
     */
    private void removeRejectedMergeRequests(Collection<Address> coords) {
      int num_removed = 0;
      for (Iterator<Map.Entry<Address, MergeData>> it =
              merge_rsps.getResults().entrySet().iterator();
          it.hasNext(); ) {
        Map.Entry<Address, MergeData> entry = it.next();
        MergeData data = entry.getValue();
        if (data.merge_rejected) {
          if (data.getSender() != null) coords.remove(data.getSender());
          it.remove();
          num_removed++;
        }
      }

      if (num_removed > 0) {
        if (log.isTraceEnabled())
          log.trace(gms.local_addr + ": removed " + num_removed + " rejected merge responses");
      }
    }
Example #14
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
    }
  }
Example #15
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);
    }
Example #16
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();
  }
Example #17
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;
  }
Example #18
0
  /**
   * An event was received from the layer below. Usually the current layer will want to examine the
   * event type and - depending on its type - perform some computation (e.g. removing headers from a
   * MSG event type, or updating the internal membership list when receiving a VIEW_CHANGE event).
   * Finally the event is either a) discarded, or b) an event is sent down the stack using <code>
   * PassDown</code> or c) the event (or another event) is sent up the stack using <code>PassUp
   * </code>.
   *
   * <p>For the PING protocol, the Up operation does the following things. 1. If the event is a
   * Event.MSG then PING will inspect the message header. If the header is null, PING simply passes
   * up the event If the header is PingHeader.GET_MBRS_REQ then the PING protocol will PassDown a
   * PingRequest message If the header is PingHeader.GET_MBRS_RSP we will add the message to the
   * initial members vector and wake up any waiting threads. 2. If the event is Event.SET_LOCAL_ADDR
   * we will simple set the local address of this protocol 3. For all other messages we simple pass
   * it up to the protocol above
   *
   * @param evt - the event that has been sent from the layer below
   */
  @SuppressWarnings("unchecked")
  public Object up(Event evt) {

    switch (evt.getType()) {
      case Event.MSG:
        Message msg = (Message) evt.getArg();
        PingHeader hdr = (PingHeader) msg.getHeader(this.id);
        if (hdr == null) return up_prot.up(evt);

        PingData data = hdr.data;
        Address logical_addr = data != null ? data.getAddress() : null;

        if (is_leaving) return null; // prevents merging back a leaving member
        // (https://issues.jboss.org/browse/JGRP-1336)

        switch (hdr.type) {
          case PingHeader.GET_MBRS_REQ: // return Rsp(local_addr, coord)
            if (group_addr == null || hdr.cluster_name == null) {
              if (log.isWarnEnabled())
                log.warn(
                    "group_addr ("
                        + group_addr
                        + ") or cluster_name of header ("
                        + hdr.cluster_name
                        + ") is null; passing up discovery request from "
                        + msg.getSrc()
                        + ", but this should not"
                        + " be the case");
            } else {
              if (!group_addr.equals(hdr.cluster_name)) {
                if (log.isWarnEnabled())
                  log.warn(
                      "discarding discovery request for cluster '"
                          + hdr.cluster_name
                          + "' from "
                          + msg.getSrc()
                          + "; our cluster name is '"
                          + group_addr
                          + "'. "
                          + "Please separate your clusters cleanly.");
                return null;
              }
            }

            // add physical address and logical name of the discovery sender (if available) to the
            // cache
            if (data != null) {
              if (logical_addr == null) logical_addr = msg.getSrc();
              Collection<PhysicalAddress> physical_addrs = data.getPhysicalAddrs();
              PhysicalAddress physical_addr =
                  physical_addrs != null && !physical_addrs.isEmpty()
                      ? physical_addrs.iterator().next()
                      : null;
              if (logical_addr != null && physical_addr != null)
                down(
                    new Event(
                        Event.SET_PHYSICAL_ADDRESS,
                        new Tuple<Address, PhysicalAddress>(logical_addr, physical_addr)));
              if (logical_addr != null && data.getLogicalName() != null)
                UUID.add(logical_addr, data.getLogicalName());
              discoveryRequestReceived(msg.getSrc(), data.getLogicalName(), physical_addrs);

              synchronized (ping_responses) {
                for (Responses response : ping_responses) {
                  response.addResponse(data, false);
                }
              }
            }

            if (hdr.view_id != null) {
              // If the discovery request is merge-triggered, and the ViewId shipped with it
              // is the same as ours, we don't respond (JGRP-1315).
              ViewId my_view_id = view != null ? view.getViewId() : null;
              if (my_view_id != null && my_view_id.equals(hdr.view_id)) return null;

              boolean send_discovery_rsp =
                  force_sending_discovery_rsps
                      || is_coord
                      || current_coord == null
                      || current_coord.equals(msg.getSrc());
              if (!send_discovery_rsp) {
                if (log.isTraceEnabled())
                  log.trace(
                      local_addr
                          + ": suppressing merge response as I'm not a coordinator and the "
                          + "discovery request was not sent by a coordinator");
                return null;
              }
            }

            if (isMergeRunning()) {
              if (log.isTraceEnabled())
                log.trace(
                    local_addr + ": suppressing merge response as a merge is already in progress");
              return null;
            }

            List<PhysicalAddress> physical_addrs =
                hdr.view_id != null
                    ? null
                    : Arrays.asList(
                        (PhysicalAddress) down(new Event(Event.GET_PHYSICAL_ADDRESS, local_addr)));
            sendDiscoveryResponse(
                local_addr,
                physical_addrs,
                is_server,
                hdr.view_id != null,
                UUID.get(local_addr),
                msg.getSrc());
            return null;

          case PingHeader.GET_MBRS_RSP: // add response to vector and notify waiting thread
            // add physical address (if available) to transport's cache
            if (data != null) {
              Address response_sender = msg.getSrc();
              if (logical_addr == null) logical_addr = msg.getSrc();
              Collection<PhysicalAddress> addrs = data.getPhysicalAddrs();
              PhysicalAddress physical_addr =
                  addrs != null && !addrs.isEmpty() ? addrs.iterator().next() : null;
              if (logical_addr != null && physical_addr != null)
                down(
                    new Event(
                        Event.SET_PHYSICAL_ADDRESS,
                        new Tuple<Address, PhysicalAddress>(logical_addr, physical_addr)));
              if (logical_addr != null && data.getLogicalName() != null)
                UUID.add(logical_addr, data.getLogicalName());

              if (log.isTraceEnabled())
                log.trace(
                    local_addr + ": received GET_MBRS_RSP from " + response_sender + ": " + data);
              boolean overwrite = logical_addr != null && logical_addr.equals(response_sender);
              synchronized (ping_responses) {
                for (Responses response : ping_responses) {
                  response.addResponse(data, overwrite);
                }
              }
            }
            return null;

          default:
            if (log.isWarnEnabled())
              log.warn("got PING header with unknown type (" + hdr.type + ')');
            return null;
        }

      case Event.GET_PHYSICAL_ADDRESS:
        try {
          sendDiscoveryRequest(group_addr, null, null);
        } catch (InterruptedIOException ie) {
          if (log.isWarnEnabled()) {
            log.warn("Discovery request for cluster " + group_addr + " interrupted");
          }
          Thread.currentThread().interrupt();
        } catch (Exception ex) {
          if (log.isErrorEnabled()) log.error("failed sending discovery request", ex);
        }
        return null;

      case Event.FIND_INITIAL_MBRS: // sent by transport
        return findInitialMembers(null);
    }

    return up_prot.up(evt);
  }
Example #19
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());
        }
      }
    }
  }
Example #20
0
  @SuppressWarnings("unchecked")
  public Object up(Event evt) {
    switch (evt.getType()) {
      case Event.MSG:
        Message msg = (Message) evt.getArg();
        PingHeader hdr = (PingHeader) msg.getHeader(this.id);
        if (hdr == null) return up_prot.up(evt);

        if (is_leaving) return null; // prevents merging back a leaving member
        // (https://issues.jboss.org/browse/JGRP-1336)

        PingData data = readPingData(msg.getRawBuffer(), msg.getOffset(), msg.getLength());
        Address logical_addr = data != null ? data.getAddress() : msg.src();

        switch (hdr.type) {
          case PingHeader.GET_MBRS_REQ: // return Rsp(local_addr, coord)
            if (cluster_name == null || hdr.cluster_name == null) {
              log.warn(
                  "cluster_name (%s) or cluster_name of header (%s) is null; passing up discovery "
                      + "request from %s, but this should not be the case",
                  cluster_name, hdr.cluster_name, msg.src());
            } else {
              if (!cluster_name.equals(hdr.cluster_name)) {
                log.warn(
                    "%s: discarding discovery request for cluster '%s' from %s; "
                        + "our cluster name is '%s'. Please separate your clusters properly",
                    logical_addr, hdr.cluster_name, msg.src(), cluster_name);
                return null;
              }
            }

            // add physical address and logical name of the discovery sender (if available) to the
            // cache
            if (data != null) {
              addDiscoveryResponseToCaches(
                  logical_addr, data.getLogicalName(), data.getPhysicalAddr());
              discoveryRequestReceived(msg.getSrc(), data.getLogicalName(), data.getPhysicalAddr());
              addResponse(data, false);
            }

            if (return_entire_cache) {
              Map<Address, PhysicalAddress> cache =
                  (Map<Address, PhysicalAddress>)
                      down(new Event(Event.GET_LOGICAL_PHYSICAL_MAPPINGS));
              if (cache != null) {
                for (Map.Entry<Address, PhysicalAddress> entry : cache.entrySet()) {
                  Address addr = entry.getKey();
                  // JGRP-1492: only return our own address, and addresses in view.
                  if (addr.equals(local_addr) || members.contains(addr)) {
                    PhysicalAddress physical_addr = entry.getValue();
                    sendDiscoveryResponse(
                        addr, physical_addr, UUID.get(addr), msg.getSrc(), isCoord(addr));
                  }
                }
              }
              return null;
            }

            // Only send a response if hdr.mbrs is not empty and contains myself. Otherwise always
            // send my info
            Collection<? extends Address> mbrs = data != null ? data.mbrs() : null;
            boolean send_response = mbrs == null || mbrs.contains(local_addr);
            if (send_response) {
              PhysicalAddress physical_addr =
                  (PhysicalAddress) down(new Event(Event.GET_PHYSICAL_ADDRESS, local_addr));
              sendDiscoveryResponse(
                  local_addr, physical_addr, UUID.get(local_addr), msg.getSrc(), is_coord);
            }
            return null;

          case PingHeader.GET_MBRS_RSP:
            // add physical address (if available) to transport's cache
            if (data != null) {
              log.trace("%s: received GET_MBRS_RSP from %s: %s", local_addr, msg.src(), data);
              handleDiscoveryResponse(data, msg.src());
            }
            return null;

          default:
            log.warn("got PING header with unknown type %d", hdr.type);
            return null;
        }

      case Event.FIND_MBRS:
        return findMembers(
            (List<Address>) evt.getArg(), false, true); // this is done asynchronously
    }

    return up_prot.up(evt);
  }