Beispiel #1
0
  @ManagedOperation(
      description =
          "Sends a STABLE message to all senders. This causes message purging and potential"
              + " retransmissions from senders")
  public void sendStableMessages() {
    for (Map.Entry<Address, ReceiverEntry> entry : recv_table.entrySet()) {
      Address dest = entry.getKey();
      ReceiverEntry val = entry.getValue();
      NakReceiverWindow win = val != null ? val.received_msgs : null;
      if (win != null) {
        long[] tmp = win.getDigest();
        long low = tmp[0], high = tmp[1];

        if (val.last_highest == high) {
          if (val.num_stable_msgs >= val.max_stable_msgs) {
            continue;
          } else val.num_stable_msgs++;
        } else {
          val.last_highest = high;
          val.num_stable_msgs = 1;
        }
        sendStableMessage(dest, val.recv_conn_id, low, high);
      }
    }
  }
Beispiel #2
0
 /**
  * This method is public only so it can be invoked by unit testing, but should not otherwise be
  * used !
  */
 @ManagedOperation(
     description = "Trashes all connections to other nodes. This is only used for testing")
 public void removeAllConnections() {
   send_table.clear();
   sendStableMessages();
   for (ReceiverEntry entry2 : recv_table.values()) entry2.reset();
   recv_table.clear();
 }
Beispiel #3
0
 public void removeReceiveConnection(Address mbr) {
   ReceiverEntry entry2 = recv_table.remove(mbr);
   if (entry2 != null) {
     NakReceiverWindow win = entry2.received_msgs;
     if (win != null)
       sendStableMessage(
           mbr, entry2.recv_conn_id, win.getHighestDelivered(), win.getHighestReceived());
     entry2.reset();
   }
 }
Beispiel #4
0
  protected void handleBatchReceived(Address sender, Map<Short, List<Message>> map) {
    for (Map.Entry<Short, List<Message>> element : map.entrySet()) {
      final List<Message> msg_list = element.getValue();
      if (log.isTraceEnabled()) {
        StringBuilder sb = new StringBuilder();
        sb.append(local_addr)
            .append(" <-- DATA(")
            .append(sender)
            .append(": " + printMessageList(msg_list))
            .append(')');
        log.trace(sb);
      }

      short conn_id = element.getKey();
      ReceiverEntry entry = null;
      for (Message msg : msg_list) {
        UnicastHeader hdr = (UnicastHeader) msg.getHeader(id);
        entry = getReceiverEntry(sender, hdr.seqno, hdr.first, conn_id);
        if (entry == null) continue;
        Table<Message> win = entry.received_msgs;
        boolean msg_added =
            win.add(hdr.seqno, msg); // win is guaranteed to be non-null if we get here
        num_msgs_received++;

        if (hdr.first && msg_added)
          sendAck(
              sender, hdr.seqno,
              conn_id); // send an ack immediately when we received the first message of a conn

        // 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.Flag.OOB) && msg_added) {
          try {
            up_prot.up(new Event(Event.MSG, msg));
          } catch (Throwable t) {
            log.error("couldn't deliver OOB message " + msg, t);
          }
        }
      }
      if (entry != null && conn_expiry_timeout > 0) entry.update();
    }

    ReceiverEntry entry = recv_table.get(sender);
    Table<Message> win = entry != null ? entry.received_msgs : null;
    if (win != null) {
      final AtomicBoolean processing = win.getProcessing();
      if (processing.compareAndSet(false, true)) {
        removeAndDeliver(processing, win, sender);
        sendAck(sender, win.getHighestDeliverable(), entry.recv_conn_id);
      }
    }
  }
Beispiel #5
0
  /**
   * Check whether the hashtable 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++;

    // 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 (from the AckReceiverWindow) as many messages as possible as 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
    int num_msgs = removeAndDeliver(processing, win);
    if (num_msgs > 0) {
      long hd = win.getHighestDelivered();
      sendAck(sender, hd);
    }
  }
Beispiel #6
0
  @ManagedOperation(
      description = "Closes connections that have been idle for more than conn_expiry_timeout ms")
  public void reapIdleConnections() {
    if (conn_expiry_timeout <= 0) return;

    // remove expired connections from send_table
    for (Map.Entry<Address, SenderEntry> entry : send_table.entrySet()) {
      SenderEntry val = entry.getValue();
      long age = val.age();
      if (age >= conn_expiry_timeout) {
        removeSendConnection(entry.getKey());
        if (log.isDebugEnabled())
          log.debug(
              local_addr
                  + ": removed expired connection for "
                  + entry.getKey()
                  + " ("
                  + age
                  + " ms old) from send_table");
      }
    }

    // remove expired connections from recv_table
    for (Map.Entry<Address, ReceiverEntry> entry : recv_table.entrySet()) {
      ReceiverEntry val = entry.getValue();
      long age = val.age();
      if (age >= conn_expiry_timeout) {
        removeReceiveConnection(entry.getKey());
        if (log.isDebugEnabled())
          log.debug(
              local_addr
                  + ": removed expired connection for "
                  + entry.getKey()
                  + " ("
                  + age
                  + " ms old) from recv_table");
      }
    }
  }
Beispiel #7
0
  /**
   * Check whether the hashtable 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;
    NakReceiverWindow win;

    recv_table_lock.lock();
    try {
      entry = recv_table.get(sender);
      win = entry != null ? entry.received_msgs : null;
      if (first) {
        if (entry == null) {
          entry = getOrCreateReceiverEntry(sender, seqno, conn_id);
          win = entry.received_msgs;
        } else { // entry != null && win != null
          if (conn_id != entry.recv_conn_id) {
            if (log.isTraceEnabled())
              log.trace(
                  local_addr
                      + ": conn_id="
                      + conn_id
                      + " != "
                      + entry.recv_conn_id
                      + "; resetting receiver window");

            ReceiverEntry entry2 = recv_table.remove(sender);
            if (entry2 != null) entry2.received_msgs.destroy();

            entry = getOrCreateReceiverEntry(sender, seqno, conn_id);
            win = entry.received_msgs;
          } else {;
          }
        }
      } else { // entry == null && win == null OR entry != null && win == null OR entry != null &&
               // win != null
        if (win == null || entry.recv_conn_id != conn_id) {
          recv_table_lock.unlock();
          sendRequestForFirstSeqno(sender, seqno); // drops the message and returns (see below)
          return;
        }
      }
    } finally {
      if (recv_table_lock.isHeldByCurrentThread()) recv_table_lock.unlock();
    }

    entry.update();
    boolean added = win.add(seqno, msg); // win is guaranteed to be non-null if we get here
    num_msgs_received++;
    num_bytes_received += msg.getLength();

    if (added) {
      int len = msg.getLength();
      if (len > 0) {
        boolean send_stable_msg = false;
        entry.lock();
        try {
          entry.received_bytes += len;
          if (entry.received_bytes >= max_bytes) {
            entry.received_bytes = 0;
            send_stable_msg = true;
          }
        } finally {
          entry.unlock();
        }

        if (send_stable_msg)
          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 (from the AckReceiverWindow) 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);
    }
  }
Beispiel #8
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);
    }
  }