While debugging some performance related issues I've seen purge calling curl_multi_exec() 4835 times (see image attached -> red rectangle on the bottom). After expecting a large list of URL's to be expired, this list turned out to be only 2 items long.

This function is called from this loop:

do {
  curl_multi_exec($curl_purges, $running);
} while ($running > 0);

The example in the PHP manual differs in that it uses the output from curl_multi_exec() in the expression:

do {
    $mrc = curl_multi_exec($mh, $active);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);

From: http://nl3.php.net/manual/en/function.curl-multi-init.php

After changing this in the purge module (see patch attached), the curl_multi_exec() function is called once.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

SqyD’s picture

Status: Active » Fixed

Thanks again for another fix Maurits! It's in the 6.x-1.4 release

SqyD’s picture

Status: Fixed » Closed (fixed)
jaydub’s picture

Status: Closed (fixed) » Active

Has the patch actually been tested? If I run 6.1.4 with this code, no PURGE requests are ever sent. If I revert to the previous code, PURGE requests are successfully sent.

For what it's worth, the full example on the PHP page is:

$active = null;
//execute the handles
do {
    $mrc = curl_multi_exec($mh, $active);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);

while ($active && $mrc == CURLM_OK) {
    if (curl_multi_select($mh) != -1) {
        do {
            $mrc = curl_multi_exec($mh, $active);
        } while ($mrc == CURLM_CALL_MULTI_PERFORM);
    }
}

so perhaps for that to work the full code above will need to be added to purge.

jaydub’s picture

Ok so I noticed that if there is only 1 purge request in the multi header with the old code that it works but if there are more than 1 (say the node/{nid} path plus the alias) then I hit this loop as well.

I'll try to implement the full solution on the php page and see if that both works and works with more than one purge request.

mauritsl’s picture

FileSize
823 bytes

I ran into this problem as wel... Results seem to be different per server. Don't know if the results are different because the load or different curl versions.

The documentation lacks a bit on this part, but another loop seems needed to make sure are requests are processed. Patch attached solves the problem for me.

SqyD’s picture

Status: Active » Needs review

Thanks for the patch Maurits. I'll be a bit more careful before committing this to a stable release. Curl_multi is very poorly documented indeed and I don't have time and resources to check on all variations of php/curl and platforms but your approach seems a good one to me.

@jaydub: could you please check if this patch also solves your issues as well?

jaydub’s picture

I've misplaced the link to the article on this but from what I read about curl_multi_exec() the way it works in the example on the PHP site as referenced in #3 is by using a loop and polling for the response from the varnish server when the multiple purge requests are sent.

When curl_multi_select() is called (http://php.net/manual/en/function.curl-multi-select.php) there is a default parameter for a timeout setting of 1 second. So what happens is the loop will keep running and poll for response depending on the timeout value. This is still potentially running lots of PHP calls during the curl request processing but compared to the previous code which just had a single while loop it is much better. The single while loop as noted can result in 1000s of requests as the same polling for responses is going on with curl_multi_exec().

update: here's one article that explains a bit about curl_multi_exec: http://www.somacon.com/p537.php

msonnabaum’s picture

Status: Needs review » Reviewed & tested by the community
FileSize
754 bytes

I also ran into this and the proposed fix is correct. Attached patch works on the D7 branch.

timhilliard’s picture

I also just ran into this bug. I tested the patches and they work. It would be great to get this committed.

chx’s picture

The inital loop is not necessary, it's repeated code. redis_ssi has this done nicely and much better explained than the PHP manual that everyone repeats... which means eventually I need to update the PHP manual as well. http://drupalcode.org/project/redis_ssi.git/blob/refs/heads/7.x-1.x:/red...

killes@www.drop.org’s picture

Priority: Normal » Major

Bumping a bit.

Without this patch I would get strange http error codes (namely: 0) returned and thus bogus errors in the logs.

pbuyle’s picture

FileSize
1.42 KB

Here is a patch for the 7.x-1.x branch with correct code copy/pasted from redis_ssi as per chx's suggestion.

SqyD’s picture

Status: Reviewed & tested by the community » Closed (fixed)

I've just committed a last patch by mongolito404 to both the D6 and D7 branches. Thanks to all who contributed!