lsm-tree-1.0.0.0: src-core/Database/LSMTree/Internal/WriteBuffer.hs
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE GeneralisedNewtypeDeriving #-}
{-# OPTIONS_HADDOCK not-home #-}
-- | The in-memory LSM level 0.
--
module Database.LSMTree.Internal.WriteBuffer (
WriteBuffer,
empty,
numEntries,
fromMap,
toMap,
fromList,
toList,
addEntry,
null,
lookups,
lookup,
rangeLookups,
) where
import Control.DeepSeq (NFData (..))
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import qualified Data.Vector as V
import Database.LSMTree.Internal.BlobRef (BlobSpan)
import Database.LSMTree.Internal.Entry
import qualified Database.LSMTree.Internal.Map.Range as Map.R
import Database.LSMTree.Internal.Range (Range (..))
import Database.LSMTree.Internal.Serialise
import qualified Database.LSMTree.Internal.Vector as V
import Prelude hiding (lookup, null)
{-------------------------------------------------------------------------------
Writebuffer type
-------------------------------------------------------------------------------}
newtype WriteBuffer =
WB { unWB :: Map SerialisedKey (Entry SerialisedValue BlobSpan) }
deriving stock (Eq, Show)
deriving newtype NFData
empty :: WriteBuffer
empty = WB Map.empty
-- | \( O(1) \)
numEntries :: WriteBuffer -> NumEntries
numEntries (WB m) = NumEntries (Map.size m)
-- | \( O(1)) \)
fromMap ::
Map SerialisedKey (Entry SerialisedValue BlobSpan)
-> WriteBuffer
fromMap m = WB m
-- | \( O(1) \)
toMap :: WriteBuffer -> Map SerialisedKey (Entry SerialisedValue BlobSpan)
toMap = unWB
-- | \( O(n \log n) \)
fromList ::
ResolveSerialisedValue -- ^ merge function
-> [(SerialisedKey, Entry SerialisedValue BlobSpan)]
-> WriteBuffer
fromList f es = WB $ Map.fromListWith (combine f) es
-- | \( O(n) \)
toList :: WriteBuffer -> [(SerialisedKey, Entry SerialisedValue BlobSpan)]
toList (WB m) = Map.assocs m
{-------------------------------------------------------------------------------
Updates
-------------------------------------------------------------------------------}
addEntry ::
ResolveSerialisedValue -- ^ merge function
-> SerialisedKey
-> Entry SerialisedValue BlobSpan
-> WriteBuffer
-> WriteBuffer
addEntry f k e (WB wb) =
WB (Map.insertWith (combine f) k e wb)
{-------------------------------------------------------------------------------
Querying
-------------------------------------------------------------------------------}
null :: WriteBuffer -> Bool
null (WB m) = Map.null m
-- We return an 'Entry' with serialised values, so it can be properly combined
-- with the lookups in other runs. Deserialisation only occurs afterwards.
--
-- Note: the entry may be 'Delete'.
--
lookups ::
WriteBuffer
-> V.Vector SerialisedKey
-> V.Vector (Maybe (Entry SerialisedValue BlobSpan))
lookups (WB !m) !ks = V.mapStrict (`Map.lookup` m) ks
lookup ::
WriteBuffer
-> SerialisedKey
-> Maybe (Entry SerialisedValue BlobSpan)
lookup (WB !m) !k = Map.lookup k m
{-------------------------------------------------------------------------------
RangeQueries
-------------------------------------------------------------------------------}
-- | We return 'Entry' so we can properly combine lookup results.
--
-- Note: 'Delete's are not filtered out.
--
rangeLookups ::
WriteBuffer
-> Range SerialisedKey
-> [(SerialisedKey, Entry SerialisedValue BlobSpan)]
rangeLookups (WB m) r =
[ (k, e)
| let (lb, ub) = convertRange r
, (k, e) <- Map.R.rangeLookup lb ub m
]
convertRange :: Range k -> (Map.R.Bound k, Map.R.Bound k)
convertRange (FromToExcluding lb ub) =
( Map.R.Bound lb Map.R.Inclusive
, Map.R.Bound ub Map.R.Exclusive )
convertRange (FromToIncluding lb ub) =
( Map.R.Bound lb Map.R.Inclusive
, Map.R.Bound ub Map.R.Inclusive )