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

bboss.org.jgroups.protocols.VIEW_SYNC Maven / Gradle / Ivy

The newest version!
package bboss.org.jgroups.protocols;


import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Vector;
import java.util.concurrent.Future;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import bboss.org.jgroups.Address;
import bboss.org.jgroups.Event;
import bboss.org.jgroups.Global;
import bboss.org.jgroups.Header;
import bboss.org.jgroups.MergeView;
import bboss.org.jgroups.Message;
import bboss.org.jgroups.View;
import bboss.org.jgroups.ViewId;
import bboss.org.jgroups.annotations.GuardedBy;
import bboss.org.jgroups.annotations.MBean;
import bboss.org.jgroups.annotations.ManagedAttribute;
import bboss.org.jgroups.annotations.ManagedOperation;
import bboss.org.jgroups.annotations.Property;
import bboss.org.jgroups.conf.ClassConfigurator;
import bboss.org.jgroups.protocols.pbcast.GMS;
import bboss.org.jgroups.stack.Protocol;
import bboss.org.jgroups.util.TimeScheduler;
import bboss.org.jgroups.util.Util;


/**
 * Periodically sends the view to the group. When a view is received which is
 * greater than the current view, we install it. Otherwise we simply discard it.
 * This is used to solve the problem for unreliable view dissemination outlined
 * in JGroups/doc/ReliableViewInstallation.txt. This protocol is supposed to be
 * just below GMS.
 * 
 * @author Bela Ban
 * @version $Id: VIEW_SYNC.java,v 1.39 2010/06/15 06:44:35 belaban Exp $
 */
@MBean(description="Periodically sends the view to the group")
public class VIEW_SYNC extends Protocol {
    
    /* -----------------------------------------    Properties     --------------------------------------- */

    @Property(description="View synchronization interval. Default is 60 sec")
    private long avg_send_interval=60000;

    /* --------------------------------------------- JMX  ---------------------------------------------- */

    private int num_views_sent=0;

    @ManagedAttribute
    private int num_view_requests_sent=0;

    @ManagedAttribute
    private int num_view_responses_seen=0;

    @ManagedAttribute
    private int num_views_non_local=0;

    @ManagedAttribute
    private int num_views_equal=0;

    @ManagedAttribute
    private int num_views_less=0;

    @ManagedAttribute
    private int num_views_adjusted=0;

    @ManagedAttribute
    private long last_view_request_sent=0;

    
    /* --------------------------------------------- Fields ------------------------------------------------------ */

    private Address local_addr=null;

