-
Notifications
You must be signed in to change notification settings - Fork 49
Getting started with Sirius
======
Configuring and instantiating Sirius requires the following steps:
- implement a RequestHandler, which will build your app-specific in-memory data structures
- build a configuration object for Sirius
- create an instance of Sirius using
SiriusFactory.createInstance
- await Sirius initialization
These steps are described in more detail below. The included examples use modified code snippets from our reference applications which implement simple datastores using the Sirius library.
####Implementing a RequestHandler
To use the Sirius library, RequestHandler must be implemented. The RequestHandler has three methods:
- handleGet(String key) - retrieves data from the backend
- handlePut(String key, byte[] body) - updates or creates an item
- handleDelete(String key) - deletes an item
A complex Sirius application will probably have the backend logic separated into other classes, but to keep this example simple the RequestHandler will use a ConcurrentHashMap as the backend implementation. The groovy reference application demonstrates this type of implementation
public class DefaultRequestHandler implements RequestHandler {
private static final String OK = "ok"
ConcurrentHashMap backend = [:]
@Override
public SiriusResult handleGet(String key) {
String value = backend.get(key)
if (value == null) {
println "[$key] does not have a value"
return SiriusResult.none()
}
println "value for [$key] is [$value]"
return SiriusResult.some(value)
}
@Override
public SiriusResult handlePut(String key, byte[] body) {
def value = new String(body)
backend.put(key, value)
println "added value [$value] to backend with key [$key]"
return SiriusResult.some(OK)
}
@Override
public SiriusResult handleDelete(String key) {
def value = backend.remove(key)
if (value) {
println "deleted value [$value] for [$key]"
} else {
println "key [$key] does not exist"
}
return SiriusResult.some(OK)
}
}
The RequestHandler implementation is not used directly, but instead it is inserted into Sirius's workflow for updating and retrieving data from the in-memory datastore. Although Sirius does not require a thread safe backend, in order to safely deal with concurrent backend operations (and avoid ConcurrentModificationException ), it is likely the backend will require some kind of synchronized behaviour.
As you can see, Sirius uses a very simple interface for managing a memory based backend. So as long as a backend is maintainable with this interface, an implementor can make the datastore as simple or complex as they need.
####Configuring Sirius
Before booting up Sirius, a SiriusConfiguration needs to be constructed. The simplest SiriusConfiguration would look something like
SiriusConfiguration siriusConfig = new SiriusConfiguration();
siriusConfig.setProp(SiriusConfiguration.HOST(), "localhost");
siriusConfig.setProp(SiriusConfiguration.PORT(), 2552);
siriusConfig.setProp(SiriusConfiguration.CLUSTER_CONFIG(), "/path/to/cluster.config");
siriusConfig.setProp(SiriusConfiguration.LOG_LOCATION(), "/path/to/UberStore");
- host - host of this Sirius / akka node (see cluster config below)
- port - port of this Sirius / akka node (see cluster config below)
- cluster config - path to cluster config containing sirius / akka endpoints of all other nodes
- log location - path of directory to store the transaction log
A typical cluster config will look something like
# specify actors in cluster, one per line, as akka addresses
akka.tcp://sirius-system@localhost:2552/user/sirius
akka.tcp://sirius-system@localhost:2553/user/sirius
akka.tcp://sirius-system@localhost:2554/user/sirius
The cluster config file must have the same host and port as the configuration. For instance, you can't use the ip in one place and the host in another.
See Configuring Sirius for more configuration details
####Running Sirius
Once RequestHandler and
SiriusConfiguration have been
implemented and instantiated, use SiriusFactory.createInstance(RequestHandler requestHandler, SiriusConfig siriusConfig)
to create a
Sirius instance. Before using
Sirius, one should wait until it is online.
To do this, periodically check the isOnline()
method. For example
System.out.println("Waiting for sirius to boot.");
Long waitTime = System.currentTimeMillis() + timeout;
Long sleepTime = 100L;
while (!siriusImpl.isOnline() && System.currentTimeMillis() < waitTime) {
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
// we're the only ones here, nobody's going to interrupt us.
// and if it does happen, well, just keep waiting for sirius to start anyway.
}
}
if (!siriusImpl.isOnline() ) {
throw new IllegalStateException("Sirius failed to boot in " + timeout + "ms");
}
When issue #17 is done, this should be a lot easier.
####Using Sirius
Sirius has the following methods
- Future enqueueGet(String key)
- Future enqueuePut(String key, byte[])
- Future enqueueDelete(String key)
- boolean isOnline()
The data operations are very similar to data operations in
RequestHandler. When calling
enqueuePut
or enqueueDelete
the following occurs
- nodes coordinate to reach consensus on ordering
- data is sent to other nodes to ensure consistency
- data is persisted to the UberStore
- appropriate RequestHandler method is called
enqueueGet(String key)
is rarely used. Instead gets are generally performed directly against the underlying
datastore. The extra serialization steps that Sirius adds when calling enqueueGet(String key)
to get the same answer
are rarely justified.
To see runnable examples, please checkout our reference applications
Copyright 2013-2017 Comcast Cable Communications Management, LLC
Using Sirius
Getting started with Sirius
Configuring Sirius
How to Deploy Sirius
Reference Applications
Migrations and Release Notes
Migration Guide 1.1.x to 1.2.x
Release Notes 2.0.0
Migration Guide 1.2.x to 2.0.x
Developing Sirius
Getting Started
Contributing Guildelines
License
Releasing Sirius
Scaladocs
Test Timeout Failures
Transaction Log
Implementation
Live Compaction
waltool
Other