pdf-slave-server-0.1.1.0: src/Text/PDF/Slave/Server/DB.hs
module Text.PDF.Slave.Server.DB(
Model
, AcidState
, createDB
-- * Execution DB queries
, HasAcidState(..)
, runQuery
, runUpdate
-- * Persistent entities
, RenderId(..)
, RenderItem(..)
, Notification(..)
-- * Queries
-- ** Render queue
, AddRenderItem(..)
, GetRenderQueueSize(..)
, CheckNextRenderItem(..)
, FetchRenderItem(..)
-- ** Notification queue
, AddNotification(..)
, GetNotificationQueueSize(..)
, CheckNextNotification(..)
, FetchNotification(..)
, GetNotificationNextTime(..)
) where
import Control.Concurrent.Thread.Delay
import Control.Monad (void, forever)
import Control.Monad.IO.Class
import Control.Monad.Trans.Control
import Data.Acid
import Data.Text (unpack)
import Data.Time
import Text.PDF.Slave.Server.Config
import Text.PDF.Slave.Server.DB.Model
import Text.PDF.Slave.Server.Util
import qualified Control.Immortal as Immortal
-- | Create connection pool for DB
createDB :: (MonadIO m, MonadBaseControl IO m)
=> DatabaseConfig -- ^ Connection configuration
-> m (AcidState Model)
createDB DatabaseConfig{..} = do
db <- liftIO $ openLocalStateFrom (unpack databasePath) initialModel
whenJust databaseCheckpointTime $ \dt -> checkpointWorker dt db
whenJust databaseArchiveTime $ \dt -> archiveWorker dt db
return db
-- | Describes monads that has internal acid-state storage
class HasAcidState a m | m -> a where
getAcidState :: m (AcidState a)
-- | Run acid-state query in monad with internal acid storage
runQuery :: (MonadIO m, HasAcidState (EventState event) m, QueryEvent event)
=> event -- ^ Event constructed from query with 'makeAcidic'
-> m (EventResult event)
runQuery e = do
db <- getAcidState
liftIO $ query db e
-- | Run acid-state update query in monad with internal acid storage
runUpdate :: (MonadIO m, HasAcidState (EventState event) m, UpdateEvent event)
=> event -- ^ Event constructed from query with 'makeAcidic'
-> m (EventResult event)
runUpdate e = do
db <- getAcidState
liftIO $ update db e
-- | Worker thread that creates DB checkpoints in given interval
checkpointWorker :: (MonadIO m, MonadBaseControl IO m)
=> NominalDiffTime -- ^ Time interval of creation of checkpoints
-> AcidState Model -- ^ DB to make checkpoint from
-> m ()
checkpointWorker dt db = liftIO . void . Immortal.createWithLabel "checkpointWorker" $
const $ forever $ do
delay . toMicroseconds $ dt
createCheckpoint db
-- | Worker thread that creates archives from DB in given interval
archiveWorker :: (MonadIO m, MonadBaseControl IO m)
=> NominalDiffTime -- ^ Time interval of creation of checkpoints
-> AcidState Model -- ^ DB to make checkpoint from
-> m ()
archiveWorker dt db = liftIO . void . Immortal.createWithLabel "archiveWorker" $
const $ forever $ do
delay . toMicroseconds $ dt
createArchive db