{-|
    Provides additional support for working with fence pointer indexes and their
    accumulators.
-}
module Database.LSMTree.Extras.Index
(
    Append (AppendSinglePage, AppendMultiPage),
    appendToCompact,
    appendToOrdinary,
    append
)
where

import           Control.DeepSeq (NFData (rnf))
import           Control.Monad.ST.Strict (ST)
import           Data.Foldable (toList)
import           Data.Word (Word32)
import           Database.LSMTree.Internal.Chunk (Chunk)
import           Database.LSMTree.Internal.Index (IndexAcc)
import qualified Database.LSMTree.Internal.Index as Index (appendMulti,
                     appendSingle)
import           Database.LSMTree.Internal.Index.CompactAcc (IndexCompactAcc)
import qualified Database.LSMTree.Internal.Index.CompactAcc as IndexCompact
                     (appendMulti, appendSingle)
import           Database.LSMTree.Internal.Index.OrdinaryAcc (IndexOrdinaryAcc)
import qualified Database.LSMTree.Internal.Index.OrdinaryAcc as IndexOrdinary
                     (appendMulti, appendSingle)
import           Database.LSMTree.Internal.Serialise (SerialisedKey)

-- | Instruction for appending pages, to be used in conjunction with indexes.
data Append
    = {-|
          Append a single page that fully comprises one or more key–value pairs.
      -}
      AppendSinglePage
          SerialisedKey -- ^ Minimum key
          SerialisedKey -- ^ Maximum key
    | {-|
          Append multiple pages that together comprise a single key–value pair.
      -}
      AppendMultiPage
          SerialisedKey -- ^ Sole key
          Word32        -- ^ Number of overflow pages

instance NFData Append where

    rnf :: Append -> ()
rnf (AppendSinglePage SerialisedKey
minKey SerialisedKey
maxKey)
        = SerialisedKey -> ()
forall a. NFData a => a -> ()
rnf SerialisedKey
minKey () -> () -> ()
forall a b. a -> b -> b
`seq` SerialisedKey -> ()
forall a. NFData a => a -> ()
rnf SerialisedKey
maxKey
    rnf (AppendMultiPage SerialisedKey
key Word32
overflowPageCount)
        = SerialisedKey -> ()
forall a. NFData a => a -> ()
rnf SerialisedKey
key () -> () -> ()
forall a b. a -> b -> b
`seq` Word32 -> ()
forall a. NFData a => a -> ()
rnf Word32
overflowPageCount

{-|
    Adds information about appended pages to an index and outputs newly
    available chunks, using primitives specific to the type of the index.

    See the documentation of the 'IndexAcc' type for constraints to adhere to.
-}
appendWith :: ((SerialisedKey, SerialisedKey) -> j s -> ST s (Maybe Chunk))
           -> ((SerialisedKey, Word32)        -> j s -> ST s [Chunk])
           -> Append
           -> j s
           -> ST s [Chunk]
appendWith :: forall (j :: * -> *) s.
((SerialisedKey, SerialisedKey) -> j s -> ST s (Maybe Chunk))
-> ((SerialisedKey, Word32) -> j s -> ST s [Chunk])
-> Append
-> j s
-> ST s [Chunk]
appendWith (SerialisedKey, SerialisedKey) -> j s -> ST s (Maybe Chunk)
appendSingle (SerialisedKey, Word32) -> j s -> ST s [Chunk]
appendMulti Append
instruction j s
indexAcc = case Append
instruction of
    AppendSinglePage SerialisedKey
minKey SerialisedKey
maxKey
        -> Maybe Chunk -> [Chunk]
forall a. Maybe a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList (Maybe Chunk -> [Chunk]) -> ST s (Maybe Chunk) -> ST s [Chunk]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (SerialisedKey, SerialisedKey) -> j s -> ST s (Maybe Chunk)
appendSingle (SerialisedKey
minKey, SerialisedKey
maxKey) j s
indexAcc
    AppendMultiPage SerialisedKey
key Word32
overflowPageCount
        -> (SerialisedKey, Word32) -> j s -> ST s [Chunk]
