Hi Travis,

connection-read appears to be subtlety wrong.
If all the bytes are ready to be read then it is correct, but if only
some are read it is incorrect. Now in the large data scenario the
latter will appear if there are no delays. Inserting a sleep delays
the program per packet such that there is always data to be read -
causing it to work. This is a much more likely scenario...

How is it wrong?
the otherwise read more data part recurs until new-bytes-read == -1
(connection closed) so its no longer reading the amount specified by
the packet header. I think this was unintentional. A better solution
would be to just do a blocking read instead which can only give you
the right number of bytes or error. Otherwise the maths for remaining
data needs to be fixed. (Blocking is simpler and has the same result
and doesn't put you in a CPU spin).

Also regarding the state transitions, it looks to me that the way it
is set up now there has to be an eof to transition to :row-start
state, which will lead to another recur to reading the (presumably
finished) response which will be eof also. However I can't see how
that would result in your described issue its probably me just
misunderstanding. Your issue sounds highly related to a 'message'
being split across multiple packets - as it is dependent on data
size... so I believe the real problem is the way read is handled if
all the bytes aren't ready to be read.

I've had to make some assumptions about what you are doing so forgive
me if no relevant.


Regards,
Tim.



On Jun 1, 1:02 pm, tmountain <tinymount...@gmail.com> wrote:
> Hi all - I'm in the process of writing a proxy for MySQL in Clojure,
> and until now everything has been going smoothly. My project has
> reached the point where it can shuffle data up and down the wire
> between client and server with accurate results, but I'm running into
> a strange issue. I've noticed that when a certain result size is
> reached, (exactly 138 rows in this case), I get a malformed packet
> response from the client.
>
> Naturally, I assumed this was just an issue with mishandling the data
> being sent to and fro somehow, but then I ran into something strange.
> In trying to nail down the issue, I wrote a debug macro which inserts
> prints a given statement so long as a *debug* variable is set to true.
> As soon as I enabled the macro, the problem resolved itself, and the
> client returned the appropriate result. After a brief WTF moment, I
> decided it might be some kind of timing issue and changed the debug
> macro to simply do a Thread.sleep for 100 milliseconds. Again, this
> resolved the problem. Finally, I narrowed down the offending code to
> the following:
>
> (defn get-result-query [client server state]
>   "handle the states necessary to return a standard query result"
>   (let [server-response (connection-read server)]
>     (Thread/sleep 100) ; !!!!!!!!! remove this, and the function will
> sporadically fail !!!!!!!!!
>     (connection-write client server-response)
>     (cond (and (= state :start) (eof-packet? server-response))
>                (recur client server :row-start)
>           (and (= state :row-start) (eof-packet? server-response))
>                {:state :send-command :server server}
>           (error-packet? server-response)
>                {:state :send-command :server server}
>           :else (recur client server state))))
>
> It seems that reading from the socket without a subsequent pause
> introduces problems for some reason. I have no idea why this would
> happen unless the data isn't fully down the wire or something along
> those lines. For good measure, here's the connection-read function as
> well:
>
> (defn connection-read [#^Socket conn]
>   "reads data up to the amount specified by the packet header"
>   (let [#^InputStream instream (. conn (getInputStream))
>         bytes (make-array (. Byte TYPE) 4)]
>     (. instream (read bytes 0 4))
>     ; make an array big enough for header + data
>     (let [data (make-array (. Byte TYPE)
>                            (+ 4 (packet-length? bytes)))]
>       (System/arraycopy bytes 0 data 0 4)
>       ; read data into the buffer
>       (loop [bytes-read (. instream (read data 4 (- (alength data)
> 4)))]
>         ; if we got all the desired data in one pass, return it
>         (if (>= bytes-read (- (alength data) 4))
>           data
>           ; otherwise, read more data
>           (let [new-bytes-read (. instream
>                                   (read data
>                                         bytes-read
>                                         (- (alength data) bytes-
> read)))]
>             (if (== new-bytes-read -1)
>               data
>               (recur (+ bytes-read new-bytes-read)))))))))
>
> If anybody has any suggestions to why this would be happening, I'd
> really appreciate it. I intend to release this project OSS when it's
> fully functional, and this is one of the few roadblocks in my way.
>
> Thanks,
> Travis
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to