TonyGen / mongoDB-haskell

MongoDB driver for Haskell
http://hackage.haskell.org/package/mongoDB
Apache License 2.0
57 stars 14 forks source link

Exceptions raised when using tailable cursors #10

Closed mkscrg closed 12 years ago

mkscrg commented 12 years ago

Suppose accoll is a capped collection with one document in the test db on localhost. (If there are no documents the server never opens the cursor anyway.) The following ghci session demonstrates the problem:

Prelude> :set prompt "> "
> :set -XOverloadedStrings
> :m + Database.MongoDB
> pipe <- runIOE . connect $ host "127.0.0.1"
> let query = (select [] "accoll") { options = [TailableCursor] }
> cursor <- access pipe master "test" (find query) >>= either (fail . show) return
> access pipe master "test" $ next cursor
Right (Just [ _id: 4ee551a4f19ceeeb26a9addd])
> access pipe master "test" $ next cursor
*** Exception: server returned empty batch but says more results on server

If an element is inserted and then the next call made again, the same exception is raised. The last call should return Right Nothing, and then Right (Just [ ... ]) after an insertion.

This can be worked around by using nextBatch instead of next, but it takes two calls to get the documents back after an insert. Using rest or nextN has the same result as using next.

mkscrg commented 12 years ago

The exception is explicitly raised by Database.MongoDB.Query.next when it gets an empty batch with a nonzero cursor ID from the server. Since this is the exact behavior of tailable cursors, it should just return Nothing and get the next batch as usual, instead of raising the exception.

But this fix would create another problem. (It's the same problem I mention above regarding nextBatch, actually.) next prefetches a promise of the next batch from the server each time it's called (assuming there cursor ID is nonzero). So if we call next until we get Nothing, then insert a document into the capped collection and call next again, we would get Nothing again. It takes an additional call to next to get the new document(s), because of the prefetched (empty) promise.

mkscrg commented 12 years ago

Here's a straightforward fix to that last issue: when next encounters an empty prefetched batch with a nonzero cursor ID, it fetches a fresh batch from the server and executes normally on that. This means that next is twice as slow on these calls, but they should be rare, anyway.

I opened pull request #11 with this change. Thoughts?

mkscrg commented 12 years ago

I'd forgotten to make the same change for nextBatch, so I closed pull request #11 and opened #12 with that update.