appendMulti (SerialisedKey
key, Word32
overflowPageCount) j s
indexAcc
{-# INLINABLE appendWith #-}

{-|
    Adds information about appended pages to a compact index and outputs newly
    available chunks.

    See the documentation of the 'IndexAcc' type for constraints to adhere to.
-}
appendToCompact :: Append -> IndexCompactAcc s -> ST s [Chunk]
appendToCompact :: forall s. Append -> IndexCompactAcc s -> ST s [Chunk]
appendToCompact = ((SerialisedKey, SerialisedKey)
 -> IndexCompactAcc s -> ST s (Maybe Chunk))
-> ((SerialisedKey, Word32) -> IndexCompactAcc s -> ST s [Chunk])
-> Append
-> IndexCompactAcc s
-> ST s [Chunk]
forall (j :: * -> *) s.
((SerialisedKey, SerialisedKey) -> j s -> ST s (Maybe Chunk))
-> ((SerialisedKey, Word32) -> j s -> ST s [Chunk])
-> Append
-> j s
-> ST s [Chunk]
appendWith (SerialisedKey, SerialisedKey)
-> IndexCompactAcc s -> ST s (Maybe Chunk)
forall s.
(SerialisedKey, SerialisedKey)
-> IndexCompactAcc s -> ST s (Maybe Chunk)
IndexCompact.appendSingle
                             (SerialisedKey, Word32) -> IndexCompactAcc s -> ST s [Chunk]
forall s.
(SerialisedKey, Word32) -> IndexCompactAcc s -> ST s [Chunk]
IndexCompact.appendMulti
{-# INLINE appendToCompact #-}

{-|
    Adds information about appended pages to an ordinary index and outputs newly
    available chunks.

    See the documentation of the 'IndexAcc' type for constraints to adhere to.
-}
appendToOrdinary :: Append -> IndexOrdinaryAcc s -> ST s [Chunk]
appendToOrdinary :: forall s. Append -> IndexOrdinaryAcc s -> ST s [Chunk]
appendToOrdinary = ((SerialisedKey, SerialisedKey)
 -> IndexOrdinaryAcc s -> ST s (Maybe Chunk))
-> ((SerialisedKey, Word32) -> IndexOrdinaryAcc s -> ST s [Chunk])
-> Append
-> IndexOrdinaryAcc s
-> ST s [Chunk]
forall (j :: * -> *) s.
((SerialisedKey, SerialisedKey) -> j s -> ST s (Maybe Chunk))
-> ((SerialisedKey, Word32) -> j s -> ST s [Chunk])
-> Append
-> j s
-> ST s [Chunk]
appendWith (SerialisedKey, SerialisedKey)
-> IndexOrdinaryAcc s -> ST s (Maybe Chunk)
forall s.
(SerialisedKey, SerialisedKey)
-> IndexOrdinaryAcc s -> ST s (Maybe Chunk)
IndexOrdinary.appendSingle
                              (SerialisedKey, Word32) -> IndexOrdinaryAcc s -> ST s [Chunk]
forall s.
(SerialisedKey, Word32) -> IndexOrdinaryAcc s -> ST s [Chunk]
IndexOrdinary.appendMulti
{-# INLINE appendToOrdinary #-}

{-|
    Adds information about appended pages to an index and outputs newly
    available chunks.

    See the documentation of the 'IndexAcc' type for constraints to adhere to.
-}
append :: Append -> IndexAcc s -> ST s [Chunk]
append :: forall s. Append -> IndexAcc s -> ST s [Chunk]
append = ((SerialisedKey, SerialisedKey)
 -> IndexAcc s -> ST s (Maybe Chunk))
-> ((SerialisedKey, Word32) -> IndexAcc s -> ST s [Chunk])
-> Append
-> IndexAcc s
-> ST s [Chunk]
forall (j :: * -> *) s.
((SerialisedKey, SerialisedKey) -> j s -> ST s (Maybe Chunk))
-> ((SerialisedKey, Word32) -> j s -> ST s [Chunk])
-> Append
-> j s
-> ST s [Chunk]
appendWith (SerialisedKey, SerialisedKey) -> IndexAcc s -> ST s (Maybe Chunk)
forall s.
(SerialisedKey, SerialisedKey) -> IndexAcc s -> ST s (Maybe Chunk)
Index.appendSingle
                    (SerialisedKey, Word32) -> IndexAcc s -> ST s [Chunk]
forall s. (SerialisedKey, Word32) -> IndexAcc s -> ST s [Chunk]
Index.appendMulti
{-# INLINE append #-}