Safe Haskell | Safe-Inferred |
---|
Control.Stasis
Contents
Description
Stasis is a modified implementation of Multi-version concurrency control MVCC. The original purpose of Stasis was to provide a mechanism for having safe, "mutable" variables WITHOUT any locking whatsoever.
How Stasis works
Given an object a.
When a is passed to a function it is wrapped in a Pod
which creates a
stasis like environment for a.
At any point, any function that received the Pod
can "update" it by
put
ting a new version of a.
i.e. a itself is not updated, it is replaced. So what the Pod
does is
store the address of an a and an update changes the address the Pod
points
to, to another a.
The address of a can only change to point to another value of a, i.e. it is type safe.
At any time, a function who's received a Pod
can freeze it. In this case,
every time that function fetch
es a from the FrozenPod
, the same version
that was frozen is always returned and at any time the function can also get
the latest version of a by get
ting the current non-frozen version.
Internally b maintains a map of addresses to frozen IDs, when a function freezes a version of a it stores the address of a with a unique freeze id that is returned to the function. The function must then pass the freeze id each time it wants to get the frozen version of a for that id. This also means that a function can lock multiple versions of a.
Originally the intention was to use pointers but IORefs works with atomic operations and achieves effectively the same thing. http://hackage.haskell.org/package/base-4.5.1.0/docs/Foreign-StablePtr.html http://hackage.haskell.org/package/base-4.6.0.1/docs/Data-IORef.html
- data Pod a = Stasis {}
- data FrozenPod a = FrozenPod {}
- stasis :: a -> IO (Pod a)
- version :: Pod a -> IO Int
- versionF :: FrozenPod a -> Int
- put :: a -> Pod a -> IO Bool
- merge :: a -> Pod a -> (a -> a -> a) -> IO Bool
- get :: Pod a -> IO a
- fetch :: FrozenPod a -> a
- freeze :: Ord a => Pod a -> IO (FrozenPod a)
- defrost :: Ord a => FrozenPod a -> IO (Pod a)
Primitives
Stasis
has two primitives, a Pod
and a FrozenPod
.
A Pod
is 'created from any value a, once created, only new versions of a can be placed in the same pod.
A Pod
gets passed around in place of an ordinary value. Pod
s can be frozen
to create a FrozenPod
, when frozen the value of a is stays the same
Operations
The type b supports 6 operations, stasis
, put
,get
,fetch
,freeze
,defrost
.
-
stasis
- creates a newPod
which can be passed around in place of a -
put
- Put adds a new version of a to an existingPod
-
get
- Gets the current version of a from aPod
-
freeze
- Freezes a version of a in stasis, usedefrost
on the returnedFrozenPod
to get the value back -
defrost
Returns the version of a for the givenFrozenPod
, i.e. it gets the value of a when it was frozen -
fetch
the same asdefrost
but leaves a in aFrozenPod
which means it will not be garbage collected until it isdefrost
ed
Arguments
:: a | A value that would otherwise be the new version |
-> Pod a | The pod which will have its next version created from the function provided |
-> (a -> a -> a) | A function which accepts the new value, current value and returns a new value made by merging the first two |
-> IO Bool |
put
works great when there is a single writer but if multiple threads are writing new versions it is sometimes
useful to be able to merge the current value with a new value to create a new version. This function allows for this
and enables the ability for multiple writers to create new versions while minimizing the probability of version loss