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

com.gemstone.org.jgroups.View Maven / Gradle / Ivy

The newest version!
/** Notice of modification as required by the LGPL
 *  This file was modified by Gemstone Systems Inc. on
 *  $Date$
 **/
// $Id: View.java,v 1.10 2005/08/08 09:48:06 belaban Exp $

package com.gemstone.org.jgroups;


import java.io.ByteArrayOutputStream;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.Vector;

import com.gemstone.org.jgroups.protocols.pbcast.Digest;
import com.gemstone.org.jgroups.stack.IpAddress;
import com.gemstone.org.jgroups.util.ExternalStrings;
import com.gemstone.org.jgroups.util.Streamable;
import com.gemstone.org.jgroups.util.StreamableFixedID;
import com.gemstone.org.jgroups.util.Util;
import com.gemstone.org.jgroups.util.VersionedStreamable;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;

/**
 * A view is a local representation of the current membership of a group.
 * Only one view is installed in a channel at a time.
 * Views contain the address of its creator, an ID and a list of member addresses.
 * These adresses are ordered, and the first address is always the coordinator of the view.
 * This way, each member of the group knows who the new coordinator will be if the current one
 * crashes or leaves the group.
 * The views are sent between members using the VIEW_CHANGE event.
 */
public class View implements Externalizable, Cloneable, StreamableFixedID {
  
  /** GemStoneAddition - added for size check on views that carry;
   * credentials
   */
//  public static int MAX_VIEW_SIZE = 60000;
  
    /* A view is uniquely identified by its ViewID
     * The view id contains the creator address and a Lamport time.
     * The Lamport time is the highest timestamp seen or sent from a view.
     * if a view change comes in with a lower Lamport time, the event is discarded.
     */
    protected ViewId vid;

    /**
     * A list containing all the members of the view
     * This list is always ordered, with the coordinator being the first member.
     * the second member will be the new coordinator if the current one disappears
     * or leaves the group.
     */
    protected Vector members;

    /**
     * GemStoneAddition -- any additional payload to be sent
     * Used by the security AUTH layer to add/verify credentials.
     */
    private Object additionalData;
    
    /**
     * GemStoneAddition - size of serialized form of additionalData
     */
    private int additionalDataSize;

    /**
     * GemStoneAddition - Members removed from previous view as Suspects
     */
    private Set suspectedMembers;
    
    /**
     * GemStoneAddition - message digest moved from GmsHeader for FRAG3
     * fragmentation
     */
    private Digest messageDigest;
    
    /**
     * creates an empty view, should not be used
     */
    public View() {
    }


    /**
     * Creates a new view
     *
     * @param vid     The view id of this view (can not be null)
     * @param members Contains a list of all the members in the view, can be empty but not null.
     */
    public View(ViewId vid, Vector members) {
        this.vid=vid;
        this.members=members;
    }


    /**
     * Creates a new view
     *
     * @param creator The creator of this view (can not be null)
     * @param id      The lamport timestamp of this view
     * @param members Contains a list of all the members in the view, can be empty but not null.
     */
    public View(Address creator, long id, Vector members) {
      this(new ViewId(creator, id), members);
    }

    /**
     * Creates a new view
     *
     * @param creator The creator of this view (can not be null)
     * @param id      The lamport timestamp of this view
     * @param members Contains a list of all the members in the view, can be empty but not null.
     * @param suspectedMembers GemStoneAddition - tracking of ousted members
     */
    public View(Address creator, long id, Vector members, Vector suspectedMembers) {
        this(new ViewId(creator, id), members);
        if (suspectedMembers != null) {
          this.suspectedMembers = new HashSet(suspectedMembers);
        }
    }


    /**
     * returns the view ID of this view
     * if this view was created with the empty constructur, null will be returned
     *
     * @return the view ID of this view
     */
    public ViewId getVid() {
        return vid;
    }

