module Simulation.Aivika.Distributed.Optimistic.Internal.UndoableLog
(UndoableLog,
newUndoableLog,
writeLog,
rollbackLog,
reduceLog,
logSize) where
import Data.IORef
import Control.Monad
import Control.Monad.Trans
import qualified Simulation.Aivika.DoubleLinkedList as DLL
import Simulation.Aivika.Trans.Comp
import Simulation.Aivika.Trans.Internal.Types
import Simulation.Aivika.Distributed.Optimistic.Internal.Priority
import Simulation.Aivika.Distributed.Optimistic.Internal.DIO
import Simulation.Aivika.Distributed.Optimistic.Internal.IO
data UndoableLog =
UndoableLog { logItems :: DLL.DoubleLinkedList UndoableItem
}
data UndoableItem =
UndoableItem { itemTime :: Double,
itemUndo :: DIO ()
}
newUndoableLog :: DIO UndoableLog
newUndoableLog =
do xs <- liftIOUnsafe DLL.newList
return UndoableLog { logItems = xs }
writeLog :: UndoableLog -> DIO () -> Event DIO ()
writeLog log h =
Event $ \p ->
do let x = UndoableItem { itemTime = pointTime p, itemUndo = h }
liftIOUnsafe $
do f <- DLL.listNull (logItems log)
if f
then DLL.listAddLast (logItems log) x
else do x0 <- DLL.listLast (logItems log)
when (itemTime x < itemTime x0) $
error $
"The logging data are not sorted by time (" ++
(show $ itemTime x) ++ " < " ++
(show $ itemTime x0) ++ "): writeLog"
DLL.listAddLast (logItems log) x
rollbackLog :: UndoableLog -> Double -> Bool -> DIO ()
rollbackLog log t including =
do
loop
where
loop =
do f <- liftIOUnsafe $ DLL.listNull (logItems log)
unless f $
do x <- liftIOUnsafe $ DLL.listLast (logItems log)
when ((t < itemTime x) || (including && t == itemTime x)) $
do liftIOUnsafe $ DLL.listRemoveLast (logItems log)
itemUndo x
loop
reduceLog :: UndoableLog -> Double -> IO ()
reduceLog log t =
do f <- DLL.listNull (logItems log)
unless f $
do x <- DLL.listFirst (logItems log)
when (itemTime x < t) $
do DLL.listRemoveFirst (logItems log)
reduceLog log t
logSize :: UndoableLog -> IO Int
logSize log = DLL.listCount (logItems log)