{-# LANGUAGE MagicHash #-}

-- | On disk key-value tables, implemented as Log Structured Merge (LSM) trees.
--
-- This module is the API for \"normal\" tables, as opposed to \"monoidal\"
-- tables (that support monoidal updates and unions).
--
-- Key features:
--
-- * Basic key\/value operations: lookup, insert, delete
-- * Range lookups by key or key prefix
-- * Support for BLOBs: large auxilliary values associated with a key
-- * On-disk durability is /only/ via named snapshots: ordinary operations
--   are otherwise not durable
-- * Opening tables from previous named snapshots
-- * Full persistent data structure by cheap table duplication: all duplicate
--   tables can be both accessed and modified
-- * High performance lookups on SSDs by I\/O batching and concurrency
--
-- This module is intended to be imported qualified.
--
-- > import qualified Database.LSMTree.Normal as LSMT
--
module Database.LSMTree.Normal (
    -- * Exceptions
    Common.SessionDirDoesNotExistError (..)
  , Common.SessionDirLockedError (..)
  , Common.SessionDirCorruptedError (..)
  , Common.SessionClosedError (..)
  , Common.TableClosedError (..)
  , Common.TableCorruptedError (..)
  , Common.TableTooLargeError (..)
  , Common.TableUnionNotCompatibleError (..)
  , Common.SnapshotExistsError (..)
  , Common.SnapshotDoesNotExistError (..)
  , Common.SnapshotCorruptedError (..)
  , Common.SnapshotNotCompatibleError (..)
  , Common.BlobRefInvalidError (..)
  , Common.CursorClosedError (..)
  , Common.FileFormat (..)
  , Common.FileCorruptedError (..)
  , Common.InvalidSnapshotNameError (..)

    -- * Tracing
  , Common.LSMTreeTrace (..)
  , Common.TableTrace (..)
  , Common.MergeTrace (..)

    -- * Table sessions
  , Session
  , withSession
  , openSession
  , closeSession

    -- * Table
  , Table
  , Common.TableConfig (..)
  , Common.defaultTableConfig
  , Common.SizeRatio (..)
  , Common.MergePolicy (..)
  , Common.WriteBufferAlloc (..)
  , Common.NumEntries (..)
  , Common.BloomFilterAlloc (..)
  , Common.defaultBloomFilterAlloc
  , Common.FencePointerIndexType (..)
  , Common.DiskCachePolicy (..)
  , Common.MergeSchedule (..)
  , Common.defaultMergeSchedule
  , withTable
  , new
  , close
    -- ** Resource management #resource#
    -- $resource-management

    -- ** Exception safety #exception#
    -- $exception-safety

    -- * Table queries and updates
    -- ** Queries
  , lookups
  , LookupResult (..)
  , rangeLookup
  , Range (..)
  , QueryResult (..)
    -- ** Cursor
  , Cursor
  , withCursor
  , withCursorAtOffset
  , newCursor
  , newCursorAtOffset
  , closeCursor
  , readCursor
    -- ** Updates
  , inserts
  , deletes
  , updates
  , Update (..)
    -- ** Blobs
  , BlobRef
  , retrieveBlobs

    -- * Durability (snapshots)
  , Common.SnapshotName
  , Common.toSnapshotName
  , Common.isValidSnapshotName
  , Common.SnapshotLabel (..)
  , createSnapshot
  , openSnapshot
  , Common.TableConfigOverride
  , Common.configNoOverride
  , Common.configOverrideDiskCachePolicy
  , deleteSnapshot
  , listSnapshots

    -- * Persistence
  , duplicate

    -- * Table union
  , union
  , unions
  , UnionDebt (..)
  , remainingUnionDebt
  , UnionCredits (..)
  , supplyUnionCredits

    -- * Concurrency #concurrency#
    -- $concurrency

    -- * Serialisation
  , SerialiseKey
  , SerialiseValue

    -- * Utility types
  , IOLike
  ) where

import           Control.DeepSeq
import           Control.Monad
import           Control.Monad.Class.MonadThrow
import           Data.Bifunctor (Bifunctor (..))
import           Data.Kind (Type)
import           Data.List.NonEmpty (NonEmpty (..))
import           Data.Typeable (Proxy (..), Typeable, eqT, type (:~:) (Refl),
                     typeRep)
import qualified Data.Vector as V
import           Database.LSMTree.Common (BlobRef (BlobRef), IOLike, Range (..),
                     SerialiseKey, SerialiseValue, Session, UnionCredits (..),
                     UnionDebt (..), closeSession, deleteSnapshot,
                     listSnapshots, openSession, withSession)
import qualified Database.LSMTree.Common as Common
import qualified Database.LSMTree.Internal as Internal
import qualified Database.LSMTree.Internal.BlobRef as Internal
import qualified Database.LSMTree.Internal.Entry as Entry
import qualified Database.LSMTree.Internal.Serialise as Internal
import qualified Database.LSMTree.Internal.Vector as V
import           GHC.Exts (Proxy#, proxy#)

-- $resource-management
-- Sessions, tables and cursors use resources and as such need to be
-- managed. In particular they retain memory (for indexes, Bloom filters and
-- write buffers) and hold open multiple file handles.
--
-- The resource management style that this library uses is explicit management,
-- with backup from automatic management. Explicit management is required to
-- enable prompt release of resources. Explicit management means using 'close'
-- on 'Table's when they are no longer needed, for example.
-- The backup management relies on GC finalisers and thus is not guaranteed to
-- be prompt.
--
-- In particular, certain operations create new resources:
--
-- * 'openSession'
-- * 'new'
-- * 'openSnapshot'
-- * 'duplicate'
-- * 'newCursor'
--
-- These ones must be paired with a corresponding 'closeSesstion', 'close' or
-- 'closeCursor'.
--

-- $exception-safety
--
-- To prevent resource/memory leaks in the presence of asynchronous exceptions,
-- it is recommended to:
--
-- 1. Run resource-allocating functions with asynchronous exceptions masked.
-- 2. Pair a resource-allocating function with a masked cleanup function, for
-- example using 'bracket'.
--
-- These function pairs include:
--
-- * 'openSession', paired with 'closeSession'
-- * 'new', paired with 'close'
-- * 'openSnapshot', paired with 'close'
-- * 'duplicate', paired with 'close'
-- * 'newCursor', paired with 'closeCursor'
--
-- Bracket-style @with*@ functions are also provided by the library, such as
-- 'withTable'.

-- $concurrency
-- Table are mutable objects and as such applications should restrict their
-- concurrent use to avoid races.
--
-- It is a reasonable mental model to think of a 'Table' as being like a
-- @IORef (Map k v)@ (though without any equivalent of @atomicModifyIORef@).
--
-- The rules are:
--
-- * It is a race to read and modify the same table concurrently.
-- * It is a race to modify and modify the same table concurrently.
-- * No concurrent table operations create a /happens-before/ relation.
-- * All synchronisation needs to occur using other concurrency constructs.
--
-- * It is /not/ a race to read and read the same table concurrently.
-- * It is /not/ a race to read or modify /separate/ tables concurrently.
--
-- We can classify all table operations as \"read\" or \"modify\" for the
-- purpose of the rules above. The read operations are:
--
-- * 'lookups'
-- * 'rangeLookup'
-- * 'retrieveBlobs'
-- * 'createSnapshot'
-- * 'duplicate'
--
-- The write operations are:
--
-- * 'inserts'
-- * 'deletes'
-- * 'updates'
-- * 'close'
--
-- In particular it is possible to read a stable view of a table while
-- concurrently modifying it: 'duplicate' the table first and then perform reads
-- on the duplicate, while modifying the original table. Note however that it
-- would still be a race to 'duplicate' concurrently with modifications: the
-- duplication must /happen before/ subsequent modifications.
--
-- Similarly, a cursor constitutes a stable view of a table and can safely be
-- read while modifying the original table.
-- However, reading from a cursor will take a lock, so concurrent reads on the
-- same cursor will block until the first one completes. This is due to the
-- cursor position being updated as entries are read.
--
-- It safe to read a table (using 'lookups' or 'rangeLookup') concurrently, and
-- doing so can take advantage of CPU and I\/O parallelism, and thus may
-- improve throughput.


{-------------------------------------------------------------------------------
  Tables
-------------------------------------------------------------------------------}

-- | A handle to an on-disk key\/value table.
--
-- An LSMT table is an individual key value mapping with in-memory and on-disk
-- parts. A table is the object\/reference by which an in-use LSM table will be
-- operated upon. In this API it identifies a single mutable instance of an LSM
-- table. The duplicate tables feature allows for there to may be many such
-- instances in use at once.
type Table = Internal.NormalTable

{-# SPECIALISE withTable ::
     Session IO
  -> Common.TableConfig
  -> (Table IO k v b -> IO a)
  -> IO a #-}
-- | (Asynchronous) exception-safe, bracketed opening and closing of a table.
--
-- If possible, it is recommended to use this function instead of 'new' and
-- 'close'.
withTable ::
     IOLike m
  => Session m
  -> Common.TableConfig
  -> (Table m k v b -> m a)
  -> m a
withTable :: forall (m :: * -> *) k v b a.
IOLike m =>
Session m -> TableConfig -> (Table m k v b -> m a) -> m a
withTable (Internal.Session' Session m h
sesh) TableConfig
conf Table m k v b -> m a
action =
    Session m h -> TableConfig -> (Table m h -> m a) -> m a
forall (m :: * -> *) h a.
(MonadMask m, MonadSTM m, MonadMVar m, PrimMonad m) =>
Session m h -> TableConfig -> (Table m h -> m a) -> m a
Internal.withTable Session m h
sesh TableConfig
conf (Table m k v b -> m a
action (Table m k v b -> m a)
-> (Table m h -> Table m k v b) -> Table m h -> m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Table m h -> Table m k v b
forall (m :: * -> *) k v b h.
Typeable h =>
Table m h -> NormalTable m k v b
Internal.NormalTable)

{-# SPECIALISE new ::
     Session IO
  -> Common.TableConfig
  -> IO (Table IO k v b) #-}
-- | Create a new empty table, returning a fresh table.
--
-- NOTE: tables hold open resources (such as open files) and should be
-- closed using 'close' as soon as they are no longer used.
--
new ::
     IOLike m
  => Session m
  -> Common.TableConfig
  -> m (Table m k v b)
new :: forall (m :: * -> *) k v b.
IOLike m =>
Session m -> TableConfig -> m (Table m k v b)
new (Internal.Session' Session m h
sesh) TableConfig
conf = Table m h -> NormalTable m k v b
forall (m :: * -> *) k v b h.
Typeable h =>
Table m h -> NormalTable m k v b
Internal.NormalTable (Table m h -> NormalTable m k v b)
-> m (Table m h) -> m (NormalTable m k v b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Session m h -> TableConfig -> m (Table m h)
forall (m :: * -> *) h.
(MonadSTM m, MonadMVar m, PrimMonad m, MonadMask m) =>
Session m h -> TableConfig -> m (Table m h)
Internal.new Session m h
sesh TableConfig
conf

{-# SPECIALISE close ::
     Table IO k v b
  -> IO () #-}
-- | Close a table. 'close' is idempotent. All operations on a closed
-- handle will throw an exception.
--
-- Any on-disk files and in-memory data that are no longer referenced after
-- closing the table are lost forever. Use 'Snapshot's to ensure data is
-- not lost.
close ::
     IOLike m
  => Table m k v b
  -> m ()
close :: forall (m :: * -> *) k v b. IOLike m => Table m k v b -> m ()
close (Internal.NormalTable Table m h
t) = Table m h -> m ()
forall (m :: * -> *) h.
(MonadMask m, MonadSTM m, MonadMVar m, PrimMonad m) =>
Table m h -> m ()
Internal.close Table m h
t

{-------------------------------------------------------------------------------
  Table queries
-------------------------------------------------------------------------------}

-- | Result of a single point lookup.
data LookupResult v b =
    NotFound
  | Found         !v
  | FoundWithBlob !v !b
  deriving stock (LookupResult v b -> LookupResult v b -> Bool
(LookupResult v b -> LookupResult v b -> Bool)
-> (LookupResult v b -> LookupResult v b -> Bool)
-> Eq (LookupResult v b)
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
forall v b.
(Eq v, Eq b) =>
LookupResult v b -> LookupResult v b -> Bool
$c== :: forall v b.
(Eq v, Eq b) =>
LookupResult v b -> LookupResult v b -> Bool
== :: LookupResult v b -> LookupResult v b -> Bool
$c/= :: forall v b.
(Eq v, Eq b) =>
LookupResult v b -> LookupResult v b -> Bool
/= :: LookupResult v b -> LookupResult v b -> Bool
Eq, Int -> LookupResult v b -> ShowS
[LookupResult v b] -> ShowS
LookupResult v b -> String
(Int -> LookupResult v b -> ShowS)
-> (LookupResult v b -> String)
-> ([LookupResult v b] -> ShowS)
-> Show (LookupResult v b)
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
forall v b. (Show v, Show b) => Int -> LookupResult v b -> ShowS
forall v b. (Show v, Show b) => [LookupResult v b] -> ShowS
forall v b. (Show v, Show b) => LookupResult v b -> String
$cshowsPrec :: forall v b. (Show v, Show b) => Int -> LookupResult v b -> ShowS
showsPrec :: Int -> LookupResult v b -> ShowS
$cshow :: forall v b. (Show v, Show b) => LookupResult v b -> String
show :: LookupResult v b -> String
$cshowList :: forall v b. (Show v, Show b) => [LookupResult v b] -> ShowS
showList :: [LookupResult v b] -> ShowS
Show, (forall a b. (a -> b) -> LookupResult v a -> LookupResult v b)
-> (forall a b. a -> LookupResult v b -> LookupResult v a)
-> Functor (LookupResult v)
forall a b. a -> LookupResult v b -> LookupResult v a
forall a b. (a -> b) -> LookupResult v a -> LookupResult v b
forall v a b. a -> LookupResult v b -> LookupResult v a
forall v a b. (a -> b) -> LookupResult v a -> LookupResult v b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
$cfmap :: forall v a b. (a -> b) -> LookupResult v a -> LookupResult v b
fmap :: forall a b. (a -> b) -> LookupResult v a -> LookupResult v b
$c<$ :: forall v a b. a -> LookupResult v b -> LookupResult v a
<$ :: forall a b. a -> LookupResult v b -> LookupResult v a
Functor, (forall m. Monoid m => LookupResult v m -> m)
-> (forall m a. Monoid m => (a -> m) -> LookupResult v a -> m)
-> (forall m a. Monoid m => (a -> m) -> LookupResult v a -> m)
-> (forall a b. (a -> b -> b) -> b -> LookupResult v a -> b)
-> (forall a b. (a -> b -> b) -> b -> LookupResult v a -> b)
-> (forall b a. (b -> a -> b) -> b -> LookupResult v a -> b)
-> (forall b a. (b -> a -> b) -> b -> LookupResult v a -> b)
-> (forall a. (a -> a -> a) -> LookupResult v a -> a)
-> (forall a. (a -> a -> a) -> LookupResult v a -> a)
-> (forall a. LookupResult v a -> [a])
-> (forall a. LookupResult v a -> Bool)
-> (forall a. LookupResult v a -> Int)
-> (forall a. Eq a => a -> LookupResult v a -> Bool)
-> (forall a. Ord a => LookupResult v a -> a)
-> (forall a. Ord a => LookupResult v a -> a)
-> (forall a. Num a => LookupResult v a -> a)
-> (forall a. Num a => LookupResult v a -> a)
-> Foldable (LookupResult v)
forall a. Eq a => a -> LookupResult v a -> Bool
forall a. Num a => LookupResult v a -> a
forall a. Ord a => LookupResult v a -> a
forall m. Monoid m => LookupResult v m -> m
forall a. LookupResult v a -> Bool
forall a. LookupResult v a -> Int
forall a. LookupResult v a -> [a]
forall a. (a -> a -> a) -> LookupResult v a -> a
forall v a. Eq a => a -> LookupResult v a -> Bool
forall v a. Num a => LookupResult v a -> a
forall v a. Ord a => LookupResult v a -> a
forall m a. Monoid m => (a -> m) -> LookupResult v a -> m
forall v m. Monoid m => LookupResult v m -> m
forall v a. LookupResult v a -> Bool
forall v a. LookupResult v a -> Int
forall v a. LookupResult v a -> [a]
forall b a. (b -> a -> b) -> b -> LookupResult v a -> b
forall a b. (a -> b -> b) -> b -> LookupResult v a -> b
forall v a. (a -> a -> a) -> LookupResult v a -> a
forall v m a. Monoid m => (a -> m) -> LookupResult v a -> m
forall v b a. (b -> a -> b) -> b -> LookupResult v a -> b
forall v a b. (a -> b -> b) -> b -> LookupResult v a -> b
forall (t :: * -> *).
(forall m. Monoid m => t m -> m)
-> (forall m a. Monoid m => (a -> m) -> t a -> m)
-> (forall m a. Monoid m => (a -> m) -> t a -> m)
-> (forall a b. (a -> b -> b) -> b -> t a -> b)
-> (forall a b. (a -> b -> b) -> b -> t a -> b)
-> (forall b a. (b -> a -> b) -> b -> t a -> b)
-> (forall b a. (b -> a -> b) -> b -> t a -> b)
-> (forall a. (a -> a -> a) -> t a -> a)
-> (forall a. (a -> a -> a) -> t a -> a)
-> (forall a. t a -> [a])
-> (forall a. t a -> Bool)
-> (forall a. t a -> Int)
-> (forall a. Eq a => a -> t a -> Bool)
-> (forall a. Ord a => t a -> a)
-> (forall a. Ord a => t a -> a)
-> (forall a. Num a => t a -> a)
-> (forall a. Num a => t a -> a)
-> Foldable t
$cfold :: forall v m. Monoid m => LookupResult v m -> m
fold :: forall m. Monoid m => LookupResult v m -> m
$cfoldMap :: forall v m a. Monoid m => (a -> m) -> LookupResult v a -> m
foldMap :: forall m a. Monoid m => (a -> m) -> LookupResult v a -> m
$cfoldMap' :: forall v m a. Monoid m => (a -> m) -> LookupResult v a -> m
foldMap' :: forall m a. Monoid m => (a -> m) -> LookupResult v a -> m
$cfoldr :: forall v a b. (a -> b -> b) -> b -> LookupResult v a -> b
foldr :: forall a b. (a -> b -> b) -> b -> LookupResult v a -> b
$cfoldr' :: forall v a b. (a -> b -> b) -> b -> LookupResult v a -> b
foldr' :: forall a b. (a -> b -> b) -> b -> LookupResult v a -> b
$cfoldl :: forall v b a. (b -> a -> b) -> b -> LookupResult v a -> b
foldl :: forall b a. (b -> a -> b) -> b -> LookupResult v a -> b
$cfoldl' :: forall v b a. (b -> a -> b) -> b -> LookupResult v a -> b
foldl' :: forall b a. (b -> a -> b) -> b -> LookupResult v a -> b
$cfoldr1 :: forall v a. (a -> a -> a) -> LookupResult v a -> a
foldr1 :: forall a. (a -> a -> a) -> LookupResult v a -> a
$cfoldl1 :: forall v a. (a -> a -> a) -> LookupResult v a -> a
foldl1 :: forall a. (a -> a -> a) -> LookupResult v a -> a
$ctoList :: forall v a. LookupResult v a -> [a]
toList :: forall a. LookupResult v a -> [a]
$cnull :: forall v a. LookupResult v a -> Bool
null :: forall a. LookupResult v a -> Bool
$clength :: forall v a. LookupResult v a -> Int
length :: forall a. LookupResult v a -> Int
$celem :: forall v a. Eq a => a -> LookupResult v a -> Bool
elem :: forall a. Eq a => a -> LookupResult v a -> Bool
$cmaximum :: forall v a. Ord a => LookupResult v a -> a
maximum :: forall a. Ord a => LookupResult v a -> a
$cminimum :: forall v a. Ord a => LookupResult v a -> a
minimum :: forall a. Ord a => LookupResult v a -> a
$csum :: forall v a. Num a => LookupResult v a -> a
sum :: forall a. Num a => LookupResult v a -> a
$cproduct :: forall v a. Num a => LookupResult v a -> a
product :: forall a. Num a => LookupResult v a -> a
Foldable, Functor (LookupResult v)
Foldable (LookupResult v)
(Functor (LookupResult v), Foldable (LookupResult v)) =>
(forall (f :: * -> *) a b.
 Applicative f =>
 (a -> f b) -> LookupResult v a -> f (LookupResult v b))
-> (forall (f :: * -> *) a.
    Applicative f =>
    LookupResult v (f a) -> f (LookupResult v a))
-> (forall (m :: * -> *) a b.
    Monad m =>
    (a -> m b) -> LookupResult v a -> m (LookupResult v b))
-> (forall (m :: * -> *) a.
    Monad m =>
    LookupResult v (m a) -> m (LookupResult v a))
-> Traversable (LookupResult v)
forall v. Functor (LookupResult v)
forall v. Foldable (LookupResult v)
forall v (m :: * -> *) a.
Monad m =>
LookupResult v (m a) -> m (LookupResult v a)
forall v (f :: * -> *) a.
Applicative f =>
LookupResult v (f a) -> f (LookupResult v a)
forall v (m :: * -> *) a b.
Monad m =>
(a -> m b) -> LookupResult v a -> m (LookupResult v b)
forall v (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> LookupResult v a -> f (LookupResult v b)
forall (t :: * -> *).
(Functor t, Foldable t) =>
(forall (f :: * -> *) a b.
 Applicative f =>
 (a -> f b) -> t a -> f (t b))
-> (forall (f :: * -> *) a. Applicative f => t (f a) -> f (t a))
-> (forall (m :: * -> *) a b.
    Monad m =>
    (a -> m b) -> t a -> m (t b))
-> (forall (m :: * -> *) a. Monad m => t (m a) -> m (t a))
-> Traversable t
forall (m :: * -> *) a.
Monad m =>
LookupResult v (m a) -> m (LookupResult v a)
forall (f :: * -> *) a.
Applicative f =>
LookupResult v (f a) -> f (LookupResult v a)
forall (m :: * -> *) a b.
Monad m =>
(a -> m b) -> LookupResult v a -> m (LookupResult v b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> LookupResult v a -> f (LookupResult v b)
$ctraverse :: forall v (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> LookupResult v a -> f (LookupResult v b)
traverse :: forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> LookupResult v a -> f (LookupResult v b)
$csequenceA :: forall v (f :: * -> *) a.
Applicative f =>
LookupResult v (f a) -> f (LookupResult v a)
sequenceA :: forall (f :: * -> *) a.
Applicative f =>
LookupResult v (f a) -> f (LookupResult v a)
$cmapM :: forall v (m :: * -> *) a b.
Monad m =>
(a -> m b) -> LookupResult v a -> m (LookupResult v b)
mapM :: forall (m :: * -> *) a b.
Monad m =>
(a -> m b) -> LookupResult v a -> m (LookupResult v b)
$csequence :: forall v (m :: * -> *) a.
Monad m =>
LookupResult v (m a) -> m (LookupResult v a)
sequence :: forall (m :: * -> *) a.
Monad m =>
LookupResult v (m a) -> m (LookupResult v a)
Traversable)

instance Bifunctor LookupResult where
  first :: forall a b c. (a -> b) -> LookupResult a c -> LookupResult b c
first a -> b
f = \case
      LookupResult a c
NotFound          -> LookupResult b c
forall v b. LookupResult v b
NotFound
      Found a
v           -> b -> LookupResult b c
forall v b. v -> LookupResult v b
Found (a -> b
f a
v)
      FoundWithBlob a
v c
b -> b -> c -> LookupResult b c
forall v b. v -> b -> LookupResult v b
FoundWithBlob (a -> b
f a
v) c
b

  second :: forall b c a. (b -> c) -> LookupResult a b -> LookupResult a c
second b -> c
g = \case
      LookupResult a b
NotFound          -> LookupResult a c
forall v b. LookupResult v b
NotFound
      Found a
v           -> a -> LookupResult a c
forall v b. v -> LookupResult v b
Found a
v
      FoundWithBlob a
v b
b -> a -> c -> LookupResult a c
forall v b. v -> b -> LookupResult v b
FoundWithBlob a
v (b -> c
g b
b)

{-# SPECIALISE lookups ::
     (SerialiseKey k, SerialiseValue v)
  => Table IO k v b
  -> V.Vector k
  -> IO (V.Vector (LookupResult v (BlobRef IO b))) #-}
{-# INLINEABLE lookups #-}
-- | Perform a batch of lookups.
--
-- Lookups can be performed concurrently from multiple Haskell threads.
lookups ::
     ( IOLike m
     , SerialiseKey k
     , SerialiseValue v
     )
  => Table m k v b
  -> V.Vector k
  -> m (V.Vector (LookupResult v (BlobRef m b)))
lookups :: forall (m :: * -> *) k v b.
(IOLike m, SerialiseKey k, SerialiseValue v) =>
Table m k v b
-> Vector k -> m (Vector (LookupResult v (BlobRef m b)))
lookups (Internal.NormalTable Table m h
t) Vector k
ks =
    (Maybe (Entry SerialisedValue (WeakBlobRef m h))
 -> LookupResult v (BlobRef m b))
-> Vector (Maybe (Entry SerialisedValue (WeakBlobRef m h)))
-> Vector (LookupResult v (BlobRef m b))
forall a b. (a -> b) -> Vector a -> Vector b
V.map Maybe (Entry SerialisedValue (WeakBlobRef m h))
-> LookupResult v (BlobRef m b)
forall {v} {h} {m :: * -> *} {b}.
(SerialiseValue v, Typeable h) =>
Maybe (Entry SerialisedValue (WeakBlobRef m h))
-> LookupResult v (BlobRef m b)
toLookupResult (Vector (Maybe (Entry SerialisedValue (WeakBlobRef m h)))
 -> Vector (LookupResult v (BlobRef m b)))
-> m (Vector (Maybe (Entry SerialisedValue (WeakBlobRef m h))))
-> m (Vector (LookupResult v (BlobRef m b)))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>
    ResolveSerialisedValue
-> Vector SerialisedKey
-> Table m h
-> m (Vector (Maybe (Entry SerialisedValue (WeakBlobRef m h))))
forall (m :: * -> *) h.
(MonadAsync m, MonadMask m, MonadMVar m, MonadST m) =>
ResolveSerialisedValue
-> Vector SerialisedKey
-> Table m h
-> m (Vector (Maybe (Entry SerialisedValue (WeakBlobRef m h))))
Internal.lookups ResolveSerialisedValue
forall a b. a -> b -> a
const ((k -> SerialisedKey) -> Vector k -> Vector SerialisedKey
forall a b. (a -> b) -> Vector a -> Vector b
V.map k -> SerialisedKey
forall k. SerialiseKey k => k -> SerialisedKey
Internal.serialiseKey Vector k
ks) Table m h
t
  where
    toLookupResult :: Maybe (Entry SerialisedValue (WeakBlobRef m h))
-> LookupResult v (BlobRef m b)
toLookupResult (Just Entry SerialisedValue (WeakBlobRef m h)
e) = case Entry SerialisedValue (WeakBlobRef m h)
e of
      Entry.Insert SerialisedValue
v            -> v -> LookupResult v (BlobRef m b)
forall v b. v -> LookupResult v b
Found (SerialisedValue -> v
forall v. SerialiseValue v => SerialisedValue -> v
Internal.deserialiseValue SerialisedValue
v)
      Entry.InsertWithBlob SerialisedValue
v WeakBlobRef m h
br -> v -> BlobRef m b -> LookupResult v (BlobRef m b)
forall v b. v -> b -> LookupResult v b
FoundWithBlob (SerialisedValue -> v
forall v. SerialiseValue v => SerialisedValue -> v
Internal.deserialiseValue SerialisedValue
v)
                                                 (WeakBlobRef m h -> BlobRef m b
forall h (m :: * -> *) b.
Typeable h =>
WeakBlobRef m h -> BlobRef m b
BlobRef WeakBlobRef m h
br)
      Entry.Mupdate SerialisedValue
v           -> v -> LookupResult v (BlobRef m b)
forall v b. v -> LookupResult v b
Found (SerialisedValue -> v
forall v. SerialiseValue v => SerialisedValue -> v
Internal.deserialiseValue SerialisedValue
v)
      Entry SerialisedValue (WeakBlobRef m h)
Entry.Delete              -> LookupResult v (BlobRef m b)
forall v b. LookupResult v b
NotFound
    toLookupResult Maybe (Entry SerialisedValue (WeakBlobRef m h))
Nothing = LookupResult v (BlobRef m b)
forall v b. LookupResult v b
NotFound

-- | A result for one point in a cursor read or range lookup.
data QueryResult k v b =
    FoundInQuery         !k !v
  | FoundInQueryWithBlob !k !v !b
  deriving stock (QueryResult k v b -> QueryResult k v b -> Bool
(QueryResult k v b -> QueryResult k v b -> Bool)
-> (QueryResult k v b -> QueryResult k v b -> Bool)
-> Eq (QueryResult k v b)
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
forall k v b.
(Eq k, Eq v, Eq b) =>
QueryResult k v b -> QueryResult k v b -> Bool
$c== :: forall k v b.
(Eq k, Eq v, Eq b) =>
QueryResult k v b -> QueryResult k v b -> Bool
== :: QueryResult k v b -> QueryResult k v b -> Bool
$c/= :: forall k v b.
(Eq k, Eq v, Eq b) =>
QueryResult k v b -> QueryResult k v b -> Bool
/= :: QueryResult k v b -> QueryResult k v b -> Bool
Eq, Int -> QueryResult k v b -> ShowS
[QueryResult k v b] -> ShowS
QueryResult k v b -> String
(Int -> QueryResult k v b -> ShowS)
-> (QueryResult k v b -> String)
-> ([QueryResult k v b] -> ShowS)
-> Show (QueryResult k v b)
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
forall k v b.
(Show k, Show v, Show b) =>
Int -> QueryResult k v b -> ShowS
forall k v b.
(Show k, Show v, Show b) =>
[QueryResult k v b] -> ShowS
forall k v b.
(Show k, Show v, Show b) =>
QueryResult k v b -> String
$cshowsPrec :: forall k v b.
(Show k, Show v, Show b) =>
Int -> QueryResult k v b -> ShowS
showsPrec :: Int -> QueryResult k v b -> ShowS
$cshow :: forall k v b.
(Show k, Show v, Show b) =>
QueryResult k v b -> String
show :: QueryResult k v b -> String
$cshowList :: forall k v b.
(Show k, Show v, Show b) =>
[QueryResult k v b] -> ShowS
showList :: [QueryResult k v b] -> ShowS
Show, (forall a b. (a -> b) -> QueryResult k v a -> QueryResult k v b)
-> (forall a b. a -> QueryResult k v b -> QueryResult k v a)
-> Functor (QueryResult k v)
forall a b. a -> QueryResult k v b -> QueryResult k v a
forall a b. (a -> b) -> QueryResult k v a -> QueryResult k v b
forall k v a b. a -> QueryResult k v b -> QueryResult k v a
forall k v a b. (a -> b) -> QueryResult k v a -> QueryResult k v b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
$cfmap :: forall k v a b. (a -> b) -> QueryResult k v a -> QueryResult k v b
fmap :: forall a b. (a -> b) -> QueryResult k v a -> QueryResult k v b
$c<$ :: forall k v a b. a -> QueryResult k v b -> QueryResult k v a
<$ :: forall a b. a -> QueryResult k v b -> QueryResult k v a
Functor, (forall m. Monoid m => QueryResult k v m -> m)
-> (forall m a. Monoid m => (a -> m) -> QueryResult k v a -> m)
-> (forall m a. Monoid m => (a -> m) -> QueryResult k v a -> m)
-> (forall a b. (a -> b -> b) -> b -> QueryResult k v a -> b)
-> (forall a b. (a -> b -> b) -> b -> QueryResult k v a -> b)
-> (forall b a. (b -> a -> b) -> b -> QueryResult k v a -> b)
-> (forall b a. (b -> a -> b) -> b -> QueryResult k v a -> b)
-> (forall a. (a -> a -> a) -> QueryResult k v a -> a)
-> (forall a. (a -> a -> a) -> QueryResult k v a -> a)
-> (forall a. QueryResult k v a -> [a])
-> (forall a. QueryResult k v a -> Bool)
-> (forall a. QueryResult k v a -> Int)
-> (forall a. Eq a => a -> QueryResult k v a -> Bool)
-> (forall a. Ord a => QueryResult k v a -> a)
-> (forall a. Ord a => QueryResult k v a -> a)
-> (forall a. Num a => QueryResult k v a -> a)
-> (forall a. Num a => QueryResult k v a -> a)
-> Foldable (QueryResult k v)
forall a. Eq a => a -> QueryResult k v a -> Bool
forall a. Num a => QueryResult k v a -> a
forall a. Ord a => QueryResult k v a -> a
forall m. Monoid m => QueryResult k v m -> m
forall a. QueryResult k v a -> Bool
forall a. QueryResult k v a -> Int
forall a. QueryResult k v a -> [a]
forall a. (a -> a -> a) -> QueryResult k v a -> a
forall m a. Monoid m => (a -> m) -> QueryResult k v a -> m
forall b a. (b -> a -> b) -> b -> QueryResult k v a -> b
forall a b. (a -> b -> b) -> b -> QueryResult k v a -> b
forall k v a. Eq a => a -> QueryResult k v a -> Bool
forall k v a. Num a => QueryResult k v a -> a
forall k v a. Ord a => QueryResult k v a -> a
forall k v m. Monoid m => QueryResult k v m -> m
forall k v a. QueryResult k v a -> Bool
forall k v a. QueryResult k v a -> Int
forall k v a. QueryResult k v a -> [a]
forall k v a. (a -> a -> a) -> QueryResult k v a -> a
forall k v m a. Monoid m => (a -> m) -> QueryResult k v a -> m
forall k v b a. (b -> a -> b) -> b -> QueryResult k v a -> b
forall k v a b. (a -> b -> b) -> b -> QueryResult k v a -> b
forall (t :: * -> *).
(forall m. Monoid m => t m -> m)
-> (forall m a. Monoid m => (a -> m) -> t a -> m)
-> (forall m a. Monoid m => (a -> m) -> t a -> m)
-> (forall a b. (a -> b -> b) -> b -> t a -> b)
-> (forall a b. (a -> b -> b) -> b -> t a -> b)
-> (forall b a. (b -> a -> b) -> b -> t a -> b)
-> (forall b a. (b -> a -> b) -> b -> t a -> b)
-> (forall a. (a -> a -> a) -> t a -> a)
-> (forall a. (a -> a -> a) -> t a -> a)
-> (forall a. t a -> [a])
-> (forall a. t a -> Bool)
-> (forall a. t a -> Int)
-> (forall a. Eq a => a -> t a -> Bool)
-> (forall a. Ord a => t a -> a)
-> (forall a. Ord a => t a -> a)
-> (forall a. Num a => t a -> a)
-> (forall a. Num a => t a -> a)
-> Foldable t
$cfold :: forall k v m. Monoid m => QueryResult k v m -> m
fold :: forall m. Monoid m => QueryResult k v m -> m
$cfoldMap :: forall k v m a. Monoid m => (a -> m) -> QueryResult k v a -> m
foldMap :: forall m a. Monoid m => (a -> m) -> QueryResult k v a -> m
$cfoldMap' :: forall k v m a. Monoid m => (a -> m) -> QueryResult k v a -> m
foldMap' :: forall m a. Monoid m => (a -> m) -> QueryResult k v a -> m
$cfoldr :: forall k v a b. (a -> b -> b) -> b -> QueryResult k v a -> b
foldr :: forall a b. (a -> b -> b) -> b -> QueryResult k v a -> b
$cfoldr' :: forall k v a b. (a -> b -> b) -> b -> QueryResult k v a -> b
foldr' :: forall a b. (a -> b -> b) -> b -> QueryResult k v a -> b
$cfoldl :: forall k v b a. (b -> a -> b) -> b -> QueryResult k v a -> b
foldl :: forall b a. (b -> a -> b) -> b -> QueryResult k v a -> b
$cfoldl' :: forall k v b a. (b -> a -> b) -> b -> QueryResult k v a -> b
foldl' :: forall b a. (b -> a -> b) -> b -> QueryResult k v a -> b
$cfoldr1 :: forall k v a. (a -> a -> a) -> QueryResult k v a -> a
foldr1 :: forall a. (a -> a -> a) -> QueryResult k v a -> a
$cfoldl1 :: forall k v a. (a -> a -> a) -> QueryResult k v a -> a
foldl1 :: forall a. (a -> a -> a) -> QueryResult k v a -> a
$ctoList :: forall k v a. QueryResult k v a -> [a]
toList :: forall a. QueryResult k v a -> [a]
$cnull :: forall k v a. QueryResult k v a -> Bool
null :: forall a. QueryResult k v a -> Bool
$clength :: forall k v a. QueryResult k v a -> Int
length :: forall a. QueryResult k v a -> Int
$celem :: forall k v a. Eq a => a -> QueryResult k v a -> Bool
elem :: forall a. Eq a => a -> QueryResult k v a -> Bool
$cmaximum :: forall k v a. Ord a => QueryResult k v a -> a
maximum :: forall a. Ord a => QueryResult k v a -> a
$cminimum :: forall k v a. Ord a => QueryResult k v a -> a
minimum :: forall a. Ord a => QueryResult k v a -> a
$csum :: forall k v a. Num a => QueryResult k v a -> a
sum :: forall a. Num a => QueryResult k v a -> a
$cproduct :: forall k v a. Num a => QueryResult k v a -> a
product :: forall a. Num a => QueryResult k v a -> a
Foldable, Functor (QueryResult k v)
Foldable (QueryResult k v)
(Functor (QueryResult k v), Foldable (QueryResult k v)) =>
(forall (f :: * -> *) a b.
 Applicative f =>
 (a -> f b) -> QueryResult k v a -> f (QueryResult k v b))
-> (forall (f :: * -> *) a.
    Applicative f =>
    QueryResult k v (f a) -> f (QueryResult k v a))
-> (forall (m :: * -> *) a b.
    Monad m =>
    (a -> m b) -> QueryResult k v a -> m (QueryResult k v b))
-> (forall (m :: * -> *) a.
    Monad m =>
    QueryResult k v (m a) -> m (QueryResult k v a))
-> Traversable (QueryResult k v)
forall k v. Functor (QueryResult k v)
forall k v. Foldable (QueryResult k v)
forall k v (m :: * -> *) a.
Monad m =>
QueryResult k v (m a) -> m (QueryResult k v a)
forall k v (f :: * -> *) a.
Applicative f =>
QueryResult k v (f a) -> f (QueryResult k v a)
forall k v (m :: * -> *) a b.
Monad m =>
(a -> m b) -> QueryResult k v a -> m (QueryResult k v b)
forall k v (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> QueryResult k v a -> f (QueryResult k v b)
forall (t :: * -> *).
(Functor t, Foldable t) =>
(forall (f :: * -> *) a b.
 Applicative f =>
 (a -> f b) -> t a -> f (t b))
-> (forall (f :: * -> *) a. Applicative f => t (f a) -> f (t a))
-> (forall (m :: * -> *) a b.
    Monad m =>
    (a -> m b) -> t a -> m (t b))
-> (forall (m :: * -> *) a. Monad m => t (m a) -> m (t a))
-> Traversable t
forall (m :: * -> *) a.
Monad m =>
QueryResult k v (m a) -> m (QueryResult k v a)
forall (f :: * -> *) a.
Applicative f =>
QueryResult k v (f a) -> f (QueryResult k v a)
forall (m :: * -> *) a b.
Monad m =>
(a -> m b) -> QueryResult k v a -> m (QueryResult k v b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> QueryResult k v a -> f (QueryResult k v b)
$ctraverse :: forall k v (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> QueryResult k v a -> f (QueryResult k v b)
traverse :: forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> QueryResult k v a -> f (QueryResult k v b)
$csequenceA :: forall k v (f :: * -> *) a.
Applicative f =>
QueryResult k v (f a) -> f (QueryResult k v a)
sequenceA :: forall (f :: * -> *) a.
Applicative f =>
QueryResult k v (f a) -> f (QueryResult k v a)
$cmapM :: forall k v (m :: * -> *) a b.
Monad m =>
(a -> m b) -> QueryResult k v a -> m (QueryResult k v b)
mapM :: forall (m :: * -> *) a b.
Monad m =>
(a -> m b) -> QueryResult k v a -> m (QueryResult k v b)
$csequence :: forall k v (m :: * -> *) a.
Monad m =>
QueryResult k v (m a) -> m (QueryResult k v a)
sequence :: forall (m :: * -> *) a.
Monad m =>
QueryResult k v (m a) -> m (QueryResult k v a)
Traversable)

instance Bifunctor (QueryResult k) where
  bimap :: forall a b c d.
(a -> b) -> (c -> d) -> QueryResult k a c -> QueryResult k b d
bimap a -> b
f c -> d
g = \case
      FoundInQuery k
k a
v           -> k -> b -> QueryResult k b d
forall k v b. k -> v -> QueryResult k v b
FoundInQuery k
k (a -> b
f a
v)
      FoundInQueryWithBlob k
k a
v c
b -> k -> b -> d -> QueryResult k b d
forall k v b. k -> v -> b -> QueryResult k v b
FoundInQueryWithBlob k
k (a -> b
f a
v) (c -> d
g c
b)

{-# SPECIALISE rangeLookup ::
     (SerialiseKey k, SerialiseValue v)
  => Table IO k v b
  -> Range k
  -> IO (V.Vector (QueryResult k v (BlobRef IO b))) #-}
-- | Perform a range lookup.
--
-- Range lookups can be performed concurrently from multiple Haskell threads.
rangeLookup ::
     ( IOLike m
     , SerialiseKey k
     , SerialiseValue v
     )
  => Table m k v b
  -> Range k
  -> m (V.Vector (QueryResult k v (BlobRef m b)))
rangeLookup :: forall (m :: * -> *) k v b.
(IOLike m, SerialiseKey k, SerialiseValue v) =>
Table m k v b
-> Range k -> m (Vector (QueryResult k v (BlobRef m b)))
rangeLookup (Internal.NormalTable Table m h
t) Range k
range =
    ResolveSerialisedValue
-> Range SerialisedKey
-> Table m h
-> (SerialisedKey
    -> SerialisedValue
    -> Maybe (WeakBlobRef m h)
    -> QueryResult k v (BlobRef m b))
-> m (Vector (QueryResult k v (BlobRef m b)))
forall (m :: * -> *) h res.
(MonadMask m, MonadMVar m, MonadST m, MonadSTM m) =>
ResolveSerialisedValue
-> Range SerialisedKey
-> Table m h
-> (SerialisedKey
    -> SerialisedValue -> Maybe (WeakBlobRef m h) -> res)
-> m (Vector res)
Internal.rangeLookup ResolveSerialisedValue
forall a b. a -> b -> a
const (k -> SerialisedKey
forall k. SerialiseKey k => k -> SerialisedKey
Internal.serialiseKey (k -> SerialisedKey) -> Range k -> Range SerialisedKey
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Range k
range) Table m h
t ((SerialisedKey
  -> SerialisedValue
  -> Maybe (WeakBlobRef m h)
  -> QueryResult k v (BlobRef m b))
 -> m (Vector (QueryResult k v (BlobRef m b))))
-> (SerialisedKey
    -> SerialisedValue
    -> Maybe (WeakBlobRef m h)
    -> QueryResult k v (BlobRef m b))
-> m (Vector (QueryResult k v (BlobRef m b)))
forall a b. (a -> b) -> a -> b
$ \SerialisedKey
k SerialisedValue
v Maybe (WeakBlobRef m h)
mblob ->
      k -> v -> Maybe (BlobRef m b) -> QueryResult k v (BlobRef m b)
forall k v b. k -> v -> Maybe b -> QueryResult k v b
toNormalQueryResult
        (SerialisedKey -> k
forall k. SerialiseKey k => SerialisedKey -> k
Internal.deserialiseKey SerialisedKey
k)
        (SerialisedValue -> v
forall v. SerialiseValue v => SerialisedValue -> v
Internal.deserialiseValue SerialisedValue
v)
        (WeakBlobRef m h -> BlobRef m b
forall h (m :: * -> *) b.
Typeable h =>
WeakBlobRef m h -> BlobRef m b
BlobRef (WeakBlobRef m h -> BlobRef m b)
-> Maybe (WeakBlobRef m h) -> Maybe (BlobRef m b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe (WeakBlobRef m h)
mblob)

{-------------------------------------------------------------------------------
  Cursor
-------------------------------------------------------------------------------}

-- | A read-only view into a table.
--
-- A cursor allows reading from a table sequentially (according to serialised
-- key ordering) in an incremental fashion. For example, this allows doing a
-- table scan in small chunks.
--
-- Once a cursor has been created, updates to the referenced table don't affect
-- the cursor.
type Cursor :: (Type -> Type) -> Type -> Type -> Type -> Type
type Cursor = Internal.NormalCursor

{-# SPECIALISE withCursor ::
     Table IO k v b
  -> (Cursor IO k v b -> IO a)
  -> IO a #-}
-- | (Asynchronous) exception-safe, bracketed opening and closing of a cursor.
--
-- If possible, it is recommended to use this function instead of 'newCursor'
-- and 'closeCursor'.
withCursor ::
     IOLike m
  => Table m k v b
  -> (Cursor m k v b -> m a)
  -> m a
withCursor :: forall (m :: * -> *) k v b a.
IOLike m =>
Table m k v b -> (Cursor m k v b -> m a) -> m a
withCursor (Internal.NormalTable Table m h
t) Cursor m k v b -> m a
action =
    OffsetKey -> Table m h -> (Cursor m h -> m a) -> m a
forall (m :: * -> *) h a.
(MonadMask m, MonadMVar m, MonadST m, MonadSTM m) =>
OffsetKey -> Table m h -> (Cursor m h -> m a) -> m a
Internal.withCursor OffsetKey
Internal.NoOffsetKey Table m h
t (Cursor m k v b -> m a
action (Cursor m k v b -> m a)
-> (Cursor m h -> Cursor m k v b) -> Cursor m h -> m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Cursor m h -> Cursor m k v b
forall (m :: * -> *) k v b h.
Typeable h =>
Cursor m h -> NormalCursor m k v b
Internal.NormalCursor)

{-# SPECIALISE withCursorAtOffset ::
     SerialiseKey k
  => k
  -> Table IO k v b
  -> (Cursor IO k v b -> IO a)
  -> IO a #-}
-- | A variant of 'withCursor' that allows initialising the cursor at an offset
-- within the table such that the first entry the cursor returns will be the
-- one with the lowest key that is greater than or equal to the given key.
-- In other words, it uses an inclusive lower bound.
--
-- NOTE: The ordering of the serialised keys will be used, which can lead to
-- unexpected results if the 'SerialiseKey' instance is not order-preserving!
withCursorAtOffset ::
     ( IOLike m
     , SerialiseKey k
     )
  => k
  -> Table m k v b
  -> (Cursor m k v b -> m a)
  -> m a
withCursorAtOffset :: forall (m :: * -> *) k v b a.
(IOLike m, SerialiseKey k) =>
k -> Table m k v b -> (Cursor m k v b -> m a) -> m a
withCursorAtOffset k
offset (Internal.NormalTable Table m h
t) Cursor m k v b -> m a
action =
    OffsetKey -> Table m h -> (Cursor m h -> m a) -> m a
forall (m :: * -> *) h a.
(MonadMask m, MonadMVar m, MonadST m, MonadSTM m) =>
OffsetKey -> Table m h -> (Cursor m h -> m a) -> m a
Internal.withCursor (SerialisedKey -> OffsetKey
Internal.OffsetKey (k -> SerialisedKey
forall k. SerialiseKey k => k -> SerialisedKey
Internal.serialiseKey k
offset)) Table m h
t ((Cursor m h -> m a) -> m a) -> (Cursor m h -> m a) -> m a
forall a b. (a -> b) -> a -> b
$
      Cursor m k v b -> m a
action (Cursor m k v b -> m a)
-> (Cursor m h -> Cursor m k v b) -> Cursor m h -> m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Cursor m h -> Cursor m k v b
forall (m :: * -> *) k v b h.
Typeable h =>
Cursor m h -> NormalCursor m k v b
Internal.NormalCursor

{-# SPECIALISE newCursor ::
     Table IO k v b
  -> IO (Cursor IO k v b) #-}
-- | Create a new cursor to read from a given table. Future updates to the table
-- will not be reflected in the cursor. The cursor starts at the beginning, i.e.
-- the minimum key of the table.
--
-- Consider using 'withCursor' instead.
--
-- NOTE: cursors hold open resources (such as open files) and should be closed
-- using 'close' as soon as they are no longer used.
newCursor ::
     IOLike m
  => Table m k v b
  -> m (Cursor m k v b)
newCursor :: forall (m :: * -> *) k v b.
IOLike m =>
Table m k v b -> m (Cursor m k v b)
newCursor (Internal.NormalTable Table m h
t) =
    Cursor m h -> NormalCursor m k v b
forall (m :: * -> *) k v b h.
Typeable h =>
Cursor m h -> NormalCursor m k v b
Internal.NormalCursor (Cursor m h -> NormalCursor m k v b)
-> m (Cursor m h) -> m (NormalCursor m k v b)
forall (m :: * -> *) a b. Monad m => (a -> b) -> m a -> m b
<$!> OffsetKey -> Table m h -> m (Cursor m h)
forall (m :: * -> *) h.
(MonadMask m, MonadMVar m, MonadST m, MonadSTM m) =>
OffsetKey -> Table m h -> m (Cursor m h)
Internal.newCursor OffsetKey
Internal.NoOffsetKey Table m h
t

{-# SPECIALISE newCursorAtOffset ::
     SerialiseKey k
  => k
  -> Table IO k v b
  -> IO (Cursor IO k v b) #-}
-- | A variant of 'newCursor' that allows initialising the cursor at an offset
-- within the table such that the first entry the cursor returns will be the
-- one with the lowest key that is greater than or equal to the given key.
-- In other words, it uses an inclusive lower bound.
--
-- NOTE: The ordering of the serialised keys will be used, which can lead to
-- unexpected results if the 'SerialiseKey' instance is not order-preserving!
newCursorAtOffset ::
     ( IOLike m
     , SerialiseKey k
     )
  => k
  -> Table m k v b
  -> m (Cursor m k v b)
newCursorAtOffset :: forall (m :: * -> *) k v b.
(IOLike m, SerialiseKey k) =>
k -> Table m k v b -> m (Cursor m k v b)
newCursorAtOffset k
offset (Internal.NormalTable Table m h
t) =
    Cursor m h -> NormalCursor m k v b
forall (m :: * -> *) k v b h.
Typeable h =>
Cursor m h -> NormalCursor m k v b
Internal.NormalCursor (Cursor m h -> NormalCursor m k v b)
-> m (Cursor m h) -> m (NormalCursor m k v b)
forall (m :: * -> *) a b. Monad m => (a -> b) -> m a -> m b
<$!>
      OffsetKey -> Table m h -> m (Cursor m h)
forall (m :: * -> *) h.
(MonadMask m, MonadMVar m, MonadST m, MonadSTM m) =>
OffsetKey -> Table m h -> m (Cursor m h)
Internal.newCursor (SerialisedKey -> OffsetKey
Internal.OffsetKey (k -> SerialisedKey
forall k. SerialiseKey k => k -> SerialisedKey
Internal.serialiseKey k
offset)) Table m h
t

{-# SPECIALISE closeCursor ::
     Cursor IO k v b
  -> IO () #-}
-- | Close a cursor. 'closeCursor' is idempotent. All operations on a closed
-- cursor will throw an exception.
closeCursor ::
     IOLike m
  => Cursor m k v b
  -> m ()
closeCursor :: forall (m :: * -> *) k v b. IOLike m => Cursor m k v b -> m ()
closeCursor (Internal.NormalCursor Cursor m h
c) = Cursor m h -> m ()
forall (m :: * -> *) h.
(MonadMask m, MonadMVar m, MonadSTM m, PrimMonad m) =>
Cursor m h -> m ()
Internal.closeCursor Cursor m h
c

{-# SPECIALISE readCursor ::
     (SerialiseKey k, SerialiseValue v)
  => Int
  -> Cursor IO k v b
  -> IO (V.Vector (QueryResult k v (BlobRef IO b))) #-}
-- | Read the next @n@ entries from the cursor. The resulting vector is shorter
-- than @n@ if the end of the table has been reached. The cursor state is
-- updated, so the next read will continue where this one ended.
--
-- The cursor gets locked for the duration of the call, preventing concurrent
-- reads.
--
-- NOTE: entries are returned in order of the serialised keys, which might not
-- agree with @Ord k@. See 'SerialiseKey' for more information.
readCursor ::
     ( IOLike m
     , SerialiseKey k
     , SerialiseValue v
     )
  => Int
  -> Cursor m k v b
  -> m (V.Vector (QueryResult k v (BlobRef m b)))
readCursor :: forall (m :: * -> *) k v b.
(IOLike m, SerialiseKey k, SerialiseValue v) =>
Int -> Cursor m k v b -> m (Vector (QueryResult k v (BlobRef m b)))
readCursor Int
n (Internal.NormalCursor Cursor m h
c) =
    ResolveSerialisedValue
-> Int
-> Cursor m h
-> (SerialisedKey
    -> SerialisedValue
    -> Maybe (WeakBlobRef m h)
    -> QueryResult k v (BlobRef m b))
-> m (Vector (QueryResult k v (BlobRef m b)))
forall (m :: * -> *) h res.
(MonadMask m, MonadMVar m, MonadST m, MonadSTM m) =>
ResolveSerialisedValue
-> Int
-> Cursor m h
-> (SerialisedKey
    -> SerialisedValue -> Maybe (WeakBlobRef m h) -> res)
-> m (Vector res)
Internal.readCursor ResolveSerialisedValue
forall a b. a -> b -> a
const Int
n Cursor m h
c ((SerialisedKey
  -> SerialisedValue
  -> Maybe (WeakBlobRef m h)
  -> QueryResult k v (BlobRef m b))
 -> m (Vector (QueryResult k v (BlobRef m b))))
-> (SerialisedKey
    -> SerialisedValue
    -> Maybe (WeakBlobRef m h)
    -> QueryResult k v (BlobRef m b))
-> m (Vector (QueryResult k v (BlobRef m b)))
forall a b. (a -> b) -> a -> b
$ \SerialisedKey
k SerialisedValue
v Maybe (WeakBlobRef m h)
mblob ->
      k -> v -> Maybe (BlobRef m b) -> QueryResult k v (BlobRef m b)
forall k v b. k -> v -> Maybe b -> QueryResult k v b
toNormalQueryResult
        (SerialisedKey -> k
forall k. SerialiseKey k => SerialisedKey -> k
Internal.deserialiseKey SerialisedKey
k)
        (SerialisedValue -> v
forall v. SerialiseValue v => SerialisedValue -> v
Internal.deserialiseValue SerialisedValue
v)
        (WeakBlobRef m h -> BlobRef m b
forall h (m :: * -> *) b.
Typeable h =>
WeakBlobRef m h -> BlobRef m b
BlobRef (WeakBlobRef m h -> BlobRef m b)
-> Maybe (WeakBlobRef m h) -> Maybe (BlobRef m b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe (WeakBlobRef m h)
mblob)

toNormalQueryResult :: k -> v -> Maybe b -> QueryResult k v b
toNormalQueryResult :: forall k v b. k -> v -> Maybe b -> QueryResult k v b
toNormalQueryResult k
k v
v = \case
    Maybe b
Nothing    -> k -> v -> QueryResult k v b
forall k v b. k -> v -> QueryResult k v b
FoundInQuery k
k v
v
    Just b
blob  -> k -> v -> b -> QueryResult k v b
forall k v b. k -> v -> b -> QueryResult k v b
FoundInQueryWithBlob k
k v
v b
blob

{-------------------------------------------------------------------------------
  Table updates
-------------------------------------------------------------------------------}

-- | Normal tables support insert and delete operations.
--
-- An __update__ is a term that groups all types of table-manipulating
-- operations, like inserts and deletes.
data Update v b =
    Insert !v !(Maybe b)
  | Delete
  deriving stock (Int -> Update v b -> ShowS
[Update v b] -> ShowS
Update v b -> String
(Int -> Update v b -> ShowS)
-> (Update v b -> String)
-> ([Update v b] -> ShowS)
-> Show (Update v b)
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
forall v b. (Show v, Show b) => Int -> Update v b -> ShowS
forall v b. (Show v, Show b) => [Update v b] -> ShowS
forall v b. (Show v, Show b) => Update v b -> String
$cshowsPrec :: forall v b. (Show v, Show b) => Int -> Update v b -> ShowS
showsPrec :: Int -> Update v b -> ShowS
$cshow :: forall v b. (Show v, Show b) => Update v b -> String
show :: Update v b -> String
$cshowList :: forall v b. (Show v, Show b) => [Update v b] -> ShowS
showList :: [Update v b] -> ShowS
Show, Update v b -> Update v b -> Bool
(Update v b -> Update v b -> Bool)
-> (Update v b -> Update v b -> Bool) -> Eq (Update v b)
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
forall v b. (Eq v, Eq b) => Update v b -> Update v b -> Bool
$c== :: forall v b. (Eq v, Eq b) => Update v b -> Update v b -> Bool
== :: Update v b -> Update v b -> Bool
$c/= :: forall v b. (Eq v, Eq b) => Update v b -> Update v b -> Bool
/= :: Update v b -> Update v b -> Bool
Eq)

instance (NFData v, NFData b) => NFData (Update v b) where
  rnf :: Update v b -> ()
rnf Update v b
Delete       = ()
  rnf (Insert v
v Maybe b
b) = v -> ()
forall a. NFData a => a -> ()
rnf v
v () -> () -> ()
forall a b. a -> b -> b
`seq` Maybe b -> ()
forall a. NFData a => a -> ()
rnf Maybe b
b

{-# SPECIALISE updates ::
     (SerialiseKey k, SerialiseValue v, SerialiseValue b)
  => Table IO k v b
  -> V.Vector (k, Update v b)
  -> IO () #-}
-- | Perform a mixed batch of inserts and deletes.
--
-- If there are duplicate keys in the same batch, then keys nearer to the front
-- of the vector take precedence.
--
-- Updates can be performed concurrently from multiple Haskell threads.
updates ::
     ( IOLike m
     , SerialiseKey k
     , SerialiseValue v
     , SerialiseValue b
     )
  => Table m k v b
  -> V.Vector (k, Update v b)
  -> m ()
updates :: forall (m :: * -> *) k v b.
(IOLike m, SerialiseKey k, SerialiseValue v, SerialiseValue b) =>
Table m k v b -> Vector (k, Update v b) -> m ()
updates (Internal.NormalTable Table m h
t) Vector (k, Update v b)
es = do
    ResolveSerialisedValue
-> Vector (SerialisedKey, Entry SerialisedValue SerialisedBlob)
-> Table m h
-> m ()
forall (m :: * -> *) h.
(MonadMask m, MonadMVar m, MonadST m, MonadSTM m) =>
ResolveSerialisedValue
-> Vector (SerialisedKey, Entry SerialisedValue SerialisedBlob)
-> Table m h
-> m ()
Internal.updates ResolveSerialisedValue
forall a b. a -> b -> a
const (((k, Update v b)
 -> (SerialisedKey, Entry SerialisedValue SerialisedBlob))
-> Vector (k, Update v b)
-> Vector (SerialisedKey, Entry SerialisedValue SerialisedBlob)
forall a b. (a -> b) -> Vector a -> Vector b
V.mapStrict (k, Update v b)
-> (SerialisedKey, Entry SerialisedValue SerialisedBlob)
serialiseEntry Vector (k, Update v b)
es) Table m h
t
  where
    serialiseEntry :: (k, Update v b)
-> (SerialisedKey, Entry SerialisedValue SerialisedBlob)
serialiseEntry = (k -> SerialisedKey)
-> (Update v b -> Entry SerialisedValue SerialisedBlob)
-> (k, Update v b)
-> (SerialisedKey, Entry SerialisedValue SerialisedBlob)
forall a b c d. (a -> b) -> (c -> d) -> (a, c) -> (b, d)
forall (p :: * -> * -> *) a b c d.
Bifunctor p =>
(a -> b) -> (c -> d) -> p a c -> p b d
bimap k -> SerialisedKey
forall k. SerialiseKey k => k -> SerialisedKey
Internal.serialiseKey Update v b -> Entry SerialisedValue SerialisedBlob
serialiseOp
    serialiseOp :: Update v b -> Entry SerialisedValue SerialisedBlob
serialiseOp = (v -> SerialisedValue)
-> (b -> SerialisedBlob)
-> Entry v b
-> Entry SerialisedValue SerialisedBlob
forall a b c d. (a -> b) -> (c -> d) -> Entry a c -> Entry b d
forall (p :: * -> * -> *) a b c d.
Bifunctor p =>
(a -> b) -> (c -> d) -> p a c -> p b d
bimap v -> SerialisedValue
forall v. SerialiseValue v => v -> SerialisedValue
Internal.serialiseValue b -> SerialisedBlob
forall v. SerialiseValue v => v -> SerialisedBlob
Internal.serialiseBlob
                (Entry v b -> Entry SerialisedValue SerialisedBlob)
-> (Update v b -> Entry v b)
-> Update v b
-> Entry SerialisedValue SerialisedBlob
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Update v b -> Entry v b
forall v b. Update v b -> Entry v b
updateToEntry

    updateToEntry :: Update v b -> Entry.Entry v b
    updateToEntry :: forall v b. Update v b -> Entry v b
updateToEntry = \case
        Insert v
v Maybe b
Nothing  -> v -> Entry v b
forall v b. v -> Entry v b
Entry.Insert v
v
        Insert v
v (Just b
b) -> v -> b -> Entry v b
forall v b. v -> b -> Entry v b
Entry.InsertWithBlob v
v b
b
        Update v b
Delete            -> Entry v b
forall v b. Entry v b
Entry.Delete

{-# SPECIALISE inserts ::
     (SerialiseKey k, SerialiseValue v, SerialiseValue b)
  => Table IO k v b
  -> V.Vector (k, v, Maybe b)
  -> IO () #-}
-- | Perform a batch of inserts.
--
-- Inserts can be performed concurrently from multiple Haskell threads.
inserts ::
     ( IOLike m
     , SerialiseKey k
     , SerialiseValue v
     , SerialiseValue b
     )
  => Table m k v b
  -> V.Vector (k, v, Maybe b)
  -> m ()
inserts :: forall (m :: * -> *) k v b.
(IOLike m, SerialiseKey k, SerialiseValue v, SerialiseValue b) =>
Table m k v b -> Vector (k, v, Maybe b) -> m ()
inserts Table m k v b
t = Table m k v b -> Vector (k, Update v b) -> m ()
forall (m :: * -> *) k v b.
(IOLike m, SerialiseKey k, SerialiseValue v, SerialiseValue b) =>
Table m k v b -> Vector (k, Update v b) -> m ()
updates Table m k v b
t (Vector (k, Update v b) -> m ())
-> (Vector (k, v, Maybe b) -> Vector (k, Update v b))
-> Vector (k, v, Maybe b)
-> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((k, v, Maybe b) -> (k, Update v b))
-> Vector (k, v, Maybe b) -> Vector (k, Update v b)
forall a b. (a -> b) -> Vector a -> Vector b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\(k
k, v
v, Maybe b
blob) -> (k
k, v -> Maybe b -> Update v b
forall v b. v -> Maybe b -> Update v b
Insert v
v Maybe b
blob))

{-# SPECIALISE deletes ::
     (SerialiseKey k, SerialiseValue v, SerialiseValue b)
  => Table IO k v b
  -> V.Vector k
  -> IO () #-}
-- | Perform a batch of deletes.
--
-- Deletes can be performed concurrently from multiple Haskell threads.
deletes ::
     ( IOLike m
     , SerialiseKey k
     , SerialiseValue v
     , SerialiseValue b
     )
  => Table m k v b
  -> V.Vector k
  -> m ()
deletes :: forall (m :: * -> *) k v b.
(IOLike m, SerialiseKey k, SerialiseValue v, SerialiseValue b) =>
Table m k v b -> Vector k -> m ()
deletes Table m k v b
t = Table m k v b -> Vector (k, Update v b) -> m ()
forall (m :: * -> *) k v b.
(IOLike m, SerialiseKey k, SerialiseValue v, SerialiseValue b) =>
Table m k v b -> Vector (k, Update v b) -> m ()
updates Table m k v b
t (Vector (k, Update v b) -> m ())
-> (Vector k -> Vector (k, Update v b)) -> Vector k -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (k -> (k, Update v b)) -> Vector k -> Vector (k, Update v b)
forall a b. (a -> b) -> Vector a -> Vector b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (,Update v b
forall v b. Update v b
Delete)

{-# SPECIALISE retrieveBlobs ::
     SerialiseValue b
  => Session IO
  -> V.Vector (BlobRef IO b)
  -> IO (V.Vector b) #-}
-- | Perform a batch of blob retrievals.
--
-- This is a separate step from 'lookups' and 'rangeLookup'. The result of a
-- lookup can include a 'BlobRef', which can be used to retrieve the actual
-- 'Blob'.
--
-- Note that 'BlobRef's can become invalid if the table is modified. See
-- 'BlobRef' for the exact rules on blob reference validity.
--
-- Blob lookups can be performed concurrently from multiple Haskell threads.
retrieveBlobs ::
     ( IOLike m
     , SerialiseValue b
     )
  => Session m
  -> V.Vector (BlobRef m b)
  -> m (V.Vector b)
retrieveBlobs :: forall (m :: * -> *) b.
(IOLike m, SerialiseValue b) =>
Session m -> Vector (BlobRef m b) -> m (Vector b)
retrieveBlobs (Internal.Session' (Session m h
sesh :: Internal.Session m h)) Vector (BlobRef m b)
refs =
    (SerialisedBlob -> b) -> Vector SerialisedBlob -> Vector b
forall a b. (a -> b) -> Vector a -> Vector b
V.map SerialisedBlob -> b
forall v. SerialiseValue v => SerialisedBlob -> v
Internal.deserialiseBlob (Vector SerialisedBlob -> Vector b)
-> m (Vector SerialisedBlob) -> m (Vector b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>
      (Session m h
-> Vector (WeakBlobRef m h) -> m (Vector SerialisedBlob)
forall (m :: * -> *) h.
(MonadMask m, MonadST m, MonadSTM m) =>
Session m h
-> Vector (WeakBlobRef m h) -> m (Vector SerialisedBlob)
Internal.retrieveBlobs Session m h
sesh (Vector (WeakBlobRef m h) -> m (Vector SerialisedBlob))
-> m (Vector (WeakBlobRef m h)) -> m (Vector SerialisedBlob)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< (Int -> BlobRef m b -> m (WeakBlobRef m h))
-> Vector (BlobRef m b) -> m (Vector (WeakBlobRef m h))
forall (m :: * -> *) a b.
Monad m =>
(Int -> a -> m b) -> Vector a -> m (Vector b)
V.imapM Int -> BlobRef m b -> m (WeakBlobRef m h)
checkBlobRefType Vector (BlobRef m b)
refs)
  where
    checkBlobRefType :: Int -> BlobRef m b -> m (WeakBlobRef m h)
checkBlobRefType Int
_ (BlobRef (WeakBlobRef m h
ref :: Internal.WeakBlobRef m h'))
      | Just h :~: h
Refl <- forall {k} (a :: k) (b :: k).
(Typeable a, Typeable b) =>
Maybe (a :~: b)
forall a b. (Typeable a, Typeable b) => Maybe (a :~: b)
eqT @h @h' = WeakBlobRef m h -> m (WeakBlobRef m h)
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure WeakBlobRef m h
ref
    checkBlobRefType Int
i BlobRef m b
_ = BlobRefInvalidError -> m (WeakBlobRef m h)
forall e a. Exception e => e -> m a
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwIO (Int -> BlobRefInvalidError
Internal.ErrBlobRefInvalid Int
i)

{-------------------------------------------------------------------------------
  Snapshots
-------------------------------------------------------------------------------}

{-# SPECIALISE createSnapshot ::
     Common.SnapshotLabel
  -> Common.SnapshotName
  -> Table IO k v b
  -> IO () #-}
-- | Make the current value of a table durable on-disk by taking a snapshot and
-- giving the snapshot a name. This is the __only__ mechanism to make a table
-- durable -- ordinary insert\/delete operations are otherwise not preserved.
--
-- Snapshots have names and the table may be opened later using 'openSnapshot'
-- via that name. Names are strings and the management of the names is up to
-- the user of the library.
--
-- Snapshot labels are included in the snapshot metadata when a snapshot is
-- created. Labels are text and the management of the labels is up to the user
-- of the library. Labels assigns a dynamically checked "type" to a snapshot.
-- See 'Common.SnapshotLabel' for more information.
--
-- The names correspond to disk files, which imposes some constraints on length
-- and what characters can be used.
--
-- Snapshotting does not close the table.
--
-- Taking a snapshot is /relatively/ cheap, but it is not so cheap that one can
-- use it after every operation. In the implementation, it must at least flush
-- the write buffer to disk.
--
-- Concurrency:
--
-- * It is safe to concurrently make snapshots from any table, provided that
--   the snapshot names are distinct (otherwise this would be a race).
createSnapshot :: forall m k v b.
     IOLike m
  => Common.SnapshotLabel
  -> Common.SnapshotName
  -> Table m k v b
  -> m ()
createSnapshot :: forall (m :: * -> *) k v b.
IOLike m =>
SnapshotLabel -> SnapshotName -> Table m k v b -> m ()
createSnapshot SnapshotLabel
label SnapshotName
snap (Internal.NormalTable Table m h
t) =
    SnapshotName
-> SnapshotLabel -> SnapshotTableType -> Table m h -> m ()
forall (m :: * -> *) h.
(MonadMask m, MonadMVar m, MonadST m, MonadSTM m) =>
SnapshotName
-> SnapshotLabel -> SnapshotTableType -> Table m h -> m ()
Internal.createSnapshot SnapshotName
snap SnapshotLabel
label SnapshotTableType
Common.SnapNormalTable Table m h
t

{-# SPECIALISE openSnapshot ::
     Session IO
  -> Common.TableConfigOverride
  -> Common.SnapshotLabel
  -> Common.SnapshotName
  -> IO (Table IO k v b ) #-}
-- | Open a table from a named snapshot, returning a new table.
--
-- This function requires passing in an expected label that will be checked
-- against the label that was included in the snapshot metadata. If there is a
-- mismatch, an exception is thrown.
--
-- NOTE: close tables using 'close' as soon as they are
-- unused.
--
-- Exceptions:
--
-- * Opening a non-existent snapshot is an error.
--
-- * Opening a snapshot but expecting the wrong type of table is an error. e.g.,
--   the following will fail:
--
-- @
-- example session = do
--   t <- 'new' \@IO \@Int \@Int \@Int session _
--   'createSnapshot' "intTable" t
--   'openSnapshot' \@IO \@Bool \@Bool \@Bool session "intTable"
-- @
openSnapshot :: forall m k v b.
     IOLike m
  => Session m
  -> Common.TableConfigOverride -- ^ Optional config override
  -> Common.SnapshotLabel
  -> Common.SnapshotName
  -> m (Table m k v b)
openSnapshot :: forall (m :: * -> *) k v b.
IOLike m =>
Session m
-> TableConfigOverride
-> SnapshotLabel
-> SnapshotName
-> m (Table m k v b)
openSnapshot (Internal.Session' Session m h
sesh) TableConfigOverride
override SnapshotLabel
label SnapshotName
snap =
    Table m h -> NormalTable m k v b
forall (m :: * -> *) k v b h.
Typeable h =>
Table m h -> NormalTable m k v b
Internal.NormalTable (Table m h -> NormalTable m k v b)
-> m (Table m h) -> m (NormalTable m k v b)
forall (m :: * -> *) a b. Monad m => (a -> b) -> m a -> m b
<$!>
      Session m h
-> SnapshotLabel
-> SnapshotTableType
-> TableConfigOverride
-> SnapshotName
-> ResolveSerialisedValue
-> m (Table m h)
forall (m :: * -> *) h.
(MonadMask m, MonadMVar m, MonadST m, MonadSTM m) =>
Session m h
-> SnapshotLabel
-> SnapshotTableType
-> TableConfigOverride
-> SnapshotName
-> ResolveSerialisedValue
-> m (Table m h)
Internal.openSnapshot
        Session m h
sesh
        SnapshotLabel
label
        SnapshotTableType
Common.SnapNormalTable
        TableConfigOverride
override
        SnapshotName
snap
        ResolveSerialisedValue
forall a b. a -> b -> a
const

{-------------------------------------------------------------------------------
  Mutiple writable tables
-------------------------------------------------------------------------------}

{-# SPECIALISE duplicate ::
     Table IO k v b
  -> IO (Table IO k v b) #-}
-- | Create a logically independent duplicate of a table. This returns a
-- new table.
--
-- A table and its duplicate are logically independent: changes to one
-- are not visible to the other. However, in-memory and on-disk data are
-- shared internally.
--
-- This operation enables /fully persistent/ use of tables by duplicating the
-- table prior to a batch of mutating operations. The duplicate retains the
-- original table value, and can still be modified independently.
--
-- This is persistence in the sense of persistent data structures (not of on-disk
-- persistence). The usual definition of a persistent data structure is one in
-- which each operation preserves the previous version of the structure when
-- the structure is modified. Full persistence is if every version can be both
-- accessed and modified. This API does not directly fit the definition because
-- the update operations do mutate the table value, however full persistence
-- can be emulated by duplicating the table prior to a mutating operation.
--
-- Duplication itself is cheap. In particular it requires no disk I\/O, and
-- requires little additional memory. Just as with normal persistent data
-- structures, making use of multiple tables will have corresponding costs in
-- terms of memory and disk space. Initially the two tables will share
-- everything (both in memory and on disk) but as more and more update
-- operations are performed on each, the sharing will decrease. Ultimately the
-- memory and disk cost will be the same as if each table were entirely
-- independent.
--
-- NOTE: duplication creates a new table, which should be closed when no
-- longer needed.
duplicate ::
     IOLike m
  => Table m k v b
  -> m (Table m k v b)
duplicate :: forall (m :: * -> *) k v b.
IOLike m =>
Table m k v b -> m (Table m k v b)
duplicate (Internal.NormalTable Table m h
t) = Table m h -> NormalTable m k v b
forall (m :: * -> *) k v b h.
Typeable h =>
Table m h -> NormalTable m k v b
Internal.NormalTable (Table m h -> NormalTable m k v b)
-> m (Table m h) -> m (NormalTable m k v b)
forall (m :: * -> *) a b. Monad m => (a -> b) -> m a -> m b
<$!> Table m h -> m (Table m h)
forall (m :: * -> *) h.
(MonadMask m, MonadMVar m, MonadST m, MonadSTM m) =>
Table m h -> m (Table m h)
Internal.duplicate Table m h
t

{-------------------------------------------------------------------------------
  Table union
-------------------------------------------------------------------------------}

{-# SPECIALISE union ::
     Table IO k v b
  -> Table IO k v b
  -> IO (Table IO k v b) #-}
-- | Union two full tables, creating a new table.
--
-- A good mental model of this operation is @'Data.Map.Lazy.union'@ on
-- @'Data.Map.Lazy.Map' k v@.
--
-- Multiple tables of the same type but with different configuration parameters
-- can live in the same session. However, 'union' only works for tables that
-- have the same key\/value types and configuration parameters.
--
-- NOTE: unioning tables creates a new table, but does not close the tables that
-- were used as inputs.
union :: forall m k v b.
     IOLike m
  => Table m k v b
  -> Table m k v b
  -> m (Table m k v b)
union :: forall (m :: * -> *) k v b.
IOLike m =>
Table m k v b -> Table m k v b -> m (Table m k v b)
union Table m k v b
t1 Table m k v b
t2 = NonEmpty (Table m k v b) -> m (Table m k v b)
forall (m :: * -> *) k v b.
IOLike m =>
NonEmpty (Table m k v b) -> m (Table m k v b)
unions (NonEmpty (Table m k v b) -> m (Table m k v b))
-> NonEmpty (Table m k v b) -> m (Table m k v b)
forall a b. (a -> b) -> a -> b
$ Table m k v b
t1 Table m k v b -> [Table m k v b] -> NonEmpty (Table m k v b)
forall a. a -> [a] -> NonEmpty a
:| [Table m k v b
t2]

{-# SPECIALISE unions :: NonEmpty (Table IO k v b) -> IO (Table IO k v b) #-}
-- | Like 'union', but for @n@ tables.
--
-- A good mental model of this operation is @'Data.Map.Lazy.unions'@ on
-- @'Data.Map.Lazy.Map' k v@.
{-# SPECIALISE unions ::
     NonEmpty (Table IO k v b)
  -> IO (Table IO k v b) #-}
unions :: forall m k v b.
     IOLike m
  => NonEmpty (Table m k v b)
  -> m (Table m k v b)
unions :: forall (m :: * -> *) k v b.
IOLike m =>
NonEmpty (Table m k v b) -> m (Table m k v b)
unions (Table m k v b
t :| [Table m k v b]
ts) =
    case Table m k v b
t of
      Internal.NormalTable (Table m h
t' :: Internal.Table m h) -> do
        [Table m h]
ts' <- (Int -> Table m k v b -> m (Table m h))
-> [Int] -> [Table m k v b] -> m [Table m h]
forall (m :: * -> *) a b c.
Applicative m =>
(a -> b -> m c) -> [a] -> [b] -> m [c]
zipWithM (Proxy# h -> Int -> Table m k v b -> m (Table m h)
forall h.
Typeable h =>
Proxy# h -> Int -> Table m k v b -> m (Table m h)
checkTableType (forall a. Proxy# a
forall {k} (a :: k). Proxy# a
proxy# @h)) [Int
1..] [Table m k v b]
ts
        Table m h -> Table m k v b
forall (m :: * -> *) k v b h.
Typeable h =>
Table m h -> NormalTable m k v b
Internal.NormalTable (Table m h -> Table m k v b) -> m (Table m h) -> m (Table m k v b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> NonEmpty (Table m h) -> m (Table m h)
forall (m :: * -> *) h.
(MonadMask m, MonadMVar m, MonadST m, MonadSTM m) =>
NonEmpty (Table m h) -> m (Table m h)
Internal.unions (Table m h
t' Table m h -> [Table m h] -> NonEmpty (Table m h)
forall a. a -> [a] -> NonEmpty a
:| [Table m h]
ts')
  where
    checkTableType ::
         forall h. Typeable h
      => Proxy# h
      -> Int
      -> Table m k v b
      -> m (Internal.Table m h)
    checkTableType :: forall h.
Typeable h =>
Proxy# h -> Int -> Table m k v b -> m (Table m h)
checkTableType Proxy# h
_ Int
i (Internal.NormalTable (Table m h
t' :: Internal.Table m h'))
      | Just h :~: h
Refl <- forall {k} (a :: k) (b :: k).
(Typeable a, Typeable b) =>
Maybe (a :~: b)
forall a b. (Typeable a, Typeable b) => Maybe (a :~: b)
eqT @h @h' = Table m h -> m (Table m h)
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Table m h
Table m h
t'
      | Bool
otherwise = TableUnionNotCompatibleError -> m (Table m h)
forall e a. Exception e => e -> m a
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwIO (TableUnionNotCompatibleError -> m (Table m h))
-> TableUnionNotCompatibleError -> m (Table m h)
forall a b. (a -> b) -> a -> b
$ Int -> TypeRep -> Int -> TypeRep -> TableUnionNotCompatibleError
Common.ErrTableUnionHandleTypeMismatch Int
0 (Proxy h -> TypeRep
forall {k} (proxy :: k -> *) (a :: k).
Typeable a =>
proxy a -> TypeRep
typeRep (Proxy h -> TypeRep) -> Proxy h -> TypeRep
forall a b. (a -> b) -> a -> b
$ forall t. Proxy t
forall {k} (t :: k). Proxy t
Proxy @h) Int
i (Proxy h -> TypeRep
forall {k} (proxy :: k -> *) (a :: k).
Typeable a =>
proxy a -> TypeRep
typeRep (Proxy h -> TypeRep) -> Proxy h -> TypeRep
forall a b. (a -> b) -> a -> b
$ forall t. Proxy t
forall {k} (t :: k). Proxy t
Proxy @h')

{-# SPECIALISE remainingUnionDebt :: Table IO k v b -> IO UnionDebt #-}
-- | Return the current union debt. This debt can be reduced until it is paid
-- off using @supplyUnionCredits@.
remainingUnionDebt :: IOLike m => Table m k v b -> m UnionDebt
remainingUnionDebt :: forall (m :: * -> *) k v b.
IOLike m =>
Table m k v b -> m UnionDebt
remainingUnionDebt (Internal.NormalTable Table m h
t) =
    (\(Internal.UnionDebt Int
x) -> Int -> UnionDebt
UnionDebt Int
x) (UnionDebt -> UnionDebt) -> m UnionDebt -> m UnionDebt
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>
      Table m h -> m UnionDebt
forall (m :: * -> *) h.
(MonadSTM m, MonadMVar m, MonadThrow m, PrimMonad m) =>
Table m h -> m UnionDebt
Internal.remainingUnionDebt Table m h
t

{-# SPECIALISE supplyUnionCredits :: Table IO k v b -> UnionCredits -> IO UnionCredits #-}
-- | Supply union credits to reduce union debt.
--
-- Supplying union credits leads to union merging work being performed in
-- batches. This reduces the union debt returned by @remainingUnionDebt@. Union
-- debt will be reduced by /at least/ the number of supplied union credits. It
-- is therefore advisable to query @remainingUnionDebt@ every once in a while to
-- see what the current debt is.
--
-- This function returns any surplus of union credits as /leftover/ credits when
-- a union has finished. In particular, if the returned number of credits is
-- non-negative, then the union is finished.
supplyUnionCredits ::
     IOLike m
  => Table m k v b
  -> UnionCredits
  -> m UnionCredits
supplyUnionCredits :: forall (m :: * -> *) k v b.
IOLike m =>
Table m k v b -> UnionCredits -> m UnionCredits
supplyUnionCredits (Internal.NormalTable Table m h
t) (UnionCredits Int
credits) =
    (\(Internal.UnionCredits Int
x) -> Int -> UnionCredits
UnionCredits Int
x) (UnionCredits -> UnionCredits) -> m UnionCredits -> m UnionCredits
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>
      ResolveSerialisedValue
-> Table m h -> UnionCredits -> m UnionCredits
forall (m :: * -> *) h.
(MonadST m, MonadSTM m, MonadMVar m, MonadMask m) =>
ResolveSerialisedValue
-> Table m h -> UnionCredits -> m UnionCredits
Internal.supplyUnionCredits ResolveSerialisedValue
forall a b. a -> b -> a
const Table m h
t (Int -> UnionCredits
Internal.UnionCredits Int
credits)