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

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

There is a newer version: 9.1.7.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.util.CreditMap;
import org.jgroups.util.Tuple;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;


/**
 * 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 MFC extends FlowControl { protected final static FcHeader MFC_REPLENISH_HDR = new FcHeader(FcHeader.REPLENISH); protected final static FcHeader MFC_CREDIT_REQUEST_HDR = new FcHeader(FcHeader.CREDIT_REQUEST); /* --------------------------------------------- Fields ------------------------------------------------------ */ /** Maintains credits per member */ protected CreditMap credits; /** Last time a credit request was sent. Used to prevent credit request storms */ protected long last_credit_request; // ns /** Allows to unblock a blocked sender from an external program, e.g. JMX */ @ManagedOperation(description="Unblock a sender") public void unblock() { credits.replenishAll(); } @ManagedOperation(description="Print credits") public String printCredits() { return super.printCredits() + "\nsenders min credits: " + credits.computeLowestCreditWithAccumulated(); } @ManagedOperation(description="Print sender credits") public String printSenderCredits() { return credits.toString(); } @ManagedAttribute(description="Number of times flow control blocks sender") public int getNumberOfBlockings() { return credits.getNumBlockings(); } @ManagedAttribute(description="Average time blocked (in ms) in flow control when trying to send a message") public double getAverageTimeBlocked() { return credits.getAverageBlockTime(); } protected boolean handleMulticastMessage() {return true;} @Override protected Header getReplenishHeader() {return MFC_REPLENISH_HDR;} @Override protected Header getCreditRequestHeader() {return MFC_CREDIT_REQUEST_HDR;} public void init() throws Exception { super.init(); credits=createCreditMap(max_credits); } public void stop() { super.stop(); credits.clear(); } public void resetStats() { super.resetStats(); credits.reset(); } protected CreditMap createCreditMap(long max_creds) { return new CreditMap(max_creds); } @Override protected Object handleDownMessage(final Message msg) { Address dest=msg.dest(); if(dest != null) // 2nd line of defense, not really needed return down_prot.down(msg); int length=msg.length(); long block_time=max_block_times != null? getMaxBlockTime(length) : max_block_time; while(running) { boolean rc=credits.decrement(msg, length, block_time); if(rc || max_block_times != null || !running) break; if(needToSendCreditRequest()) { List> targets=credits.getMembersWithCreditsLessThan(min_credits); for(Tuple tuple: targets) sendCreditRequest(tuple.getVal1(), Math.min(max_credits, max_credits - tuple.getVal2())); } } // send message - either after regular processing, or after blocking (when enough credits are available again) return down_prot.down(msg); } protected synchronized boolean needToSendCreditRequest() { long current_time=System.nanoTime(); // will most likely send a request the first time (last_credit_request is 0), unless nanoTime() is negative if(current_time - last_credit_request >= TimeUnit.NANOSECONDS.convert(max_block_time, TimeUnit.MILLISECONDS)) { last_credit_request=current_time; return true; } return false; } protected void handleCredit(Address sender, long increase) { credits.replenish(sender, increase); if(log.isTraceEnabled()) log.trace("received %d credits from %s, new credits for %s: %d, min_credits=%d", increase, sender, sender, credits.get(sender), credits.getMinCredits()); } protected void handleViewChange(List
      mbrs) { super.handleViewChange(mbrs); Set
      keys=new HashSet<>(credits.keys()); keys.stream().filter(key -> !mbrs.contains(key)).forEach(key -> credits.remove(key)); mbrs.forEach(key -> credits.putIfAbsent(key)); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy