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

nirvana.support.services.ZkEphemeralPathSupport.scala Maven / Gradle / Ivy

// Copyright 2014 Jun Tsai. All rights reserved.
// site: http://www.ganshane.com
package nirvana.support.services

import java.util.concurrent.{CopyOnWriteArrayList, CopyOnWriteArraySet}
import org.apache.zookeeper.CreateMode
import collection.JavaConversions._
import nirvana.support.NirvanaSupportConstants

/**
 * ephemeral path support
 */
trait ZkEphemeralPathSupport {
  this:ZkClientSupport
    with ZkDeletePathSupport
    with LoggerSupport
    with ZkPathCreatorSupport =>

  /**
   * 记录所有的临时节点,以及异常的临时节点
   *  临时节点被删除,则watch将失效,
   *  但是当临时节点重新被创建,则此watch又重新生效
   */
  private final val ephemeralNodes = new CopyOnWriteArraySet[Node]()
  private final val failedEphemeralNodes = new CopyOnWriteArrayList[Node]()

  sealed class EphemeralMode
  case object NormalEphemeralMode extends EphemeralMode
  case object SequenceEphemeralMode extends EphemeralMode

  /**
   * 创建临时节点
   * @param path 目标路径
   * @param data 原始数据
   * @param mode 模式
   * @param isPermanent 永远跟踪
   */
  def createEphemeralPathWithStringData(path:String,
                          data:Option[String]=None,
                          mode:EphemeralMode=NormalEphemeralMode,
                          isPermanent:Boolean=true){
    data match{
      case Some(str)=>
        createEphemeralPath(path,
          Some(str.getBytes(NirvanaSupportConstants.UTF8_ENCODING)),
          mode,
          isPermanent)
      case None=>
        createEphemeralPath(path,
          None,
          mode,
          isPermanent)
    }
  }
  /**
   * 创建临时节点
   * @param path 目标路径
   * @param data 原始数据
   * @param mode 模式
   * @param isPermanent 永远跟踪
   */
  def createEphemeralPath(path:String,
                          data:Option[Array[Byte]]=None,
                          mode:EphemeralMode=NormalEphemeralMode,
                          isPermanent:Boolean=true){
    mode match{
      case NormalEphemeralMode =>
        createEphemeralPath(path,data,CreateMode.EPHEMERAL,isPermanent)
      case SequenceEphemeralMode =>
        createEphemeralPath(path,data,CreateMode.EPHEMERAL_SEQUENTIAL,isPermanent)
      case other =>
        logger.error("mode "+other+" unsupported!")
    }
  }
  private def createEphemeralPath(path:String,
                            data:Option[Array[Byte]],
                            mode:CreateMode,
                            isPermanent:Boolean){
    /**
     * 此处有一个特别的处理,因为在创建临时节点的时候,
     * 有可能是上一个session未关闭造成此临时节点仍然存在,
     * 如果只是简单setData,那么当上一个session失效的时候,本临时节点将消失
     *
     * @see http://developers.blog.box.com/2012/04/10/a-gotcha-when-using-zookeeper-ephemeral-nodes/
     */
    try {
      delete(path)
    }catch{
      case e:Throwable =>
        logger.warn("fail to delete path when create ephemeral path for "+path)
    }
    val node = new Node(path,data,mode)
    try {
      failedEphemeralNodes.remove(path)
      internalCreatePath(path,data,node.createMode)
      if(isPermanent){
        ephemeralNodes.add(node)
      }
    }catch{
      case e:Throwable =>
        logger.warn(e.getMessage+",will retry")
        failedEphemeralNodes.add(node)
    }
  }
  protected def retryFailedEphemeralNodes(){
    logger.info("retry to create ephemeral nodes")
    val it = failedEphemeralNodes.iterator()
    while(it.hasNext){
      val node = it.next()
      createEphemeralPath(node.path,node.data,node.createMode,true)
    }
  }
  protected def recreateEphemeralNodes(){
    //针对临时节点的再次创建
    ephemeralNodes.foreach( node =>createEphemeralPath(node.path,node.data,node.createMode,true))
  }
  private[nirvana] def testCreateFailedEphemeral(path:String){
    failedEphemeralNodes.add(new Node(path,None,CreateMode.EPHEMERAL))
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy