@@ -99,7 +99,6 @@ module Database.LSMTree.Monoidal (
9999 , resolveDeserialised
100100 -- ** Properties
101101 , resolveValueValidOutput
102- , resolveValueTotality
103102 , resolveValueAssociativity
104103
105104 -- * Utility types
@@ -111,9 +110,9 @@ import Control.Monad (void, (<$!>))
111110import Data.Bifunctor (Bifunctor (.. ))
112111import Data.Coerce (coerce )
113112import Data.Kind (Type )
113+ import Data.Monoid (Sum (.. ))
114114import Data.Typeable (Proxy (Proxy ), Typeable )
115115import qualified Data.Vector as V
116- import Data.Word (Word64 )
117116import Database.LSMTree.Common (IOLike , Range (.. ), SerialiseKey ,
118117 SerialiseValue (.. ), Session (.. ), SnapshotName ,
119118 closeSession , deleteSnapshot , listSnapshots , openSession ,
@@ -369,7 +368,7 @@ open (Session sesh) override snap =
369368 label = Common. makeSnapshotLabel (Proxy @ (k , v )) <> " (monoidal)"
370369
371370{- ------------------------------------------------------------------------------
372- Mutiple writable table handles
371+ Multiple writable table handles
373372-------------------------------------------------------------------------------}
374373
375374{-# SPECIALISE duplicate :: TableHandle IO k v -> IO (TableHandle IO k v) #-}
@@ -435,25 +434,20 @@ merge = undefined
435434-------------------------------------------------------------------------------}
436435
437436-- | A class to specify how to resolve/merge values when using monoidal updates
438- -- (mupserts ). This is required for merging entries during compaction and also
439- -- for doing lookups, to resolve multiple entries of the same key on the fly.
437+ -- ('Mupsert' ). This is required for merging entries during compaction and also
438+ -- for doing lookups, resolving multiple entries of the same key on the fly.
440439-- The class has some laws, which should be tested (e.g. with QuickCheck).
441440--
441+ -- It is okay to assume that the input bytes can be deserialised using
442+ -- 'deserialiseValue', as they are produced by either 'serialiseValue' or
443+ -- 'resolveValue' itself, which are required to produce deserialisable output.
444+ --
442445-- Prerequisites:
443446--
444447-- * [Valid Output] The result of resolution should always be deserialisable.
445448-- See 'resolveValueValidOutput'.
446449-- * [Associativity] Resolving values should be associative.
447450-- See 'resolveValueAssociativity'.
448- -- * [Totality] For any input 'RawBytes', resolution should successfully provide
449- -- a result. This is a pretty strong requirement. Usually it is sufficient to
450- -- handle input produced by 'serialiseValue' and 'resolveValue' (which are
451- -- are required to be deserialisable by 'deserialiseValue'),
452- -- but this makes sure no error occurs in the middle of compaction, which
453- -- could lead to corruption.
454- -- See 'resolveValueTotality'.
455- --
456- -- TODO: Revisit Totality. How are errors handled during run merging?
457451--
458452-- Future opportunities for optimisations:
459453--
@@ -465,8 +459,10 @@ merge = undefined
465459-- means that the inserted value is serialised and (if there is another value
466460-- with the same key in the write buffer) immediately deserialised again.
467461--
468- -- TODO: Should this go into @Internal.Monoidal@ or @Internal.ResolveValue@?
469462-- TODO: The laws depend on 'SerialiseValue', should we make it a superclass?
463+ -- TODO: should we additionally require Totality (for any input 'RawBytes',
464+ -- resolution should successfully provide a result)? This could reduce the
465+ -- risk of encountering errors during a run merge.
470466class ResolveValue v where
471467 resolveValue :: Proxy v -> RawBytes -> RawBytes -> RawBytes
472468
@@ -486,13 +482,6 @@ resolveValueAssociativity (serialiseValue -> x) (serialiseValue -> y) (serialise
486482 where
487483 (<+>) = resolveValue (Proxy @ v )
488484
489- -- | Test the __Totality__ law for the 'ResolveValue' class
490- resolveValueTotality ::
491- forall v . ResolveValue v
492- => Proxy v -> RawBytes -> RawBytes -> Bool
493- resolveValueTotality _ x y =
494- resolveValue (Proxy @ v ) x y `deepseq` True
495-
496485-- | A helper function to implement 'resolveValue' by operating on the
497486-- deserialised representation. Note that especially for simple types it
498487-- should be possible to provide a more efficient implementation by directly
@@ -502,14 +491,10 @@ resolveValueTotality _ x y =
502491-- for 'resolveValue', but it's probably best to be explicit about instances.
503492--
504493-- To satisfy the prerequisites of 'ResolveValue', the function provided to
505- -- 'resolveDeserialised' should itself satisfy some properties.
506- --
507- -- Prerequisites:
494+ -- 'resolveDeserialised' should itself satisfy some properties:
508495--
509496-- * [Associativity] The provided function should be associative.
510- -- * [Total Resolution] The provided function should be total.
511- -- * [Total Deserialisation] 'deserialiseValue' for @v@ should handle any input
512- -- 'RawBytes'.
497+ -- * [Totality] The provided function should be total.
513498resolveDeserialised ::
514499 SerialiseValue v
515500 => (v -> v -> v ) -> Proxy v -> RawBytes -> RawBytes -> RawBytes
@@ -520,5 +505,7 @@ resolve :: ResolveValue v => Proxy v -> Internal.ResolveSerialisedValue
520505resolve = coerce . resolveValue
521506
522507-- | Mostly to give an example instance (plus the property tests for it).
523- instance ResolveValue Word64 where
508+ -- Additionally, this instance for 'Sum' provides a nice monoidal, numerical
509+ -- aggregator.
510+ instance (Num a , SerialiseValue a ) => ResolveValue (Sum a ) where
524511 resolveValue = resolveDeserialised (+)
0 commit comments