Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.twitter.finagle.serverset2.buoyant.ZkDtabStore.scala Maven / Gradle / Ivy
package com.twitter.finagle.serverset2.buoyant
import com.twitter.finagle.Dtab
import com.twitter.finagle.serverset2.client._
import com.twitter.finagle.serverset2.{RetryStream , Zk2Resolver , ZkSession => FZkSession }
import com.twitter.finagle.stats.DefaultStatsReceiver
import com.twitter.finagle.util.DefaultTimer
import com.twitter.io.Buf
import com.twitter.logging.Logger
import com.twitter.util._
import io.buoyant.namerd.{Ns , VersionedDtab , DtabStore , RichActivity }
import io.buoyant.namerd.DtabStore .{DtabVersionMismatchException , DtabNamespaceDoesNotExistException , DtabNamespaceAlreadyExistsException , Forbidden }
import io.buoyant.namerd.storage.{AuthInfo , Acl }
import java.nio.ByteBuffer
class ZkDtabStore (
hosts: String ,
zkPrefix: String ,
sessionTimeout: Option [Duration ],
authInfo: Option [AuthInfo ],
acls: Seq [Acl ]
) extends DtabStore {
private [this ] val log = Logger ()
private [this ] val retryStream = RetryStream ()
private [this ] val stats = DefaultStatsReceiver .scope("zkclient" ).scope(Zk2Resolver .statsOf(hosts))
private [this ] implicit val timer = DefaultTimer .twitter
private [this ] val builder = ClientBuilder ()
.hosts(hosts)
.sessionTimeout(sessionTimeout.getOrElse(FZkSession .DefaultSessionTimeout ))
.statsReceiver(stats)
private [this ] val zkSession = new ZkSession (
retryStream,
retryStream,
() => builder.writer(),
authInfo,
stats
)
private [this ] def actOf [T ](go: ZooKeeperRW => Future [Watched [T ]]): Activity [T ] =
zkSession.watchedOperation(go(zkSession.zk))
private [this ] val actNs = actOf(_.getChildrenWatch(zkPrefix)).map(_.children.toSet)
def list (): Activity [Set [Ns ]] = actNs.transform {
case Activity .Failed (KeeperException .NoAuth (_)) => Activity .exception(Forbidden )
case state => Activity (Var (state))
}
def create (ns: String , dtab: Dtab ): Future [Unit ] = {
val path = s"$zkPrefix /$ns "
log.info(s"Attempting to create dtab at $path " )
zkSession.zk.create(
path,
Some (Buf .Utf8 (dtab.show)),
acls.map(ZkDtabStore .zkAcl),
CreateMode .Persistent
).rescue {
case KeeperException .NodeExists (_) =>
Future .exception(new DtabNamespaceAlreadyExistsException (ns))
case KeeperException .NoAuth (_) =>
Future .exception(Forbidden )
}.unit
}
def delete (ns: String ): Future [Unit ] = {
val path = s"$zkPrefix /$ns "
log.info(s"Attempting to delete dtab at $path " )
zkSession.zk.delete(path, None ).rescue {
case KeeperException .NoNode (_) =>
Future .exception(new DtabNamespaceDoesNotExistException (ns))
case KeeperException .NoAuth (_) =>
Future .exception(Forbidden )
}
}
override def update (ns: String , dtab: Dtab , version: Buf ): Future [Unit ] = {
val path = s"$zkPrefix /$ns "
log.info(s"Attempting to update dtab at $path " )
zkSession.zk.setData(
path,
Some (Buf .Utf8 (dtab.show)),
Some (versionInt(version))
).rescue {
case KeeperException .BadVersion (_) => Future .exception(new DtabVersionMismatchException )
case KeeperException .NoNode (_) => Future .exception(new DtabNamespaceDoesNotExistException (ns))
case KeeperException .NoAuth (_) => Future .exception(Forbidden )
}.unit
}
def observe (ns: String ): Activity [Option [VersionedDtab ]] = {
val path = s"$zkPrefix /$ns "
log.info(s"Attempting to observe $path " )
actOf(_.getDataWatch(path)).flatMap { data =>
data.data match {
case Some (Buf .Utf8 (s)) =>
Activity .value(Some (VersionedDtab (Dtab .read(s), versionBuf(data.stat.version))))
case None =>
Activity .exception(new IllegalStateException (s"Empty node: $path " ))
}
}.transform {
case Activity .Failed (KeeperException .NoNode (_)) => Activity .value(None )
case Activity .Failed (KeeperException .NoAuth (_)) => Activity .exception(Forbidden )
case state => Activity (Var .value(state))
}
}
override def put (ns: String , dtab: Dtab ): Future [Unit ] = {
val path = s"$zkPrefix /$ns "
log.info(s"Attempting to put dtab at $path " )
Future .collectToTry(
Seq (
zkSession.zk.create(
path,
Some (Buf .Utf8 (dtab.show)),
acls.map(ZkDtabStore .zkAcl),
CreateMode .Persistent
).unit,
zkSession.zk.setData(path, Some (Buf .Utf8 (dtab.show)), None ).unit
)
).flatMap {
case Seq (Throw (KeeperException .NoAuth (_)), _) |
Seq (_, Throw (KeeperException .NoAuth (_))) => Future .exception(Forbidden )
case Seq (Throw (e1), Throw (e2)) => Future .exception(new Exception ("Failed to put, try again." ))
case Seq (_, _) => Future .Done
}
}
private [this ] def versionInt (version: Buf ): Int = {
val bb = Buf .ByteBuffer .Owned .extract(version)
bb.getInt
}
private [this ] def versionBuf (version: Int ): Buf = {
val bb = ByteBuffer .allocate(4 )
bb.putInt(version)
bb.rewind()
Buf .ByteBuffer .Owned (bb)
}
}
object ZkDtabStore {
def zkAcl (acl: Acl ): Data .ACL = {
val perms = acl.perms.map {
case 'r' => Perms .Read
case 'w' => Perms .Write
case 'c' => Perms .Create
case 'd' => Perms .Delete
case 'a' => Perms .Admin
case c => throw new IllegalArgumentException (s"$c is not a valid permission" )
}.sum
Data .ACL (perms, Data .Id (acl.scheme, acl.id))
}
}