Package com.sun.sgs.impl.service.watchdog

Source Code of com.sun.sgs.impl.service.watchdog.NodeImpl$NodeIterator

/*
* Copyright 2007-2009 Sun Microsystems, Inc.
*
* This file is part of Project Darkstar Server.
*
* Project Darkstar Server is free software: you can redistribute it
* and/or modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation and
* distributed hereunder to you.
*
* Project Darkstar Server is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

package com.sun.sgs.impl.service.watchdog;

import com.sun.sgs.app.ManagedObject;
import com.sun.sgs.app.NameNotBoundException;
import com.sun.sgs.app.ObjectNotFoundException;
import com.sun.sgs.app.TransactionException;
import com.sun.sgs.impl.util.BoundNamesUtil;
import com.sun.sgs.management.NodeInfo;
import com.sun.sgs.service.DataService;
import com.sun.sgs.service.Node;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

/**
* Implements the {@link Node} interface.  The state for a given
* {@code nodeId} is bound in the datastore with the following service
* bound name:
*
* <p><code>com.sun.sgs.impl.service.watchdog.NodeImpl.<i>nodeId</i></code>
*/
class NodeImpl
    implements Node, ManagedObject, Serializable, Comparable<NodeImpl>
{
    /** The serialVersionUID of this class. */
    private static final long serialVersionUID = 1L;

    /** The ID for an unknown node. */
    public static final long INVALID_ID = -1L;

    /** The name of this class. */
    private static final String PKG_NAME =
  "com.sun.sgs.impl.service.watchdog";

    /** The prefix for NodeImpl state. */
    private static final String NODE_PREFIX = PKG_NAME + ".node";

    /** The node id. */
    private final long id;
   
    /** The host name, or {@code null}. */
    private final String host;
   
    /** The port JMX can listen on, or {@code -1}. */
    private final int jmxPort;
   
    /** The watchdog client, or {@code null}. */
    private final WatchdogClient client;
   
    /** If true, this node is considered alive. */
    private boolean isAlive;

    /** The ID of the backup for this node. */
    private long backupId = INVALID_ID;

    /** The set of primaries for which this node is a backup. */
    private final Set<Long> primaryIds = new HashSet<Long>();

    /**
     * The expiration time for this node. A value of {@code 0} means
     * that either the value has not been initialized or the value is
     * not meaningful because the node has failed.
     */
    private transient long expiration;

    /**
     * Constructs an instance of this class with the given {@code
     * nodeId}, {@code hostName}, and {@code client}. 
     * This instance's alive status is set to {@code true}.  The expiration
     * time for this instance should be set as soon as it is known.
     *
     * @param   nodeId a node ID
     * @param   hostName a host name
     * @param   jmxPort  the port JMX is listening on for the node,
     *                   or {@code -1}
     * @param  client a watchdog client
     */
    NodeImpl(long nodeId, String hostName, int jmxPort, WatchdogClient client) {
        this (nodeId, hostName, jmxPort, client, true, INVALID_ID);
    }

    /**
     * Constructs an instance of this class with the given {@code
     * nodeId}, {@code hostName}, and {@code isAlive} status.  This
     * instance's watchdog client is set to {@code null} and its
     * backup is unassigned (backup ID is -1).
     *
     * @param   nodeId a node ID
     * @param   hostName a host name, or {@code null}
     * @param  isAlive if {@code true}, this node is considered alive
     */
    NodeImpl(long nodeId, String hostName, boolean isAlive) {
  this(nodeId, hostName, -1, null, isAlive, INVALID_ID);
    }
 
    /**
     * Constructs an instance of this class with the given {@code
     * nodeId}, {@code hostName}, {@code isAlive} status, and
     * {@code backupId}.  This instance's watchdog client is set to
     * {@code null}.
     *
     * @param   nodeId a node ID
     * @param   hostName a host name, or {@code null}
     * @param  isAlive if {@code true}, this node is considered alive
     * @param  backupId the ID of the node's backup (-1 if no backup
     *    is assigned)
     */
    NodeImpl(long nodeId, String hostName, boolean isAlive, long backupId) {
        this(nodeId, hostName, -1, null, isAlive, backupId);
    }
   
    /**
     * Constructs an instance of this class with the given {@code
     * nodeId}, {@code hostName}, {@code jmxPort}, {@code client},
     * {@code isAlive} status, and {@code backupId}.
     *
     * @param   nodeId a node ID
     * @param   hostName a host name, or {@code null}
     * @param   jmxPort  the port JMX is listening on, or {@code -1}
     * @param  client   a watchdog client
     * @param  isAlive if {@code true}, this node is considered alive
     * @param  backupId the ID of the node's backup (-1 if no backup
     *    is assigned)
     */
    private NodeImpl(long nodeId, String hostName, int jmxPort,
                     WatchdogClient client, boolean isAlive, long backupId)
    {
        this.id = nodeId;
  this.host = hostName;
        this.client = client;
        this.isAlive = isAlive;
        this.backupId = backupId;
        this.jmxPort = jmxPort;
    }

    /* -- Implement Node -- */

    /** {@inheritDoc} */
    public long getId() {
  return id;
    }

    /** {@inheritDoc} */
    public String getHostName() {
  return host;
    }
   
    /** {@inheritDoc} */
    public synchronized boolean isAlive() {
  return isAlive;
    }

    /* -- Implement Comparable -- */

    /** {@inheritDoc} */
    public int compareTo(NodeImpl o) {
  long difference = getExpiration() - o.getExpiration();
  if (difference == 0) {
      difference = id - o.id;
      if (difference == 0) {
    difference = compareStrings(host, o.host);
      }
  }
  return difference < 0 ? -1 : (difference > 0 ? 1 : 0);
    }

    /* -- Implement Object -- */

    /** {@inheritDoc} */
    public boolean equals(Object obj) {
  if (obj == null) {
      throw new NullPointerException("obj is null");
  } else if (this == obj) {
      return true;
  } else if (obj.getClass() == this.getClass()) {
      NodeImpl node = (NodeImpl) obj;
            if (id == node.id) {
                if (compareStrings(host, node.host) != 0) {
                    throw new RuntimeException("two node objects with ID " +
                                               id +
                                               " have different host names: " +
                                               host + " and " + node.host);
                }
                return true;
            }
  }
  return false;
    }

    /** {@inheritDoc} */
    public int hashCode() {
  return ((int) (id >>> 32)) ^ ((int) id);
    }

    /** {@inheritDoc} */
    public synchronized String toString() {
  return getClass().getName() + "[" + id + "," +
      (isAlive() ? "alive" : "failed") + ",backup:" +
      (backupId == INVALID_ID ? "(none)" : backupId) +
            "]@" + host;
    }

    /* -- package access methods -- */

    /**
     * Returns the watchdog client, or {@code null}.
     */
    WatchdogClient getWatchdogClient() {
  return client;
    }
   
    /**
     * Returns the expiration time.  A value of {@code 0} means that
     * either the value has not been initialized or the value is not
     * meaningful because the node has failed.  If {@link #isAlive}
     * returns {@code false} the value returned from this method is
     * not meaningful.
     */
    synchronized long getExpiration() {
  return expiration;
    }

    /**
     * Sets the expiration time for this node instance.
     *
     * @param  newExpiration the new expiration value
     */
    synchronized void setExpiration(long newExpiration) {
  expiration = newExpiration;
    }

    /**
     * Returns {@code true} if the node is expired, and {@code false}
     * otherwise.
     *
     * @return  {@code true} if the node is expired, and {@code false}
     *    otherwise
     */
    synchronized boolean isExpired() {
  return expiration <= System.currentTimeMillis();
    }
   
    /**
     * Sets the alive status of this node instance to {@code false},
     * sets this node's backup to the specified {@code backup},
     * empties the set of primaries for which this node is recovering,
     * and updates the node's state in the specified {@code
     * dataService}.  Subsequent calls to {@link #isAlive isAlive}
     * will return {@code false}.
     *
     * @param  dataService a data service
     * @param  backup a chosen backup
     * @throws  ObjectNotFoundException if this node has been removed
     * @throws   TransactionException if there is a problem with the
     *    current transaction
     */
    synchronized void setFailed(DataService dataService, NodeImpl backup) {
  NodeImpl nodeImpl = getForUpdate(dataService);
  this.isAlive = false;
  nodeImpl.isAlive = false;
  this.backupId =
      (backup != null) ?
      backup.getId() :
      INVALID_ID;
  nodeImpl.backupId = this.backupId;
  this.primaryIds.clear();
  nodeImpl.primaryIds.clear();
    }

    /**
     * Adds the specified {@code primaryId} to the list of primaries
     * for which this node is a backup, and updates the node's state
     * in the specified {@code dataService}.
     *
     * @param  dataService a data service
     * @param  primaryId the ID of a primary for which this node is a
     *    backup
     * @throws  ObjectNotFoundException if this node has been removed
     * @throws   TransactionException if there is a problem with the
     *    current transaction
     */
    synchronized void addPrimary(DataService dataService, long primaryId) {
  NodeImpl nodeImpl = getForUpdate(dataService);
  primaryIds.add(primaryId);
  nodeImpl.primaryIds.add(primaryId);
    }

    /** Returns the set of primary nodes for which this node is a backup. */
    synchronized Set<Long> getPrimaries() {
  return primaryIds;
    }

    /** Returns {@code true} if this node has a backup. */
    synchronized boolean hasBackup() {
  return backupId != INVALID_ID;
    }

    /**
     * Returns the backup for this node, or {@value INVALID_ID} if there
     * is no backup.
     */
    synchronized long getBackupId() {
  return backupId;
    }

    /**
     * Stores this instance in the specified {@code dataService}.
     * This method should only be called within a transaction.
     *
     * @param  dataService a data service
     * @throws   TransactionException if there is a problem with the
     *    current transaction
     */
    synchronized void putNode(DataService dataService) {
  dataService.setServiceBinding(getNodeKey(id), this);
    }
   
    /**
     * Fetches this node's state from the specified {@code
     * dataService}, marked for update.
     *
     * @param  dataService a data service
     * @throws  ObjectNotFoundException if this node has been removed
     * @throws   TransactionException if there is a problem with the
     *    current transaction
     */
     private NodeImpl getForUpdate(DataService dataService) {
  NodeImpl nodeImpl = getNodeForUpdate(dataService, id);
  if (nodeImpl == null) {
      throw new ObjectNotFoundException("node is removed");
  }
  return nodeImpl;
    }

     /**
      * Returns the port used for remote JMX monitoring, or {@code -1}
      * if only local monitoring is allowed.
      *
      * @return the port used for remote JMX monitoring of this node
      */
    private int getJmxPort() {
        return jmxPort;
    }
   
    /**
     * Returns the management information for this node.
     *
     * @return the management information for this node
     */
    NodeInfo getNodeInfo() {
        return new NodeInfo(getHostName(),
                            getId(),
                            isAlive(),
                            getBackupId(),
                            getJmxPort());
    }
    
    /**
     * Removes the node with the specified {@code nodeId} and its
     * binding from the specified {@code dataService}.  If the binding
     * has already been removed from the {@code dataService} this
     * method takes no action.  This method should only be called
     * within a transaction.
     *
     * @param  dataService a data service
     * @param  nodeId a node ID
     * @throws   TransactionException if there is a problem with the
     *    current transaction
     */
    static void removeNode(DataService dataService, long nodeId) {
  String key = getNodeKey(nodeId);
  NodeImpl node;
  try {
      node = (NodeImpl) dataService.getServiceBinding(key);
      dataService.removeServiceBinding(key);
      dataService.removeObject(node);
  } catch (NameNotBoundException e) {
  }
    }

    /**
     * Returns the {@code Node} instance for the given {@code nodeId},
     * retrieved from the specified {@code dataService}, or {@code
     * null} if the node isn't bound in the data service .  This
     * method should only be called within a transaction.
     *
     * @param  dataService a data service
     * @param  nodeId a node ID
     * @return  the node for the given {@code nodeId}, or {@code null}
     * @throws   TransactionException if there is a problem with the
     *    current transaction
     */
    static NodeImpl getNode(DataService dataService, long nodeId) {
  String key = getNodeKey(nodeId);
  NodeImpl node = null;
  try {
      node = (NodeImpl) dataService.getServiceBinding(key);
  } catch (NameNotBoundException e) {
  }
  return node;
    }
   
    /**
     * Returns the {@code Node} instance for the given {@code nodeId},
     * retrieved from the specified {@code dataService} for update.
     * This method returns {@code null} if the node isn't bound in the data
     * service .  This method must only be called within a transaction.
     *
     * @param  dataService a data service
     * @param  nodeId a node ID
     * @return  the node for the given {@code nodeId}, or {@code null}
     * @throws   TransactionException if there is a problem with the
     *    current transaction
     */
    static NodeImpl getNodeForUpdate(DataService dataService, long nodeId) {
  String key = getNodeKey(nodeId);
  NodeImpl node = null;
  try {
      node = (NodeImpl) dataService.getServiceBinding(key);
      dataService.markForUpdate(node);
  } catch (NameNotBoundException e) {
  }
  return node;
    }
   
    /**
     * Marks all nodes currently bound in the specified {@code
     * dataService} as failed, and returns a collection of those
     * nodes.  This method should only be called within a transaction.
     *
     * @param  dataService a data service
     * @return  a collection of currently bound nodes, each marked as failed
     * @throws   TransactionException if there is a problem with the
     *    current transaction
     */
    static Collection<NodeImpl> markAllNodesFailed(DataService dataService) {
  Collection<NodeImpl> nodes = new ArrayList<NodeImpl>();
  for (String key :
       BoundNamesUtil.getServiceBoundNamesIterable(
    dataService, NODE_PREFIX))
  {
      NodeImpl node = (NodeImpl) dataService.getServiceBinding(key);
      node.setFailed(dataService, null);
      nodes.add(node);
  }
  return nodes;
    }

    /**
     * Returns an iterator for {@code Node} instances to be retrieved
     * from the specified {@code dataService}.  The returned iterator
     * does not support the {@code remove} operation.  This method
     * should only be called within a transaction, and the returned
     * iterator should only be used within that transaction.
     *
     * @param  dataService a data service
     * @return  an iterator for nodes
     * @throws   TransactionException if there is a problem with the
     *    current transaction
     */
    static Iterator<Node> getNodes(DataService dataService) {
  return new NodeIterator(dataService);
    }

    /* -- private methods and classes -- */

    /**
     * Compares the specified strings and returns -1, 0, or 1
     * according to whether the first string is less than, equal to,
     * or greater than the second string in a lexicographic ordering.
     * In this ordering, a string with a value of {@code null} is less
     * than any non-{@code null} string.
     *
     * @param  s1 a string, or {@code null}
     * @param  s2 a string, or {@code null}
     * @return  -1, 0, or 1 according to whether {@code s1} is less than,
     *    equal to, or greater than {@code s2}
     */
    private static int compareStrings(String s1, String s2) {
  if (s1 == null) {
      return (s2 == null) ? 0 : -1;
  } else if (s2 == null) {
      return 1;
  } else {
      return s1.compareTo(s2);
  }
    }
   
    /**
     * Returns the key to access from the data service the {@code
     * Node} instance with the specified {@code nodeId}.
     *
     * @param  a node ID
     * @return  a key for accessing the {@code Node} instance
     */
    private static String getNodeKey(long nodeId) {
  return NODE_PREFIX + "." + nodeId;
    }
   
    /**
     * An iterator for node state.
     */
    private static class NodeIterator implements Iterator<Node> {

  /** The data service. */
  private final DataService dataService;

  /** The underlying iterator for service bound names. */
  private Iterator<String> iterator;

  /**
   * Constructs an instance of this class with the specified
   * {@code dataService}.
   */
  NodeIterator(DataService dataService) {
      this.dataService = dataService;
      this.iterator =
    BoundNamesUtil.getServiceBoundNamesIterator(
        dataService, NODE_PREFIX);
  }

  /** {@inheritDoc} */
  public boolean hasNext() {
      return iterator.hasNext();
  }

  /** {@inheritDoc} */
  public Node next() {
      String key = iterator.next();
      return (NodeImpl) dataService.getServiceBinding(key);
  }

  /** {@inheritDoc} */
  public void remove() {
      throw new UnsupportedOperationException("remove is not supported");
  }
    }
}
TOP

Related Classes of com.sun.sgs.impl.service.watchdog.NodeImpl$NodeIterator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.