Exemple #1
0
  protected void forwardToCoord(long seqno, Message msg) {
    if (is_coord) {
      forward(msg, seqno, false);
      return;
    }

    if (!running || flushing) {
      forward_table.put(seqno, msg);
      return;
    }

    if (!ack_mode) {
      forward_table.put(seqno, msg);
      forward(msg, seqno, false);
      return;
    }

    send_lock.lock();
    try {
      forward_table.put(seqno, msg);
      while (running && !flushing) {
        ack_promise.reset();
        forward(msg, seqno, true);
        if (!ack_mode || !running || flushing) break;
        Long ack = ack_promise.getResult(500);
        if ((Objects.equals(ack, seqno)) || !forward_table.containsKey(seqno)) break;
      }
    } finally {
      send_lock.unlock();
    }
  }
Exemple #2
0
  protected void getState(Address target, long timeout, Callable<Boolean> flushInvoker)
      throws Exception {
    checkClosedOrNotConnected();
    if (!state_transfer_supported)
      throw new IllegalStateException(
          "fetching state will fail as state transfer is not supported. "
              + "Add one of the state transfer protocols to your configuration");

    if (target == null) target = determineCoordinator();
    if (target != null && local_addr != null && target.equals(local_addr)) {
      log.trace(
          local_addr
              + ": cannot get state from myself ("
              + target
              + "): probably the first member");
      return;
    }

    boolean initiateFlush = flushSupported() && flushInvoker != null;

    if (initiateFlush) {
      boolean successfulFlush = false;
      try {
        successfulFlush = flushInvoker.call();
      } catch (Throwable e) {
        successfulFlush = false; // http://jira.jboss.com/jira/browse/JGRP-759
      }
      if (!successfulFlush)
        throw new IllegalStateException(
            "Node " + local_addr + " could not flush the cluster for state retrieval");
    }

    state_promise.reset();
    StateTransferInfo state_info = new StateTransferInfo(target, timeout);
    long start = System.currentTimeMillis();
    down(new Event(Event.GET_STATE, state_info));
    StateTransferResult result = state_promise.getResult(state_info.timeout);

    if (initiateFlush) stopFlush();

    if (result == null)
      throw new StateTransferException(
          "timeout during state transfer (" + (System.currentTimeMillis() - start) + "ms)");
    if (result.hasException())
      throw new StateTransferException("state transfer failed", result.getException());
  }
Exemple #3
0
  /**
   * Sends all messages currently in forward_table to the new coordinator (changing the dest field).
   * This needs to be done, so the underlying reliable unicast protocol (e.g. UNICAST) adds these
   * messages to its retransmission mechanism<br>
   * Note that we need to resend the messages in order of their seqnos ! We also need to prevent
   * other message from being inserted until we're done, that's why there's synchronization.<br>
   * Access to the forward_table doesn't need to be synchronized as there won't be any insertions
   * during flushing (all down-threads are blocked)
   */
  protected void flushMessagesInForwardTable() {
    if (is_coord) {
      for (Map.Entry<Long, Message> entry : forward_table.entrySet()) {
        Long key = entry.getKey();
        Message msg = entry.getValue();
        Buffer buf;
        try {
          buf = Util.streamableToBuffer(msg);
        } catch (Exception e) {
          log.error(Util.getMessage("FlushingBroadcastingFailed"), e);
          continue;
        }

        SequencerHeader hdr = new SequencerHeader(SequencerHeader.WRAPPED_BCAST, key);
        Message forward_msg = new Message(null, buf).putHeader(this.id, hdr);
        if (log.isTraceEnabled())
          log.trace(local_addr + ": flushing (broadcasting) " + local_addr + "::" + key);
        down_prot.down(new Event(Event.MSG, forward_msg));
      }
      return;
    }

    // for forwarded messages, we need to receive the forwarded message from the coordinator, to
    // prevent this case:
    // - V1={A,B,C}
    // - A crashes
    // - C installs V2={B,C}
    // - C forwards messages 3 and 4 to B (the new coord)
    // - B drops 3 because its view is still V1
    // - B installs V2
    // - B receives message 4 and broadcasts it
    // ==> C's message 4 is delivered *before* message 3 !
    // ==> By resending 3 until it is received, then resending 4 until it is received, we make sure
    // this won't happen
    // (see https://issues.jboss.org/browse/JGRP-1449)
    while (flushing && running && !forward_table.isEmpty()) {
      Map.Entry<Long, Message> entry = forward_table.firstEntry();
      final Long key = entry.getKey();
      Message msg = entry.getValue();
      Buffer buf;

      try {
        buf = Util.streamableToBuffer(msg);
      } catch (Exception e) {
        log.error(Util.getMessage("FlushingBroadcastingFailed"), e);
        continue;
      }

      while (flushing && running && !forward_table.isEmpty()) {
        SequencerHeader hdr = new SequencerHeader(SequencerHeader.FLUSH, key);
        Message forward_msg =
            new Message(coord, buf).putHeader(this.id, hdr).setFlag(Message.Flag.DONT_BUNDLE);
        if (log.isTraceEnabled())
          log.trace(
              local_addr
                  + ": flushing (forwarding) "
                  + local_addr
                  + "::"
                  + key
                  + " to coord "
                  + coord);
        ack_promise.reset();
        down_prot.down(new Event(Event.MSG, forward_msg));
        Long ack = ack_promise.getResult(500);
        if ((Objects.equals(ack, key)) || !forward_table.containsKey(key)) break;
      }
    }
  }