    /**
     * returns the creator of this view
     * if this view was created with the empty constructur, null will be returned
     *
     * @return the creator of this view in form of an Address object
     */
    public Address getCreator() {
        return vid != null ? vid.getCoordAddress() : null;
    }
    
    /**
     * returns the coordinator of this view, which may not be the creator if it is not in the view.
     *  GemStoneAddition
     */
    public Address getCoordinator() {

      if (this.members.size() < 1) {
        return null;
      }
      
      return new Membership(this.members).getCoordinator();
    }

    /**
     * Returns a reference to the List of members (ordered)
     * Do NOT change this list, hence your will invalidate the view
     * Make a copy if you have to modify it.
     *
     * @return a reference to the ordered list of members in this view
     */
    public Vector getMembers() {
        return members;
    }
    
    /**
     * GemStoneAddition
     * get the members that were removed from the previous view due to
     * Suspect processing
     */
    public Set getSuspectedMembers() {
      return this.suspectedMembers == null? Collections.EMPTY_SET : this.suspectedMembers;
    }

    /**
     * GemStoneAddition -- getter for additional data
     */
    public Object getAdditionalData() {
      return this.additionalData;
    }

    /**
     * GemStoneAddition -- setter for additional data
     */
    public void setAdditionalData(Object data) {
      this.additionalData = data;
      // until credential fragmentation is implemented, we must perform
      // a size check to make sure the view fits into a datagram
      try {
        ByteArrayOutputStream bas = new ByteArrayOutputStream(10000);
        ObjectOutputStream oos = new ObjectOutputStream(bas);
        oos.writeObject(data);
        this.additionalDataSize = bas.size();
//        if (serializedSize() > MAX_VIEW_SIZE) {
//          this.additionalData = null;
//          this.additionalDataSize = 0;
//          throw new IllegalArgumentException(
//            JGroupsStrings.View_SERIALIZED_VIEW_SIZE_0_EXCEEDS_MAXIMUM_OF_1
//              .toLocalizedString(new Object[] { Integer.valueOf(bas.size()), Integer.valueOf(MAX_VIEW_SIZE) }));
//        }
      }
      catch (IOException e) {
        // ignore - this will happen again when the view is serialized
        // for transmission
      }
    }

    /**
     * returns true, if this view contains a certain member
     *
     * @param mbr - the address of the member,
     * @return true if this view contains the member, false if it doesn't
     *         if the argument mbr is null, this operation returns false
     */
    public boolean containsMember(Address mbr) {
        if(mbr == null || members == null) {
            return false;
        }
        return members.contains(mbr);
    }
    
    /**
     * GemStoneAddition - removes the given address from the set of suspected members
     * @param mbr
     */
    public void notSuspect(Address mbr) {
      this.suspectedMembers.remove(mbr);
    }
    
    /**
     * GemStoneAddition - retrieve the address in the view that corresponds
     * to the given address.  If the address is not in the view, return
     * the argument.
     */
    public Address getMember(Address addr) {
      int sz = members.size();
      // reverse search to find the newest member that matches, in case
      // of membership race condition that includes an old ID and a new ID
      // for a member that's joining
      for (int i=sz-1; i>0; i--) {
        Address mbr = (Address)members.get(i);
        if (mbr.equals(addr)) {
          return mbr;
        }
      }
      return addr;
    }


    @Override // GemStoneAddition
    public boolean equals(Object obj) {
        if(obj == null)
            return false;
        if(vid != null) {
          if (!(obj instanceof View)) return false; // GemStoneAddition
            int rc=vid.compareTo(((View)obj).vid);
            if(rc != 0)
                return false;
            if(members != null && ((View)obj).members != null) {
                return members.equals(((View)obj).members);
            }
        }
        return false;
    }

