A library that caches ZooKeeper data. The cached data is used only for read operations, namely get Data and get Children. It does not support write operations, these should be done via the ZooKeeper Client.
The library is intended to be used by applications that heavily use ZooKeeper for read operations and can cope with eventual consistency.
It is written in Scala, the cache synchronization is internally done using Akka and it provides APIs for Scala, Java and Akka, all of them easily accessible via a factory object.
The paths to be cached are defined using the library's API. Subtrees and children of the defined paths to cache are automatically cached as well.
Whenever something changes in the ZooKeeper, watches are activated and the cache eventually follows the change (add/remove nodes and data).
- Built on top of the ZooKeeper API
- Offering the required abstractions in order to use other ZooKeper frameworks (like Apache Curator)
- Cache the whole ZooKeeper tree, or just parts of it
- Data synchronization using Akka Actors
- Access with Scala, Akka, or Java APIs.
- Deployed in the Maven Central:
<dependency>
<groupId>com.github.astonbitecode</groupId>
<artifactId>scakka-zoo-cache</artifactId>
<version>0.2.1</version>
</dependency>
Latest snapshot:
<dependency>
<groupId>com.github.astonbitecode</groupId>
<artifactId>scakka-zoo-cache</artifactId>
<version>0.2.2-SNAPSHOT</version>
</dependency>
The APIs of the ScakkaZooCache are offered for Scala, Akka and Java, depending on how the cache is created (which com.github.astonbitecode.zoocache.ScakkaZooCacheFactory
method will be used for the instantiation of the cache).
They all support the following:
-
Adding a path to the cache
After adding a path to the cache (eg.
/path/one
, all the ZooKeeper changes under the path/path/one
will be monitored. So, for example when getting the data of the path/path/one/child1
the Data of the zNode will be returned from the cache. Of course, this will happen if and only if the path really exists in the ZooKeeper. In the opposite case, the call will throw aNotCachedException
. -
Reading children of a path.
-
Getting data of a node in a path.
-
Removing a path from the cache
Stop monitoring a path and remove it from the cache.
-
Stopping the cache
Note: Writing to the ZooKeeper is not done via the ScakkaZooCache. It should be done by using the ZooKeeper client itself. The cache is used only for reading operations.
Assuming that zk is a ZooKeeper
class instance, a ScakkaZooCache
can be created like following:
import com.github.astonbitecode.zoocache.ScakkaZooCacheFactory
val zooCache = ScakkaZooCacheFactory.scala(zk)
import com.github.astonbitecode.zoocache.ScakkaZooCacheFactory
val actorSystem = ActorSystem("myActorSystem")
val zooCache = ScakkaZooCacheFactory.scala(zk, actorSystem)
import com.github.astonbitecode.zoocache.ScakkaZooCacheFactory
// This is one Actor
class MyActor extends Actor {
// Create a zoocache instance
val zooCache = ScakkaZooCacheFactory.scala(zk, context)
// Handle messages
override def receive(): Receive = {
case _ => ... // Use the zoo cache
}
}
Simply call the addPathToCache:
zooCache.addPathToCache("/path/one")
// Get the children of a path
val children = zooCache.getChildren("/a/path")
// Get the data of a path
val data = zooCache.getData("/a/path")
// Find all the paths that match a regex and return a List of results
val cacheResults = zooCache.find("(^\\/a\\/path\\/[\\w]*)")
import com.github.astonbitecode.zoocache.ScakkaZooCacheFactory
// Create your ActorSystem
val actorSystem = ActorSystem("myActorSystem")
// Create a ScakkaZooCache
val zooCache = ScakkaZooCacheFactory.scala(zk, actorSystem)
// Get the Akka Props from the factory
val props = ScakkaZooCacheFactory.props()
// Create the ActorRef
val zooCacheActorRef = actorSystem.actorOf(props)
// Contact the ActorRef
zooCacheActorRef ! GetChildren("/a/path")
zooCacheActorRef ! AddPathToCache("/a/path")
// Get the children of a path
zooCacheActorRef ! GetChildren("/a/path")
// Get the data of a path
zooCacheActorRef ! GetData("/a/path")
// Find all the paths that match a regex and return a List of results
zooCacheActorRef ! Find("(^\\/a\\/path\\/[\\w]*)")
The available messages for the Akka API exist in the com.github.astonbitecode.zoocache.api.akka
package.
Each one of the available Akka messages has its corresponding response. This message is sent by the Actor that handles the Akka API as a response to a request. (You can consult the Scaladocs for more details).
For example, when sending a GetChildren
message, a response of GetChildrenResponse
will be received:
val askFuture = zooCacheActorRef ? GetChildren("/a/path")
val children: GetChildrenResponse = Await.result(askFuture, 30 seconds)
Akka users are not obliged to use the Ask pattern. All the Akka messages offered by the ScakkaZooCache API have an Optional parameter that can be used for Request-Response correlation:
import com.github.astonbitecode.zoocache.ScakkaZooCacheFactory
import com.github.astonbitecode.zoocache.api.akka._
// This is one Actor
class MyActor extends Actor {
// Create a zoocache instance
val zooCache = ScakkaZooCacheFactory.scala(zk, context)
// Create the zoocache Actor to handle the Akka API messages
val zooCacheActorRef = context.actorOf(ScakkaZooCacheFactory.props(zooCache))
// Send a message to the zooCacheActor
zooCacheActorRef ! GetChildren("/a/path", Some("123"))
// Handle the Responses
override def receive(): Receive = {
case getChildrenResponse: GetChildrenResponse => {
if (getChildrenResponse.correlation == Some("123")) {
println("OK")
} else {
println("CORRELATION ERROR")
}
}
case _ =>
}
}
In case of failure of any of the Akka API messages, the sender will receive a CacheFailure
.
This message contains the failure details along with any correlation object the respective request contained.
import com.github.astonbitecode.zoocache.ScakkaZooCacheFactory;
import com.github.astonbitecode.zoocache.api.java.JScakkaZooCache;
JScakkaZooCache zooCache = ScakkaZooCacheFactory.java(zk);
Simply call the addPathToCache:
import java.util.concurrent.Future;
Future<BoxedUnit> f = zooCache.addPathToCache("/a/path");
f.get();
// Get the children of a path
List<String> children = zooCache.getChildren("/a/path");
// Get the data of a path
byte[] data = zooCache.getData("/a/path");
// Find all the paths that match a regex and return a List of results
import com.github.astonbitecode.zoocache.api.dtos.JCacheResult;
List<JCacheResult> cacheResults = zooCache.find("(^\\/a\\/path\\/[\\w]*)");