    private final Vector
mbrs=new Vector
(); private View my_view=null; private ViewId my_vid=null; @GuardedBy("view_task_lock") private Future view_send_task_future=null; // bcasts periodic view sync message (added to timer below) private final Lock view_task_lock=new ReentrantLock(); private TimeScheduler timer=null; private static final short gms_id=ClassConfigurator.getProtocolId(GMS.class); public long getAverageSendInterval() { return avg_send_interval; } public void setAverageSendInterval(long gossip_interval) { avg_send_interval=gossip_interval; } @ManagedAttribute public int getNumViewsSent() { return num_views_sent; } public int getNumViewsAdjusted() { return num_views_adjusted; } @ManagedOperation public void resetStats() { super.resetStats(); num_views_adjusted=num_views_sent=0; } public void start() throws Exception { timer=getTransport().getTimer(); if(timer == null) throw new Exception("timer cannot be retrieved from protocol stack"); } public void stop() { stopViewSender(); } /** Sends a VIEW_SYNC_REQ to all members, every member replies with a VIEW multicast */ @ManagedOperation(description="Sends a VIEW_SYNC_REQ to all members") public void sendViewRequest() { Message msg=new Message(null); msg.setFlag(Message.OOB); ViewSyncHeader hdr=new ViewSyncHeader(ViewSyncHeader.VIEW_SYNC_REQ, null); msg.putHeader(this.id, hdr); down_prot.down(new Event(Event.MSG, msg)); num_view_requests_sent++; last_view_request_sent=System.currentTimeMillis(); } // public void sendFakeViewForTestingOnly() { // ViewId fake_vid=new ViewId(local_addr, my_vid.getId() +2); // View fake_view=new View(fake_vid, new Vector(my_view.getMembers())); // System.out.println("sending fake view " + fake_view); // my_view=fake_view; // my_vid=fake_vid; // sendView(); // } public Object up(Event evt) { Message msg; ViewSyncHeader hdr; int type=evt.getType(); switch(type) { case Event.MSG: msg=(Message)evt.getArg(); hdr=(ViewSyncHeader)msg.getHeader(this.id); if(hdr == null) break; Address sender=msg.getSrc(); switch(hdr.type) { case ViewSyncHeader.VIEW_SYNC: handleView(hdr.view, sender); break; case ViewSyncHeader.VIEW_SYNC_REQ: if(!sender.equals(local_addr)) sendView(); break; default: if(log.isErrorEnabled()) log.error("ViewSyncHeader type " + hdr.type + " not known"); } return null; case Event.VIEW_CHANGE: View view=(View)evt.getArg(); handleViewChange(view); break; } return up_prot.up(evt); } public Object down(Event evt) { switch(evt.getType()) { case Event.VIEW_CHANGE: View v=(View)evt.getArg(); handleViewChange(v); break; case Event.SET_LOCAL_ADDRESS: local_addr=(Address)evt.getArg(); break; } return down_prot.down(evt); } /* --------------------------------------- Private Methods ---------------------------------------- */ private void handleView(View v, Address sender) { num_view_responses_seen++; Vector
members=v.getMembers(); if(!members.contains(local_addr)) { if(log.isWarnEnabled()) log.warn("discarding view as I (" + local_addr + ") am not member of view (" + v + ")"); num_views_non_local++; return; } ViewId vid=v.getVid(); int rc=vid.compareTo(my_vid); if(rc > 0) { // foreign view is greater than my own view; update my own view ! if(log.isTraceEnabled()) log.trace("view from " + sender + " (" + vid + ") is greater than my own view (" + my_vid + ");" + " will update my own view"); Message view_change=new Message(local_addr, local_addr, null); bboss.org.jgroups.protocols.pbcast.GMS.GmsHeader hdr; hdr=new bboss.org.jgroups.protocols.pbcast.GMS.GmsHeader(bboss.org.jgroups.protocols.pbcast.GMS.GmsHeader.VIEW, v); view_change.putHeader(gms_id, hdr); up_prot.up(new Event(Event.MSG, view_change)); num_views_adjusted++; } else if (rc == 0) { if (log.isTraceEnabled()) log.trace("view from " + sender + " (" + vid + ") is same as my own view; ignoring"); num_views_equal++; } else { if (log.isTraceEnabled()) log.trace("view from " + sender + " (" + vid + ") is less than my own view (" + my_vid + "); ignoring"); num_views_less++; } } private void handleViewChange(View view) { Vector
tmp=view.getMembers(); if(tmp != null) { mbrs.clear(); mbrs.addAll(tmp); } my_view=(View)view.clone(); my_vid=my_view.getVid(); if(my_view.size() > 1) { startViewSender(); } else { stopViewSender(); } } private void sendView() { View tmp=(View)(my_view != null? my_view.clone() : null); if(tmp == null) return; Message msg=new Message(null); // send to the group msg.setFlag(Message.OOB); ViewSyncHeader hdr=new ViewSyncHeader(ViewSyncHeader.VIEW_SYNC, tmp); msg.putHeader(this.id, hdr); down_prot.down(new Event(Event.MSG, msg)); num_views_sent++; } /** Starts with view_task_lock held, no need to acquire it again */ void startViewSender() { try { view_task_lock.lock(); if(view_send_task_future == null || view_send_task_future.isDone()) { ViewSendTask view_send_task=new ViewSendTask(); view_send_task_future=timer.scheduleWithDynamicInterval(view_send_task); if(log.isTraceEnabled()) log.trace("view send task started"); } } finally { view_task_lock.unlock(); } } void stopViewSender() { try { view_task_lock.lock(); if(view_send_task_future != null) { view_send_task_future.cancel(false); view_send_task_future=null; if(log.isTraceEnabled()) log.trace("view send task stopped"); } } finally { view_task_lock.unlock(); } } /* ------------------------------------End of Private Methods ------------------------------------- */ public static class ViewSyncHeader extends Header { public static final int VIEW_SYNC = 1; // contains a view public static final int VIEW_SYNC_REQ = 2; // request to all members to send their views int type=0; View view=null; public ViewSyncHeader() { } public ViewSyncHeader(int type, View view) { this.type=type; this.view=view; } public int getType() { return type; } public View getView() { return view; } static String type2String(int t) { switch(t) { case VIEW_SYNC: return "VIEW_SYNC"; case VIEW_SYNC_REQ: return "VIEW_SYNC_REQ"; default: return ""; } } public String toString() { StringBuilder sb=new StringBuilder("[").append(type2String(type)).append("]"); if(view != null) sb.append(", view= ").append(view); return sb.toString(); } public int size() { int retval=Global.INT_SIZE + Global.BYTE_SIZE + Global.BYTE_SIZE; // type + view type + presence for digest if(view != null) retval+=view.serializedSize(); return retval; } public void writeTo(DataOutputStream out) throws IOException { out.writeInt(type); // 0 == null, 1 == View, 2 == MergeView byte b=(byte)(view == null? 0 : (view instanceof MergeView? 2 : 1)); out.writeByte(b); Util.writeStreamable(view, out); } public void readFrom(DataInputStream in) throws IOException, IllegalAccessException, InstantiationException { type=in.readInt(); byte b=in.readByte(); Class clazz=b == 2? MergeView.class : View.class; view=(View)Util.readStreamable(clazz, in); } } /** Periodically multicasts a View_SYNC message */ private class ViewSendTask implements TimeScheduler.Task { public long nextInterval() { long interval=computeSleepTime(); if(interval <= 0) return 10000; else return interval; } public void run() { sendView(); } long computeSleepTime() { int num_mbrs=Math.max(mbrs.size(), 1); return getRandom((num_mbrs * avg_send_interval * 2)); } long getRandom(long range) { return (long)((Math.random() * range) % range); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy