swapper-0.1: Transparently swapping data from in-memory structures to disk

MaintainerRoman Smr <roman.smrz@seznam.cz>



This module provides the actual wrapper around functors, which allows them to swap their values to disk. Before any use, original structure have to by turned into appropriate Swapper using function mkSwapper; this has to be done in IO monad. The created object can then be used in normal pure way, when internal side effects concern only database files determined by the first parameter passed to mkSwapper; those should not be altered externally during the program run.

Because the Swapper is different type than the original functor, lifting functions are provided to allow manipulation with it. Those are adding for functions, which add new elements like : or Data.Map.insert, getting for function retrieving elements like head or Data.Map.lookup, changing for functions changing the structure itself like tail. Concrete examples are provided it the description of the aforementioned functions.

When creating snapshot using putToSnapshot, all items present it structure are saved into the current database file (its name is then recorded to the snapshot itself in order to be able to load in future) and new one is created for items added thereafter. When the snapshot is loaded using getFromSnapshot, only indices and auxiliary data are loaded into the memory at that time; values are read on demand from their database file.





:: (Serialize a, NFData a, Functor f) 
=> FilePath

Prefix of database files

-> f a

Initial data

-> IO (Swapper f a) 

Creates Swapper from given functor object. The first parameter is prefix from which the name of database files are derived (by appending their index number and database extension), those files should not be altered by external files when the program is running or between saving and loading snapshots.

The Swapper initially uses the NullCache, which does not keep any data in memory, apart from those referenced from other places.

setCache :: Cache c a => Swapper f a -> c -> IO ()Source

Sets cache for given Swapper object; it determines, which items are to be swapped onto disk, when available slots are used up (and also how many of such slots actually exists in the first place); can be shared among several Swappable objects.

setCacheRef :: Cache c a => IORef (Swapper f a) -> c -> IO ()Source

Analogous to the setCache, but works with Swapper encosed in an IORef.

adding :: (Serialize a, NFData a) => (forall b. b -> f b -> f b) -> a -> Swapper f a -> Swapper f aSource

Lifting function used for adding new elements to the Swapper object. Needs to be applied to functions like : or Data.Map.insert for them to act on Swapper instead of the original structure. Requires the function in its first argument to work for functor containing arbitrary type.

 a :: Swapper [] Int
 let a' = adding (:) 6 a

 b :: Swapper (Map String) Int
 let b' = adding (insert "new") 42 b

getting :: Serialize a => (forall b. f b -> b) -> Swapper f a -> aSource

Function used to lift functions getting elements from inner structure, like head or Data.Map.lookup, to functions getting elements from Swapper object. Functions in the first argument needs to work on f containing elements of arbitrary type.

 a :: Swapper [] Int
 let x = getting head a

 b :: Swapper (Map String) Int
 let y = getting (lookup "some") b

changing :: Serialize a => (forall b. f b -> f b) -> Swapper f a -> Swapper f aSource

This function is needed to make functions changing the structure somehow (like tail or Data.Map.delete), to change the Swapper instead. Like the previous lifting functions, its first argument needs to work for any values of any type.

 a :: Swapper [] Int
 let a' = changing tail a

 b :: Swapper (Map String) Int
 let b' = changing (delete "some") b