Data.Binary, strict reading

Hi, I want to read a file using Data.Binary, and I want to read the file strictly - i.e. when I leave the read file I want to guarantee the handle is closed. The reason is that (possibly immediately after) I need to write to the file. The following is the magic I need to use - is it all necessary, is it guaranteed correct, should I use something else? src <- decodeFile "_make/_make" Map.size mp `seq` performGC Thanks for all the helpful replies to the last post, I think I've nearly come up with a minimal test case I can give you, or at least characterise where the issue might lie. But I'll post to that thread when I've got the details. Thanks Neil

On Wed, Feb 25, 2009 at 2:15 PM, Neil Mitchell
src <- decodeFile "_make/_make" Map.size mp `seq` performGC
Shouldn't you use rnf[1]? Also, there seems to be binary-strict on Hackage, but I don't know if it is being maintained anymore. HTH, [1] http://www.haskell.org/ghc/docs/latest/html/libraries/parallel/Control-Paral... -- Felipe.

On Wed, Feb 25, 2009 at 12:15 PM, Neil Mitchell
Hi,
I want to read a file using Data.Binary, and I want to read the file strictly - i.e. when I leave the read file I want to guarantee the handle is closed. The reason is that (possibly immediately after) I need to write to the file. The following is the magic I need to use - is it all necessary, is it guaranteed correct, should I use something else?
src <- decodeFile "_make/_make" Map.size mp `seq` performGC
Thanks for all the helpful replies to the last post, I think I've nearly come up with a minimal test case I can give you, or at least characterise where the issue might lie. But I'll post to that thread when I've got the details.
Thanks
Neil
Funnily enough, I was just grappling with this issue in Yi. My solution was to make the read strict, so my function looked like this: readDB ∷ YiM ArticleDB readDB = io $ (dbLocation >>= r) `catch` (λ_ → return empty) where r x = fmap (decode · BL.fromChunks · return) $ B.readFile x -- gwern

On Wed, 2009-02-25 at 17:15 +0000, Neil Mitchell wrote:
Hi,
I want to read a file using Data.Binary, and I want to read the file strictly - i.e. when I leave the read file I want to guarantee the handle is closed. The reason is that (possibly immediately after) I need to write to the file. The following is the magic I need to use - is it all necessary, is it guaranteed correct, should I use something else?
src <- decodeFile "_make/_make" Map.size mp `seq` performGC
I suggest you use withFile instead and decode from the Handle that gives you (via hGetContents) rather than decodeFile from the file name. That makes it much clearer. Of course you have to avoid doing lazy stuff, but that should be ok, Binary is strict in reading by default. Duncan

Neil Mitchell wrote:
Hi,
I want to read a file using Data.Binary, and I want to read the file strictly - i.e. when I leave the read file I want to guarantee the handle is closed. The reason is that (possibly immediately after) I need to write to the file. The following is the magic I need to use - is it all necessary, is it guaranteed correct, should I use something else?
src <- decodeFile "_make/_make" Map.size mp `seq` performGC
With binary 0.5,
src <- decodeFile "_make/_make"
return $! src
should close the file, assuming that all the data is read from the file,
thanks to this patch:
Mon Aug 25 23:01:09 CEST 2008 Don Stewart

Hi
With binary 0.5,
src <- decodeFile "_make/_make" return $! src
I'm pretty sure I was on the latest Cabal released version of binary, and the above trick did not work. It _usually_ worked, but every so often I'd get a locking error.
Shouldn't you use rnf[1]? Also, there seems to be binary-strict on Hackage, but I don't know if it is being maintained anymore.
Map.size is rnf on maps, I know exactly what its doing so in this case I'm willing to cheat a little - but rnf would certainly be the more principled way of doing it.
I suggest you use withFile instead and decode from the Handle that gives you (via hGetContents) rather than decodeFile from the file name. That makes it much clearer. Of course you have to avoid doing lazy stuff, but that should be ok, Binary is strict in reading by default.
That was my first attempt, but the types didn't match up. I can withFile using a System.IO handle, but Data.Binary doesn't seem to be able to start going from a Handle. I guess I have to hop via the ByteString bit myself with hGetContents. That's perfectly fine, and much better than currently. However
readDB = io $ (dbLocation >>= r) `catch` (λ_ → return empty) where r x = fmap (decode · BL.fromChunks · return) $ B.readFile x
This seems to be a very nice way of doing it, the strictness is explicit in the ByteString.readFile. I've gone for this in my code. Thanks Neil

On Thu, 2009-02-26 at 09:17 +0000, Neil Mitchell wrote:
I suggest you use withFile instead and decode from the Handle that gives you (via hGetContents) rather than decodeFile from the file name. That makes it much clearer. Of course you have to avoid doing lazy stuff, but that should be ok, Binary is strict in reading by default.
That was my first attempt, but the types didn't match up. I can withFile using a System.IO handle, but Data.Binary doesn't seem to be able to start going from a Handle. I guess I have to hop via the ByteString bit myself with hGetContents. That's perfectly fine, and much better than currently. However
Yes, you would use hGetContents.
readDB = io $ (dbLocation >>= r) `catch` (λ_ → return empty) where r x = fmap (decode · BL.fromChunks · return) $ B.readFile x
This seems to be a very nice way of doing it, the strictness is explicit in the ByteString.readFile. I've gone for this in my code.
I still think my suggestion was nicer. It makes the resource boundedness completely explicit, not relying on any strictness properties. It also doesn't unnecessarily read the whole file into memory before processing, though I expect for your example that doesn't matter too much. Duncan
participants (5)
-
Bertram Felgenhauer
-
Duncan Coutts
-
Felipe Lessa
-
Gwern Branwen
-
Neil Mitchell