-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | semi-transparent persistence for Haskell using LMDB, STM -- @package vcache @version 0.2.5 module Database.VCache.VPut -- | VPut is a serialization monad akin to Data.Binary or Data.Cereal. -- However, VPut is not restricted to pure binaries: developers may -- include VRefs and PVars in the output. -- -- Content emitted by VPut will generally be read only by VCache. So it -- may be worth optimizing some cases, such as lists are written in -- reverse such that readers won't need to reverse the list. data VPut a -- | Store a reference to a value. The value reference must already use the -- same VCache and addres space as where you're putting it. putVRef :: VRef a -> VPut () -- | Store an identifier for a persistent variable in the same VCache and -- address space. putPVar :: PVar a -> VPut () -- | Put VSpace doesn't actually output anything, but will fail if the -- target space does not match the given one. putVSpace :: VSpace -> VPut () -- | Store an 8 bit word. putWord8 :: Word8 -> VPut () -- | Put a Word in little-endian or big-endian form. -- -- Note: These are mostly included because they're part of the -- Data.Binary and Data.Cereal APIs. They may be useful in some cases, -- but putVarInt will frequently be preferable. putWord16le :: Word16 -> VPut () -- | Put a Word in little-endian or big-endian form. -- -- Note: These are mostly included because they're part of the -- Data.Binary and Data.Cereal APIs. They may be useful in some cases, -- but putVarInt will frequently be preferable. putWord16be :: Word16 -> VPut () putWord32le :: Word32 -> VPut () putWord32be :: Word32 -> VPut () putWord64le :: Word64 -> VPut () putWord64be :: Word64 -> VPut () -- | Put a Data.Storable value, using intermediate storage to ensure -- alignment when serializing argument. Note that this shouldn't have any -- pointers, since serialized pointers won't usually be valid when loaded -- later. Also, the storable type shouldn't have any gaps (unassigned -- bytes); uninitialized bytes may interfere with structure sharing in -- VCache. putStorable :: Storable a => a -> VPut () -- | Put an arbitrary non-negative integer in varint format -- associated with Google protocol buffers. This takes one byte for -- values 0..127, two bytes for 128..16k, etc.. Will fail if given a -- negative argument. putVarNat :: Integer -> VPut () -- | Put an arbitrary integer in a varint format associated with -- Google protocol buffers with zigzag encoding of negative numbers. This -- takes one byte for values -64..63, two bytes for -8k..8k, three bytes -- for -1M..1M, etc.. Very useful if most numbers are near 0. putVarInt :: Integer -> VPut () -- | Ensure that at least N bytes are available for storage without growing -- the underlying buffer. Use this before unsafePutWord8 and similar -- operations. If the buffer must grow, it will grow exponentially to -- ensure amortized constant allocation costs. reserve :: Int -> VPut () reserving :: Int -> VPut a -> VPut a -- | Store an 8 bit word *assuming* enough space has been reserved. This -- can be used safely together with reserve. unsafePutWord8 :: Word8 -> VPut () -- | Put the contents of a bytestring directly. Unlike the put -- method for bytestrings, this does not include size information; just -- raw bytes. putByteString :: ByteString -> VPut () -- | Put contents of a lazy bytestring directly. Unlike the put -- method for bytestrings, this does not include size information; just -- raw bytes. putByteStringLazy :: ByteString -> VPut () -- | Put a character in UTF-8 format. putc :: Char -> VPut () -- | Obtain the number of bytes output by this VPut effort so far. This -- might be useful if you're breaking data structures up by their -- serialization sizes. This does not include VRefs or PVars, only raw -- binary data. See also peekChildCount. peekBufferSize :: VPut Int -- | Obtain the total count of VRefs and PVars in the VPut buffer. peekChildCount :: VPut Int -- | Limited cache control. module Database.VCache.Cache -- | VCache uses simple heuristics to decide which VRef contents to hold in -- memory. One heuristic is a target cache size. Developers may tune this -- to influence how many VRefs are kept in memory. -- -- The value is specified in bytes, and the default is ten megabytes. -- -- VCache size estimates are imprecise, converging on approximate size, -- albeit not accounting for memory amplification (e.g. from a compact -- UTF-8 string to Haskell's representation for [Char]). The limit given -- here is soft, influencing how aggressively content is removed from -- cache - i.e. there is no hard limit on content held by the cache. -- Estimated cache size is observable via vcacheStats. -- -- If developers need precise control over caching, they should use -- normal means to reason about GC of values in Haskell (i.e. VRef is -- cleared from cache upon GC). Or use vref' and deref' to avoid caching -- and use VCache as a simple serialization layer. setVRefsCacheLimit :: VSpace -> Int -> IO () -- | clearVRefsCache will iterate over cached VRefs in Haskell memory at -- the time of the call, clearing the cache for each of them. This -- operation isn't recommended for common use. It is rather hostile to -- independent libraries working with VCache. But this function may find -- some use for benchmarks or staged applications. clearVRefsCache :: VSpace -> IO () -- | Immediately clear the cache associated with a VRef, allowing any -- contained data to be GC'd. Normally, VRef cached values are cleared -- either by a background thread or when the VRef itself is garbage -- collected from Haskell memory. But sometimes the programmer knows -- best. clearVRefCache :: VRef a -> IO () module Database.VCache.Stats -- | Miscellaneous statistics for a VCache instance. These are not -- necessarily consistent, current, or useful. But they can say a a bit -- about the liveliness and health of a VCache system. data VCacheStats VCacheStats :: {-# UNPACK #-} !Int -> {-# UNPACK #-} !Int -> {-# UNPACK #-} !Int -> {-# UNPACK #-} !Int -> {-# UNPACK #-} !Int -> {-# UNPACK #-} !Int -> {-# UNPACK #-} !Int -> {-# UNPACK #-} !Address -> {-# UNPACK #-} !Int -> {-# UNPACK #-} !Int -> {-# UNPACK #-} !Int -> {-# UNPACK #-} !Int -> {-# UNPACK #-} !Int -> {-# UNPACK #-} !Int -> {-# UNPACK #-} !Int -> VCacheStats -- | estimated database file size (in bytes) vcstat_file_size :: VCacheStats -> {-# UNPACK #-} !Int -- | number of immutable values in the database vcstat_vref_count :: VCacheStats -> {-# UNPACK #-} !Int -- | number of mutable PVars in the database vcstat_pvar_count :: VCacheStats -> {-# UNPACK #-} !Int -- | number of named roots (a subset of PVars) vcstat_root_count :: VCacheStats -> {-# UNPACK #-} !Int -- | number of VRefs in Haskell process memory vcstat_mem_vrefs :: VCacheStats -> {-# UNPACK #-} !Int -- | number of PVars in Haskell process memory vcstat_mem_pvars :: VCacheStats -> {-# UNPACK #-} !Int -- | number of addresses with zero references vcstat_eph_count :: VCacheStats -> {-# UNPACK #-} !Int -- | address to next be used by allocator vcstat_alloc_pos :: VCacheStats -> {-# UNPACK #-} !Address -- | number of allocations by this process vcstat_alloc_count :: VCacheStats -> {-# UNPACK #-} !Int -- | target cache size in bytes vcstat_cache_limit :: VCacheStats -> {-# UNPACK #-} !Int -- | estimated cache size in bytes vcstat_cache_size :: VCacheStats -> {-# UNPACK #-} !Int -- | number of addresses GC'd by this process vcstat_gc_count :: VCacheStats -> {-# UNPACK #-} !Int -- | number of PVar updates to disk (after batching) vcstat_write_pvars :: VCacheStats -> {-# UNPACK #-} !Int -- | number of sync requests (~ durable transactions) vcstat_write_sync :: VCacheStats -> {-# UNPACK #-} !Int -- | number of LMDB-layer transactions by this process vcstat_write_frames :: VCacheStats -> {-# UNPACK #-} !Int -- | Compute some miscellaneous statistics for a VCache instance at -- runtime. These aren't really useful for anything, except to gain some -- confidence about activity or comprehension of performance. vcacheStats :: VSpace -> IO VCacheStats instance Show VCacheStats instance Ord VCacheStats instance Eq VCacheStats module Database.VCache.Path -- | VCache implements a simplified filesystem metaphor. By assigning a -- different prefix for root PVars loaded by different subprograms, -- developers can guard against namespace collisions. Each component may -- have its own persistent roots. -- -- While I call it a subdirectory, it really is just a prefix. Using -- "foo" followed by "bar" is equivalent to using "foobar". Developers -- should include their own separators if they expect them, i.e. "foo/" -- and "bar/". -- -- Paths are limited to ~500 bytes. For normal use, this limit will not -- be a problem. If you're creating PVars based on runtime inputs, those -- should always be dynamic PVars. Root PVar names should never be much -- larger than fully qualified function names. vcacheSubdir :: ByteString -> VCache -> VCache -- | as vcacheSubdir, but returns Nothing if the path is too large. vcacheSubdirM :: ByteString -> VCache -> Maybe VCache module Database.VCache.VGet -- | VGet is a parser combinator monad for VCache. Unlike pure binary -- parsers, VGet supports reads from a stack of VRefs and PVars to -- directly model structured data. data VGet a -- | Load a VRef, just the reference rather than the content. User must -- know the type of the value, since getVRef is essentially a typecast. -- VRef content is not read until deref. -- -- All instances of a VRef with the same type and address will share the -- same cache. getVRef :: VCacheable a => VGet (VRef a) -- | Load a PVar, just the variable. Content is loaded lazily on first -- read, then kept in memory until the PVar is GC'd. Unlike other Haskell -- variables, PVars can be serialized to the VCache address space. All -- PVars for a specific address are collapsed, using the same TVar. -- -- Developers must know the type of the PVar, since getPVar will cast to -- any cacheable type. A runtime error is raised only if you attempt to -- load the same PVar address with two different types. getPVar :: VCacheable a => VGet (PVar a) -- | Obtain the VSpace associated with content being read. Does not consume -- any data. getVSpace :: VGet VSpace -- | Read one byte of data, or fail if not enough data. getWord8 :: VGet Word8 -- | Read words of size 16, 32, or 64 in little-endian or big-endian. getWord16le :: VGet Word16 -- | Read words of size 16, 32, or 64 in little-endian or big-endian. getWord16be :: VGet Word16 getWord32le :: VGet Word32 getWord32be :: VGet Word32 getWord64le :: VGet Word64 getWord64be :: VGet Word64 -- | Read a Storable value. In this case, the content should be bytes only, -- since pointers aren't really meaningful when persisted. Data is copied -- to an intermediate structure via alloca to avoid alignment issues. getStorable :: Storable a => VGet a -- | Get a non-negative number represented in the Google protocol buffers -- varint encoding, e.g. as produced by putVarNat. getVarNat :: VGet Integer -- | Get an integer represented in the Google protocol buffers zigzag -- varint encoding, e.g. as produced by putVarInt. getVarInt :: VGet Integer -- | Load a number of bytes from the underlying object. A copy is performed -- in this case (typically no copy is performed by VGet, but the -- underlying pointer is ephemeral, becoming invalid after the current -- read transaction). Fails if not enough data. O(N) getByteString :: Int -> VGet ByteString -- | Get a lazy bytestring. (Simple wrapper on strict bytestring.) getByteStringLazy :: Int -> VGet ByteString -- | Get a character from UTF-8 format. Assumes a valid encoding. (In case -- of invalid encoding, arbitrary characters may be returned.) getc :: VGet Char -- | Access a given number of bytes without copying them. These bytes are -- read-only, and are considered to be consumed upon returning. The -- pointer should be considered invalid after returning from the -- withBytes computation. withBytes :: Int -> (Ptr Word8 -> IO a) -> VGet a -- | isolate a parser to a subset of bytes and value references. The child -- parser must process its entire input (all bytes and values) or will -- fail. If there is not enough available input to isolate, this -- operation will fail. -- -- isolate nBytes nVRefs operation isolate :: Int -> Int -> VGet a -> VGet a -- | label will modify the error message returned from the argument -- operation; it can help contextualize parse errors. label :: ShowS -> VGet a -> VGet a -- | lookAhead will parse a value, but not consume any input. lookAhead :: VGet a -> VGet a -- | lookAheadM will consume input only if it returns `Just a`. lookAheadM :: VGet (Maybe a) -> VGet (Maybe a) -- | lookAheadE will consume input only if it returns `Right b`. lookAheadE :: VGet (Either a b) -> VGet (Either a b) -- | isEmpty will return True iff there is no available input (neither -- references nor values). isEmpty :: VGet Bool module Database.VCache.VCacheable -- | To be utilized with VCache, a value must be serializable as a simple -- sequence of binary data and child VRefs. Also, to put then get a value -- must result in equivalent values. Further, values are Typeable to -- support memory caching of values loaded. -- -- Under the hood, structured data is serialized as the pair: -- -- (ByteString,[Either VRef PVar]) -- -- Developers must ensure that get on the serialization from -- put returns the same value. And get must be backwards -- compatible. Developers should consider version wrappers, cf. SafeCopy -- package. class Typeable a => VCacheable a put :: VCacheable a => a -> VPut () get :: VCacheable a => VGet a instance (VCacheable a, VCacheable b, VCacheable c, VCacheable d, VCacheable e, VCacheable f, VCacheable g) => VCacheable (a, b, c, d, e, f, g) instance (VCacheable a, VCacheable b, VCacheable c, VCacheable d, VCacheable e, VCacheable f) => VCacheable (a, b, c, d, e, f) instance (VCacheable a, VCacheable b, VCacheable c, VCacheable d, VCacheable e) => VCacheable (a, b, c, d, e) instance (VCacheable a, VCacheable b, VCacheable c, VCacheable d) => VCacheable (a, b, c, d) instance (VCacheable a, VCacheable b, VCacheable c) => VCacheable (a, b, c) instance (VCacheable a, VCacheable b) => VCacheable (a, b) instance VCacheable a => VCacheable [a] instance (VCacheable a, VCacheable b) => VCacheable (Either a b) instance VCacheable a => VCacheable (Maybe a) instance VCacheable () instance VCacheable VSpace instance VCacheable a => VCacheable (PVar a) instance VCacheable a => VCacheable (VRef a) instance VCacheable ByteString instance VCacheable ByteString instance VCacheable Word8 instance VCacheable Char instance VCacheable Bool instance VCacheable Integer instance VCacheable Int module Database.VCache.VTx -- | The VTx transactions allow developers to atomically manipulate PVars -- and STM resources (TVars, TArrays, etc..). VTx is a thin layer above -- STM, additionally tracking which PVars are written so it can push the -- batch to a background writer thread upon commit. -- -- VTx supports full ACID semantics (atomic, consistent, isolated, -- durable), but durability is optional (see markDurable). data VTx a -- | runVTx executes a transaction that may involve both STM TVars (via -- liftSTM) and VCache PVars (via readPVar, writePVar). runVTx :: VSpace -> VTx a -> IO a -- | run an arbitrary STM operation as part of a VTx transaction. liftSTM :: STM a -> VTx a -- | Durability for a VTx transaction is optional: it requires an -- additional wait for the background thread to signal that it has -- committed content to the persistence layer. Due to how writes are -- batched, a durable transaction may share its wait with many other -- transactions that occur at more or less the same time. -- -- Developers should mark a transaction durable only if necessary based -- on domain layer policies. E.g. for a shopping service, normal updates -- and views of the virtual shopping cart might not be durable while -- committing to a purchase is durable. markDurable :: VTx () -- | This variation of markDurable makes it easier to short-circuit complex -- computations to decide durability when the transaction is already -- durable. If durability is already marked, the boolean is not -- evaluated. markDurableIf :: Bool -> VTx () getVTxSpace :: VTx VSpace module Database.VCache.Sync -- | If you use a lot of non-durable transactions, you may wish to ensure -- they are synchronized to disk at various times. vcacheSync will simply -- wait for all transactions committed up to this point. This is -- equivalent to running a durable, read-only transaction. -- -- It is recommended you perform a vcacheSync as part of graceful -- shutdown of any application that uses VCache. vcacheSync :: VSpace -> IO () module Database.VCache.PVar -- | A PVar is a mutable variable backed by VCache. PVars can be read or -- updated transactionally (see VTx), and may store by reference as part -- of domain data (see VCacheable). -- -- A PVar is not cached. If you want memory cached contents, you'll need -- a PVar that contains one or more VRefs. However, the first read from a -- PVar is lazy, so merely referencing a PVar does not require loading -- its contents into memory. -- -- Due to how updates are batched, high frequency or bursty updates on a -- PVar should perform acceptably. Not every intermediate value is -- written to disk. -- -- Anonymous PVars will be garbage collected if not in use. Persistence -- requires ultimately tying contents to named roots (cf. loadRootPVar). -- Garbage collection is based on reference counting, so developers must -- be cautious when working with cyclic data, i.e. break cycles before -- disconnecting them from root. -- -- Note: PVars must never contain undefined or error values, nor any -- value that cannot be serialized by a VCacheable instance. data PVar a -- | Create a new, anonymous PVar as part of an active transaction. -- Contents of the new PVar are not serialized unless the transaction -- commits (though a placeholder is still allocated). newPVar :: VCacheable a => a -> VTx (PVar a) -- | Create an array of PVars with a given set of initial values. This is -- equivalent to `mapM newPVar`, but guarantees adjacent addresses in the -- persistence layer. This is mostly useful when working with large -- arrays, to simplify reasoning about paging performance. newPVars :: VCacheable a => [a] -> VTx [PVar a] -- | Create a new, anonymous PVar via the IO monad. This is similar to -- newTVarIO, but not as well motivated: global PVars should -- almost certainly be constructed as named, persistent roots. newPVarIO :: VCacheable a => VSpace -> a -> IO (PVar a) -- | Create an array of adjacent PVars via the IO monad. newPVarsIO :: VCacheable a => VSpace -> [a] -> IO [PVar a] -- | Global, persistent variables may be loaded by name. The name here is -- prefixed by vcacheSubdir to control namespace collisions between -- software components. These named variables are roots for GC purposes, -- and will not be deleted. -- -- Conceptually, the root PVar has always been there. Loading a root is -- thus a pure computation. At the very least, it's an idempotent -- operation. If the PVar exists, its value is lazily read from the -- persistence layer. Otherwise, the given initial value is stored. To -- reset a root PVar, simply write before reading. -- -- The recommended practice for roots is to use only a few of them for -- each persistent software component (i.e. each plugin, WAI app, etc.) -- similarly to how a module might use just a few global variables. If -- you need a dynamic set of variables, such as one per client, model -- that explicitly using anonymous PVars. loadRootPVar :: VCacheable a => VCache -> ByteString -> a -> PVar a -- | Load a root PVar in the IO monad. This is convenient to control where -- errors are detected or when initialization is performed. See -- loadRootPVar. loadRootPVarIO :: VCacheable a => VCache -> ByteString -> a -> IO (PVar a) -- | Read a PVar as part of a transaction. readPVar :: PVar a -> VTx a -- | Read a PVar in the IO monad. -- -- This is more efficient than a full transaction. It simply peeks at the -- underlying TVar with readTVarIO. Durability of the value read is not -- guaranteed. readPVarIO :: PVar a -> IO a -- | Write a PVar as part of a transaction. writePVar :: PVar a -> a -> VTx () -- | Modify a PVar. modifyPVar :: PVar a -> (a -> a) -> VTx () -- | Modify a PVar, strictly. modifyPVar' :: PVar a -> (a -> a) -> VTx () -- | Swap contents of a PVar for a new value. swapPVar :: PVar a -> a -> VTx a -- | virtual address space for PVar pvar_space :: PVar a -> VSpace -- | Each PVar has a stable address in the VCache. This address will be -- very stable, but is not deterministic and isn't really something you -- should treat as meaningful information about the PVar. Mostly, this -- function exists to support hashtables or memoization with PVar keys. -- -- The Show instance for PVars will also show the address. unsafePVarAddr :: PVar a -> Address -- | This function allows developers to access the reference count for the -- PVar that is currently recorded in the database. This may be useful -- for heuristic purposes. However, caveats are needed: -- -- First, because the VCache writer operates in a background thread, the -- reference count returned here may be slightly out of date. -- -- Second, it is possible that VCache will eventually use some other form -- of garbage collection than reference counting. This function should be -- considered an unstable element of the API. -- -- Root PVars start with one root reference. unsafePVarRefct :: PVar a -> IO Int module Database.VCache.VRef -- | A VRef is an opaque reference to an immutable value backed by a file, -- specifically via LMDB. The primary motivation for VRefs is to support -- memory-cached values, i.e. very large data structures that should not -- be stored in all at once in RAM. -- -- The API involving VRefs is conceptually pure. -- --
--   vref  :: (VCacheable a) => VSpace -> a -> VRef a
--   deref :: VRef a -> a
--   
-- -- Under the hood, each VRef has a 64-bit address and a local cache. When -- dereferenced, the cache is checked or the value is read from the -- database then cached. Variants of vref and deref control cache -- behavior. -- -- VCacheable values may themselves contain VRefs and PVars, storing just -- the address. Very large structured data is readily modeled by using -- VRefs to load just the pieces you need. However, there is one major -- constraint: -- -- VRefs may only represent acyclic structures. -- -- If developers want cyclic structure, they need a PVar in the chain. -- Alternatively, cycles may be modeled indirectly using explicit IDs. -- -- Besides memory caching, VRefs also utilize structure sharing: all -- VRefs sharing the same serialized representation will share the same -- address. Structure sharing enables VRefs to be compared for equality -- without violating conceptual purity. It also simplifies reasoning -- about idempotence, storage costs, memoization, etc.. data VRef a -- | Construct a reference with the cache initially active, i.e. such that -- immediate deref can access the value without reading from the -- database. The given value will be placed in the cache unless the same -- vref has already been constructed. vref :: VCacheable a => VSpace -> a -> VRef a -- | Dereference a VRef, obtaining its value. If the value is not in cache, -- it will be read into the database then cached. Otherwise, the value is -- read from cache and the cache is touched to restart any expiration. -- -- Assuming a valid VCacheable instance, this operation should return an -- equivalent value as was used to construct the VRef. deref :: VRef a -> a -- | In some cases, developers can reasonably assume they won't need a -- value in the near future. In these cases, use the vref' constructor to -- allocate a VRef without caching the content. vref' :: VCacheable a => VSpace -> a -> VRef a -- | Dereference a VRef. This will read from the cache if the value is -- available, but will not update the cache. If the value is not cached, -- it will be read instead from the persistence layer. -- -- This can be useful if you know you'll only dereference a value once -- for a given task, or if the datatype involved is cheap to parse (e.g. -- simple bytestrings) such that there isn't a strong need to cache the -- parse result. deref' :: VRef a -> a -- | Each VRef has an numeric address in the VSpace. This address is -- non-deterministic, and essentially independent of the arguments to the -- vref constructor. This function is unsafe in the sense that -- it violates the illusion of purity. However, the VRef address will be -- stable so long as the developer can guarantee it is reachable. -- -- This function may be useful for memoization tables and similar. -- -- The Show instance for VRef will also show the address. unsafeVRefAddr :: VRef a -> Address -- | This function allows developers to access the reference count for the -- VRef that is currently recorded in the database. This may be useful -- for heuristic purposes. However, caveats are needed: -- -- First, due to structure sharing, a VRef may share an address with -- VRefs of other types having the same serialized form. Reference counts -- are at the address level. -- -- Second, because the VCache writer operates in a background thread, the -- reference count returned here may be slightly out of date. -- -- Third, it is possible that VCache will eventually use some other form -- of garbage collection than reference counting. This function should be -- considered an unstable element of the API. unsafeVRefRefct :: VRef a -> IO Int -- | virtual address space for VRef vref_space :: VRef a -> VSpace -- | Cache modes are used when deciding, heuristically, whether to clear a -- value from cache. These modes don't have precise meaning, but there is -- a general intention: higher numbered modes indicate that VCache should -- hold onto a value for longer or with greater priority. In the current -- implementation, CacheMode is used as a pool of hitpoints in a -- gaming metaphor: if an entry would be removed, but its mode is greater -- than zero, the mode is reduced instead. -- -- The default for vref and deref is CacheMode1. Use of vrefc or derefc -- may specify other modes. Cache mode is monotonic: if the same VRef is -- deref'd with two different modes, the higher mode will be favored. -- -- Note: Regardless of mode, a VRef that is fully GC'd from the Haskell -- layer will ensure any cached content is also GC'd. data CacheMode CacheMode0 :: CacheMode CacheMode1 :: CacheMode CacheMode2 :: CacheMode CacheMode3 :: CacheMode -- | Construct a VRef with an alternative cache control mode. vrefc :: VCacheable a => CacheMode -> VSpace -> a -> VRef a -- | Dereference a VRef with an alternative cache control mode. derefc :: CacheMode -> VRef a -> a -- | Specialized, zero-copy access to a `VRef ByteString`. Access to the -- given ByteString becomes invalid after returning. This operation may -- also block the writer if it runs much longer than a single writer -- batch (though, writer batches are frequently large enough that this -- shouldn't be a problem if you're careful). withVRefBytes :: VRef ByteString -> (Ptr Word8 -> Int -> IO a) -> IO a -- | Zero-copy access to the raw encoding for any VRef. The given data -- becomes invalid after returning. This is provided for mostly for -- debugging purposes, i.e. so you can peek under the hood and see how -- things are encoded or eyeball the encoding. unsafeVRefEncoding :: VRef any -> (Ptr Word8 -> Int -> IO a) -> IO a module Database.VCache -- | VCache supports a filesystem-backed address space plus a set of -- persistent, named root variables that can be loaded from one run of -- the application to another. VCache supports a simple filesystem like -- model to resist namespace collisions between named roots. -- --
--   openVCache   :: Int -> FilePath -> IO VCache
--   vcacheSubdir :: ByteString -> VCache -> VCache
--   loadRootPVar :: (VCacheable a) => VCache -> ByteString -> a -> PVar a
--   
-- -- The normal use of VCache is to open VCache in the main function, use -- vcacheSubdir for each major framework, plugin, or independent -- component that might need persistent storage, then load at most a few -- root PVars per component. Most domain modeling should be at the data -- layer, i.e. the type held by the PVar. -- -- See VSpace, VRef, and PVar for more information. data VCache -- | Open a VCache with a given database file. -- -- In most cases, a Haskell process should open VCache in the Main module -- then pass it as an argument to the different libraries, frameworks, -- plugins, and other software components that require persistent -- storage. Use vcacheSubdir to progect against namespace collisions. -- -- When opening VCache, developers decide the maximum size and the file -- name. For example: -- --
--   vc <- openVCache 100 "db"
--   
-- -- This would open a VCache whose file-size limit is 100 megabytes, with -- the name "db", plus an additional "db-lock" lockfile. An exception -- will be raised if these files cannot be created, locked, or opened. -- The size limit is passed to LMDB and is separate from -- setVRefsCacheSize. -- -- Once opened, VCache typically remains open until process halt. If -- errors are detected, e.g. due to writing an undefined value to a PVar -- or running out of space, VCache will attempt to halt the process. openVCache :: Int -> FilePath -> IO VCache -- | VSpace represents the virtual address space used by VCache. Except for -- loadRootPVar, most operations use VSpace rather than the VCache. -- VSpace is accessed by vcache_space, vref_space, or pvar_space. -- -- Addresses from this space are allocated incrementally, odds to PVars -- and evens to VRefs, independent of object size. The space is elastic: -- it isn't a problem to change the size of PVars (even drastically) from -- one update to another. -- -- In theory, VSpace could run out of 64-bit addresses. In practice, this -- isn't a real concern - a quarter million years at a sustained million -- allocations per second. data VSpace -- | virtual address space for VCache vcache_space :: VCache -> VSpace