All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jgroups.protocols.UFC Maven / Gradle / Ivy

There is a newer version: 5.3.13.Final
Show newest version
package org.jgroups.protocols;

import org.jgroups.Address;
import org.jgroups.Header;
import org.jgroups.Message;
import org.jgroups.annotations.MBean;
import org.jgroups.annotations.ManagedAttribute;
import org.jgroups.annotations.ManagedOperation;
import org.jgroups.conf.AttributeType;
import org.jgroups.util.Credit;
import org.jgroups.util.Util;

import java.util.Iterator;
import java.util.List;
import java.util.Map;


/**
 * Simple flow control protocol based on a credit system. Each sender has a number of credits (bytes
 * to send). When the credits have been exhausted, the sender blocks. Each receiver also keeps track of
 * how many credits it has received from a sender. When credits for a sender fall below a threshold,
 * the receiver sends more credits to the sender. Works for both unicast and multicast messages.
 * 

* Note that this protocol must be located towards the top of the stack, or all down_threads from JChannel to this * protocol must be set to false ! This is in order to block JChannel.send()/JChannel.down(). *
This is the second simplified implementation of the same model. The algorithm is sketched out in * doc/FlowControl.txt *
* Changes (Brian) April 2006: *

    *
  1. Receivers now send credits to a sender when more than min_credits have been received (rather than when min_credits * are left) *
  2. Receivers don't send the full credits (max_credits), but rather the actual number of bytes received *
      * @author Bela Ban */ @MBean(description="Simple flow control protocol based on a credit system") public class UFC extends FlowControl { protected final static FcHeader UFC_REPLENISH_HDR = new FcHeader(FcHeader.REPLENISH); protected final static FcHeader UFC_CREDIT_REQUEST_HDR = new FcHeader(FcHeader.CREDIT_REQUEST); /** * Map: keys are members, values are credits left. For each send, * the number of credits is decremented by the message size */ protected final Map sent=Util.createConcurrentMap(); @ManagedOperation(description="Print sender credits") public String printSenderCredits() { return printMap(sent); } @ManagedOperation(description="Print credits") public String printCredits() { return String.format("%s\nsenders:\n%s", super.printCredits(), printMap(sent)); } protected boolean handleMulticastMessage() {return false;} @Override protected Header getReplenishHeader() {return UFC_REPLENISH_HDR;} @Override protected Header getCreditRequestHeader() {return UFC_CREDIT_REQUEST_HDR;} public void unblock() { super.unblock(); sent.values().forEach(cred -> cred.increment(max_credits, max_credits)); } public long getSenderCreditsFor(Address mbr) { Credit credits=sent.get(mbr); return credits == null? 0 : credits.get(); } @ManagedAttribute(description="Number of times flow control blocks sender",type=AttributeType.SCALAR) public int getNumberOfBlockings() { int retval=0; for(Credit cred: sent.values()) retval+=cred.getNumBlockings(); return retval; } @ManagedAttribute(description="Average time blocked (in ms) in flow control when trying to send a message", type=AttributeType.TIME) public double getAverageTimeBlocked() { return sent.values().stream().mapToDouble(c -> c.getAverageBlockTime() / 1_000_000).average().orElse(0.0); } public void stop() { super.stop(); unblock(); sent.values().forEach(Credit::reset); } public void resetStats() { super.resetStats(); sent.values().forEach(Credit::resetStats); } @Override protected Object handleDownMessage(final Message msg, int length) { Address dest=msg.getDest(); if(dest == null) { // 2nd line of defense, not really needed log.error("%s doesn't handle multicast messages; passing message down", getClass().getSimpleName()); return down_prot.down(msg); } Credit cred=sent.get(dest); if(cred == null) return down_prot.down(msg); while(running && sent.containsKey(dest)) { boolean rc=cred.decrementIfEnoughCredits(msg, length, max_block_time); if(rc || !running) break; if(cred.needToSendCreditRequest(max_block_time)) sendCreditRequest(dest, Math.max(0, max_credits - cred.get())); } // send message - either after regular processing, or after blocking (when enough credits available again) return down_prot.down(msg); } protected void handleViewChange(List
      mbrs) { super.handleViewChange(mbrs); if(mbrs == null) return; // add members not in membership to received and sent hashmap (with full credits) mbrs.stream().filter(addr -> !sent.containsKey(addr)).forEach(addr -> sent.put(addr, createCredit((int)max_credits))); // remove members that left Iterator> it=sent.entrySet().iterator(); while(it.hasNext()) { Map.Entry entry=it.next(); Address addr=entry.getKey(); if(!mbrs.contains(addr)) { Credit cred=entry.getValue(); cred.reset(); it.remove(); } } // sent.keySet().retainAll(mbrs); } protected void handleCredit(Address sender, long increase) { Credit cred; if(sender == null || (cred=sent.get(sender)) == null || increase <= 0) return; if(log.isTraceEnabled()) { long new_credit=Math.min(max_credits, cred.get() + increase); log.trace("received %d credits from %s, old credits: %s, new credits: %d", increase, sender, cred, new_credit); } cred.increment(increase, max_credits); } protected T createCredit(int initial_credits) { return (T)new Credit(initial_credits); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy