Hello Café!
It's my first post here so do tell me if I get something wrong :)
I'm in the process of writing an event database; it should adhere to ACID principles and is specifically aimed at persisting then broadcasting events in some event-driven system.
The code is up on GitHub and I expect to build a Hackage package soon, for now I'm prototyping with Stack generating the .cabal file, but this will change when things settle down.
My question is about a function I have:
readEvents :: Word64 -> Connection -> IO ([IndexedEvent], TChan IndexedEvent)
readEvents from conn = do
(ec, chan) <- atomically $ (,)
<$> (readTVar $ evCount conn)
<*> (dupTChan $ readSubs conn)
evsFromDisk <- readEventsRange from ec conn
pure (evsFromDisk, chan)
1. What I'd like to understand is how I might unify the return type into a single `TChan IndexedEvent` which would contain first the `evsFromDisk` and then pull from the broadcast channel `chan`. The only way I can think to do it is to fork a thread to write to a new broadcast channel - which might be unexpected for a client of my API and seems quite heavyweight.
I have a connected couple of questions too, related to lazy IO as I'm still learning Haskell!
2. does my `readEventsRange` function pull all events into memory or does lazy IO magically avoid this by streaming the data through from the disk?
3. if I did fork a thread and write the `evsFromDisk` and the sit in a `forever` reading off `chan` and onto my new broadcast channel, would this result in all the written events being read into memory or does the laziness spread so that only when the client does a `readTChan` will the data flow through from the disk/`chan`?
Thanks for reading,
Adam