On Fri, Jun 24, 2011 at 2:44 PM, Stefan Sperling <stsp_at_elego.de> wrote:
> Trying to update my working copy I observed svn spinning on the CPU
> forever. Attaching with gdb showed that it was stuck in an endless
> loop inside svn_ra_serf__handle_xml_parser().
>
> Below is the code. The problem was that serf_bucket_read() returned
> zero bytes but also indicated success. If that happens the loop never
> terminates.
>
> I suppose this code was written with the assumption that reading
> from the socket would always block until data is available?
No, serf is non-blocking! It's ok that serf returns 0 bytes read but
still APR_SUCCESS, but that should happen only once. The second time
svn reads something it should either return more data, or 0 with
status APR_EOF.
> This does not seem to happen in my case. Maybe serf is doing something
> wrong when it opens the socket?
>
> I'm using serf-0.7.x from the branch as of June 21.
>
Assuming you have a working copy checkout out from https://s.a.o, en
you haven't disabled gzip compression, my guess is that you're
encountering the same issue I have documented here:
http://groups.google.com/group/serf-dev/browse_thread/thread/56fcd4f25b290e29
In my scenario it loops in handle_fetch instead of the xml parser, but
it's basically the same case.
Serf trunk r1481 ensures the loop ends with an error in this situation.
Lieven
> while (1)
> {
> const char *data;
> apr_size_t len;
>
> status = serf_bucket_read(response, PARSE_CHUNK_SIZE, &data, &len);
>
> if (SERF_BUCKET_READ_ERROR(status))
> {
> return svn_error_wrap_apr(status, NULL);
> }
>
> /* Note: once the callbacks invoked by inject_to_parser() sets the
> PAUSED flag, then it will not be cleared. write_to_pending() will
> only save the content. Logic outside of serf_context_run() will
> clear that flag, as appropriate, along with processing the
> content that we have placed into the PENDING buffer.
>
> We want to save arriving content into the PENDING structures if
> the parser has been paused, or we already have data in there (so
> the arriving data is appended, rather than injected out of order) */
> #ifdef DISABLE_THIS_FOR_NOW
> if (ctx->paused || HAS_PENDING_DATA(ctx->pending))
> {
> err = write_to_pending(ctx, data, len, pool);
> }
> else
> #endif
> {
> err = inject_to_parser(ctx, data, len, &sl);
> if (err)
> {
> /* Should have no errors if IGNORE_ERRORS is set. */
> SVN_ERR_ASSERT(!ctx->ignore_errors);
> }
> }
> if (err)
> {
> XML_ParserFree(ctx->xmlp);
> add_done_item(ctx);
> return svn_error_return(err);
> }
>
> if (APR_STATUS_IS_EAGAIN(status))
> {
> return svn_error_wrap_apr(status, NULL);
> }
>
> if (APR_STATUS_IS_EOF(status))
> {
> if (ctx->pending != NULL)
> ctx->pending->network_eof = TRUE;
>
> /* We just hit the end of the network content. If we have nothing
> in the PENDING structures, then we're completely done. */
> if (!HAS_PENDING_DATA(ctx->pending))
> {
> /* Ignore the return status. We just don't care. */
> (void) XML_Parse(ctx->xmlp, NULL, 0, 1);
>
> XML_ParserFree(ctx->xmlp);
> add_done_item(ctx);
> }
>
> return svn_error_wrap_apr(status, NULL);
> }
>
> /* feed me! */
> }
>
>
Received on 2011-06-24 19:53:37 CEST