    /*
     * (non-Javadoc)
     * @see java.lang.Object#hashCode()
     * 
     * Note that we just need to make sure that equal objects return equal
     * hashcodes; nothing really elaborate is done here.
     */
    @Override // GemStoneAddition
    public int hashCode() { // GemStoneAddition
      int result = 0;
      if (vid != null) {
        result += vid.hashCode();
        if (members != null) {
          result += members.hashCode();
        }
      }
      return result;
    }
    
    /**
     * returns the number of members in this view
     *
     * @return the number of members in this view 0..n
     */
    public int size() {
        return members == null ? 0 : members.size();
    }


    /**
     * creates a copy of this view
     *
     * @return a copy of this view
     */
    @Override // GemStoneAddition
    @SuppressFBWarnings(value="CN_IDIOM_NO_SUPER_CALL")
    public Object clone() {
        ViewId vid2=vid != null ? (ViewId)vid.clone() : null;
        Vector members2=members != null ? (Vector)members.clone() : null;
        View result = new View(vid2, members2);
        if (this.suspectedMembers != null) {
          result.suspectedMembers = new HashSet(this.suspectedMembers);
        }
        if (additionalData != null) {
          result.additionalData = additionalData;
          result.additionalDataSize = additionalDataSize;
        }
        return result;
    }


    /**
     * debug only
     */
    public String printDetails() {
        StringBuffer ret=new StringBuffer();
        ret.append(vid).append("\n\t");
        if(members != null) {
            for(int i=0; i < members.size(); i++) {
                ret.append(members.elementAt(i)).append("\n\t");
            }
            ret.append('\n');
        }
        return ret.toString();
    }


    // GemStoneAddition - get the member name for an address
    private String memberName(Address m) {
      if (!(m instanceof IpAddress))
        return m.toString();
      IpAddress im = (IpAddress)m;
      StringBuffer sb = new StringBuffer();

      sb.append(im.toString());
      int port = im.getDirectPort(); 
      if (port > 0) {
        sb.append('/');
        sb.append(port);
      }
      return sb.toString();
    }


    @Override // GemStoneAddition
    public String toString() {
        StringBuffer ret=new StringBuffer(64);
        // GemStoneAddition - give more info than jgroups defaults to giving
        ret.append(vid);
        ret.append(" [");
        for (Iterator iter = members.iterator(); iter.hasNext(); ) {
          Address member = (Address) iter.next();
          // GemStoneAddition
          ret.append(memberName(member));
          
          if (iter.hasNext()) {
            ret.append(", ");
          }
        }
        // GemStoneAddition
        if (this.additionalData != null) {
          ret.append(this.additionalData);
        }
        ret.append("]");
        if (this.suspectedMembers != null && this.suspectedMembers.size() > 0) {
          ret.append(" crashed mbrs: [");
          for (Iterator it=this.suspectedMembers.iterator(); it.hasNext(); ) {
            ret.append(memberName((Address)it.next()));
            if (it.hasNext()) {
              ret.append(", ");
            }
          }
          ret.append(']');
        }
        //ret.append(vid).append(" ").append(members);
        return ret.toString();
    }
    //public String toString() {
    //    StringBuffer ret=new StringBuffer(64);
    //    ret.append(vid).append(" ").append(members);
    //    return ret.toString();
    //}
    
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeObject(vid);
        out.writeObject(members);
        out.writeObject(this.suspectedMembers); // GemStoneAddition
        out.writeInt(this.additionalDataSize);
        out.writeObject(this.additionalData); // GemStoneAddition
    }


    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        vid=(ViewId)in.readObject();
        members=(Vector)in.readObject();
        this.suspectedMembers = (Set)in.readObject(); // GemStoneAddition
        this.additionalDataSize = in.readInt();
        this.additionalData = in.readObject(); // GemStoneAddition
    }
    
    /** GemStoneAddition - find the lead member in this view */
    public Address getLeadMember() {
      for (int i=0; i




© 2015 - 2025 Weber Informatics LLC | Privacy Policy