see if you can spot the bug
post_ids <- case r of Nothing -> (do -- actually have to run the query here let q = "SELECT post_id FROM s_posts p WHERE " ++ q_where ++ " ORDER BY p.post_date DESC" where q_where = intercalate " AND " post_clauses stm <- prepare db q execute stm post_params rs <- fetchAllRows' stm let post_ids = map (\x -> fromSql (x !! 0) :: Int) rs -- cache the results let q = "INSERT INTO " ++ cache_table ++ "( query_string, query_result ) VALUES( ?, ? )" stm <- prepare db q execute stm [toSql q_serialized, toSql (encode post_ids)] return post_ids)
This block of code runs right after checking to see if the fulltext search results are cached. Specifically, this bit gets run if the search isn't currently cached -- it performs the fulltext search and throws the results back into the database as a JSON-encoded list of matching post IDs.
The kicker here is the fetchAllRows'. This function differs from fetchAllRows in that it is strictly evaluated -- which means if you've got a lot of search results, it'll pull them in all at once and leave you sitting with a massive array. Instead, we'd like to collect the results and throw them to the DB as we're fetching them. The solution is to switch to fetchAllRows, making sure to use a separate stm (because the subsequent execute on the same statement will dick stuff up).
I won't bother posting the fixed code, it's a fairly trivial change.
This also explains why I was never able to reproduce the problem by re-executing requests from the access logs -- this code only gets triggered the first time the search hits the database. Once it was run, the results got cached and this bit of code wouldn't need to execute again.
Sneaky motherfuckers!
Comments are off for this post