-
Notifications
You must be signed in to change notification settings - Fork 123
org.corfudb.runtime.smr
A State-Machine-Replication (SMR) layer provides transparent object replication. An object is replicated by inflicting all object accesses through an SMR. The basic API of an SMR engine is defined in ISMREngine, and a direct log-based implementation is provided in a template class SimpleSMREngine<T>
.
ISMREngine defines two fundamental functionalities.
-
propose
takes as parameter a lambda function captured inside an ISMREngineCommand object, and appends it to the stream. To mutate a replicated object state, user code needs to propose the update through theISMREngine.propose
method. -
sync
plays back the sequence of SMR updates, which are each applied to the in-memory state. To access the in-memory state of a replicated object, user code should first invokesync
.
Below is a recipe for transforming a user's custom-made class into a replicated object via ISMREngine. To be concrete, consider a MyMap
object with two methods, get
and put
.
class Map<T> {
MyMap<T>() { .. }
public void put(<T> param1) { .. }
public <T> get(param2) { .. }
}
-
Inside the constructor, instantiate an
SMREngine
object over a stream.MyMap<T>() { smrEngine = new SimpleSMREngine(streamID, MyMap<T>.class); }
-
Turn object methods private.
private void pPut(<T> param1) { .. } private <T> pGet(param2) { .. }
-
Capture mutating-methods as lambdas. This lambda is a BiConsumer, which takes the object the command is to act on, and an options object. You'll need to cast the lambda into a ISMREngineCommand, otherwise the lambda won't be serializable and your object won't work! ISMREngineCommand<MyMap> mapPut = (ISMREngineCommand<MyMap>) (a,opt) -> a.pPut(opt);
-
Re-define the public mutator-methods to propose the corresponding update:
void put(<T> obj) { smrEngine.propose(mapPut, obj); }
-
Turn reading methods to first invoke
SMREngine.sync
.public <T> get(param2) { smrEngine.sync(); return pGet(param2); }
An interesting use case to consider is an object method that contains conditional writes, such as a test-and-modify. In order to apply the compound operation, we need to wait until a log position is determined, play back the log, and then apply the operation. The recommended way to implement this, which uses Java runtime futures, is exemplified in the CorfuDB tutorial example.