[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

Re: serf infinite loop in svn_ra_serf__handle_xml_parser()

From: Lieven Govaerts <lgo_at_mobsol.be>
Date: Fri, 24 Jun 2011 19:52:45 +0200

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

This is an archived mail posted to the Subversion Dev mailing list.

This site is subject to the Apache Privacy Policy and the Apache Public Forum Archive Policy.