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

com.gemstone.org.jgroups.protocols.FLOW_CONTROL Maven / Gradle / Ivy

There is a newer version: 2.0-BETA
Show newest version
/** Notice of modification as required by the LGPL
 *  This file was modified by Gemstone Systems Inc. on
 *  $Date$
 **/
// $Id: FLOW_CONTROL.java,v 1.10 2005/08/11 12:43:47 belaban Exp $

package com.gemstone.org.jgroups.protocols;


import com.gemstone.org.jgroups.Address;
import com.gemstone.org.jgroups.Event;
import com.gemstone.org.jgroups.Message;
import com.gemstone.org.jgroups.blocks.GroupRequest;
import com.gemstone.org.jgroups.stack.MessageProtocol;
import com.gemstone.org.jgroups.util.ExternalStrings;
import com.gemstone.org.jgroups.util.ReusableThread;
import com.gemstone.org.jgroups.util.RspList;
import com.gemstone.org.jgroups.util.Util;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Properties;


// @todo Handle view changes (e.g., members {A,B,C}, blocked on C, and C crashes --> unblock).
/**
 * FLOW_CONTROL provides end-end congestion control and flow control.
 * Attempts to maximize through put, by minimizing the
 * possible block times(Forward flow control). Initially, sender starts with a smaller
 * window size  W and large expected RTT grpRTT. Sender also
 * keeps a margin in the window size. When the margin is hit, insted of waiting for the
 * window size to be exhausted, sender multicasts a FLOW_CONTROL info request message.
 * If the window size is exhausted before the responses are received, send will be blocked.
 * FCInfo(flow control info) from all the receivers is gathered at the sender, and current RTT
 * is computed. If the current RTT is greater than estimated RTT window size and margin are reduced,
 * otherwise they are increased.
 * 

* Horizontal interaction is initiated by the sender with the other group members. *

* Note: A reliable transport layer is required for this protocol to function properly. * With little effort this can be made completely independent. *

*
Also block on down() instead of sending BLOCK_SEND. * * @author Ananda Bollu */ public class FLOW_CONTROL extends MessageProtocol implements Runnable { private int _numMSGsSentThisPeriod=0; private static final String FLOW_CONTROL="FLOW_CONTROL"; private final HashMap _rcvdMSGCounter=new HashMap(); private int _windowSize=1000; private int _fwdMarginSize=200; private int _estimatedRTT=100000; private boolean waitingForResponse=false; private final ReusableThread _reusableThread; private double RTT_WEIGHT=0.125; private int _msgsSentAfterFCreq=0; // private final double TIME_OUT_FACTOR=0.25;//if resp not received from more than n*TIME_OUT_INCREMENT_FACTOR // private final double TIME_OUT_INCR_MULT=1.25; private double WINDOW_SIZE_REDUCTION=0.75; private double WINDOW_SIZE_EXPANSION=1.25; private boolean isBlockState=false; private int _windowsize_cap=1000000; //initial window size can not be more than 10^6 messages. public FLOW_CONTROL() { _reusableThread=new ReusableThread(FLOW_CONTROL); } @Override // GemStoneAddition public String getName() { return FLOW_CONTROL; } /** * If Event.MSG type is received count is incremented by one, * and message is passed to the down_prot. At some point, * based on the algorithm(FLOW_CONTROL protocol definition) * data collection sequence is started. This is done by each * member in SENDER role when _numMSGsSentThisPeriod hits the margin. * Before rsp arrives only _fwdMarginSize number of messages can be sent, * and then sender will be blocked. */ @Override // GemStoneAddition public boolean handleDownEvent(Event evt) { if(evt.getType() == Event.MSG) { _numMSGsSentThisPeriod++; if((_numMSGsSentThisPeriod > (_windowSize - _fwdMarginSize)) && !waitingForResponse) { waitingForResponse=true; //wait for the previous request to return.before assigning a new task. _reusableThread.waitUntilDone(); _reusableThread.assignTask(this); } if(waitingForResponse) { _msgsSentAfterFCreq++; if((_msgsSentAfterFCreq >= _fwdMarginSize) && !isBlockState) { if(log.isInfoEnabled()) log.info(ExternalStrings.FLOW_CONTROL_ACTION_BLOCK); log.error(ExternalStrings.FLOW_CONTROL_0_0_1, new Object[] {Long.valueOf(System.currentTimeMillis()), Integer.valueOf(_windowSize)}); passUp(new Event(Event.BLOCK_SEND)); isBlockState=true; } } } return true; } /** * If Event.MSG type is received message, number of received * messages from the sender is incremented. And the message is * passed up the stack. */ @Override // GemStoneAddition public boolean handleUpEvent(Event evt) { if(evt.getType() == Event.MSG) { Message msg=(Message)evt.getArg(); Address src=msg.getSrc(); FCInfo fcForSrc=(FCInfo)_rcvdMSGCounter.get(src); if(fcForSrc == null) { fcForSrc=new FCInfo(); _rcvdMSGCounter.put(src, fcForSrc); } fcForSrc.increment(1); if(log.isInfoEnabled()) log.info(ExternalStrings.FLOW_CONTROL_MESSAGE__0__RECEIVED_FROM__1, new Object[] {Integer.valueOf(fcForSrc.getRcvdMSGCount()), src}); } return true; } /** * Called when a request for this protocol layer is received. * Processes and return value is sent back in the reply. * FLOW_CONTROL protocol of all members gets this message(including sender?) * * @return Object containing FC information for sender with senderID. * Callback. Called when a request for this protocol layer is received. */ @Override // GemStoneAddition public Object handle(Message req) { Address src=req.getSrc(); Long resp=Long.valueOf(((FCInfo)_rcvdMSGCounter.get(src)).getRcvdMSGCount()); if(log.isInfoEnabled()) log.info(ExternalStrings.FLOW_CONTROL_REQEST_CAME_FROM__0__PREPARED_RESPONSE__1, new Object[] {src, resp}); return resp; } /** * FCInfo request must be submitted in a different thread. * handleDownEvent() can still be called to send messages * while waiting for FCInfo from receivers. usually takes * RTT. */ public void run() { if(log.isInfoEnabled()) log.info(ExternalStrings.FLOW_CONTROL__HIT_THE__FWDMARGIN_REMAINING_SIZE__0, _fwdMarginSize); reqFCInfo(); } /** * Following parameters can be optionally supplied: *

    *
  • window size cap - int Limits the window size to a reasonable value. *
  • window size - int these many number of messages are sent before a block could happen *
  • forward margin -int a request for flow control information is sent when remaining window size hits this margin *
  • RTT weight -double Max RTT in the group is calculated during each Flow control request. lower number assigns * higher weight to current RTT in estimating RTT. *
  • window size reduction factor -double When current RTT is greater than estimated RTT current window size * is reduced by this multiple. *
  • window size expansion factor -double When current RTT is less than estimated RTT window is incremented * by this multiple. *
* * @see com.gemstone.org.jgroups.stack.Protocol#setProperties(Properties) */ @Override // GemStoneAddition public boolean setProperties(Properties props) { String str=null; String winsizekey="window_size"; String fwdmrgnkey="fwd_mrgn"; String rttweightkey="rttweight"; String sizereductionkey="reduction"; String sizeexpansionkey="expansion"; String windowsizeCapKey="window_size_cap"; super.setProperties(props); str=props.getProperty(windowsizeCapKey); if(str != null) { _windowsize_cap=Integer.parseInt(str); props.remove(windowsizeCapKey); } str=props.getProperty(winsizekey); if(str != null) { _windowSize=Integer.parseInt(str); if(_windowSize > _windowsize_cap) _windowSize=_windowsize_cap; props.remove(winsizekey); } str=props.getProperty(fwdmrgnkey); if(str != null) { _fwdMarginSize=Integer.parseInt(str); props.remove(fwdmrgnkey); } str=props.getProperty(rttweightkey); if(str != null) { RTT_WEIGHT=Double.parseDouble(str); props.remove(rttweightkey); } str=props.getProperty(sizereductionkey); if(str != null) { WINDOW_SIZE_REDUCTION=Double.parseDouble(str); props.remove(sizereductionkey); } str=props.getProperty(sizeexpansionkey); if(str != null) { WINDOW_SIZE_EXPANSION=Double.parseDouble(str); props.remove(sizeexpansionkey); } if(props.size() > 0) { log.error(ExternalStrings.FLOW_CONTROL_FLOW_CONTROLSETPROPERTIES_THE_FOLLOWING_PROPERTIES_ARE_NOT_RECOGNIZED__0, props); return false; } return true; } /*-----------private stuff ------*/ private RspList reqFCInfo() { RspList rspList=null; long reqSentTime=0, rspRcvdTime=0; try { reqSentTime=System.currentTimeMillis(); //alternatively use _estimatedRTT for timeout.(timeout is the right way, but need to //check the use cases. rspList=castMessage(null, new Message(null, null, Util.objectToByteBuffer(FLOW_CONTROL)), GroupRequest.GET_ALL, 0); rspRcvdTime=System.currentTimeMillis(); } catch(Exception ex) { ex.printStackTrace(); } /*If NAKACK layer is present, if n+1 th message is FLOW_CONTROL Request, if responses are received that means all n messages sent earlier are received(?), ignore NAK_ACK. */ //ANALYSE RESPONSES long currentRTT=rspRcvdTime - reqSentTime; if(currentRTT > _estimatedRTT) { _windowSize=(int)(_windowSize * WINDOW_SIZE_REDUCTION); _fwdMarginSize=(int)(_fwdMarginSize * WINDOW_SIZE_REDUCTION); } else { _windowSize=(int)(_windowSize * WINDOW_SIZE_EXPANSION); if(_windowSize > _windowsize_cap) _windowSize=_windowsize_cap; _fwdMarginSize=(int)(_fwdMarginSize * WINDOW_SIZE_EXPANSION); } _estimatedRTT=(int)((RTT_WEIGHT * currentRTT) + (1.0 - RTT_WEIGHT) * _estimatedRTT); //reset for new FLOW_CONTROL request period. _numMSGsSentThisPeriod=0; waitingForResponse=false; _msgsSentAfterFCreq=0; if(isBlockState) { if(warn) log.warn("ACTION UNBLOCK"); passUp(new Event(Event.UNBLOCK_SEND)); log.error(ExternalStrings.FLOW_CONTROL_1_0_1, new Object[] {Long.valueOf(System.currentTimeMillis()), Integer.valueOf(_windowSize)}); isBlockState=false; } if(warn) log.warn("estimatedTimeout = " + _estimatedRTT); if(warn) log.warn("window size = " + _windowSize + " forward margin size = " + _fwdMarginSize); return rspList; } /* use this instead of Integer. */ private static class FCInfo implements Serializable { int _curValue; private static final long serialVersionUID = -8365016426836017979L; FCInfo() { } public void increment(int i) { _curValue+=i; } public int getRcvdMSGCount() { return _curValue; } @Override // GemStoneAddition public String toString() { return Integer.toString(_curValue); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy