Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
The attached patch has the goal to make the module more failure tolerant. This by ensuring that a failing cache not fully breaks the page and avoiding unnecessary slow down on failure.
Changes:
dmemcache_get()
: Make sure the variable $result
is set in any case.dmemcache_object()
: If a connection to a server fails don't try to connect again within the same request. Avoids that we run into the connection timeout multiple times.MemCacheDrupal->clear()
: Stop execution if there's no memcache connection.
Comments
Comment #1
girishmuraly CreditAttribution: girishmuraly commentedYour patch certainly reduced the number of warnings I get on screen if a particular bin (cache_menu's in my case) was killed. I still get a couple of them though:
Notice: Memcache::connect() [memcache.connect]: Server 127.0.0.1 (tcp 11212) failed with: Connection refused (111) in dmemcache_object() (line 293 of /var/www/html/drupal/sites/all/modules/contrib/memcache/dmemcache.inc).
In my case, line 293 is marked in the code snippet below:
Comment #2
pillarsdotnet CreditAttribution: pillarsdotnet commentedThis is wrong. The function documentation says that it returns FALSE on error, which is different from NULL.
See correct patch at #1307078: Fix Notice: Undefined variable: result in dmemcache_get() (line 114 of /var/www/sites/all/modules/memcache/dmemcache.inc).
Comment #3
das-peter CreditAttribution: das-peter commentedWow, long time ago I've created this patch. Luckily I've found some time to re-roll it today.
@girishmuraly: I'm not sure if we should suppress this error - since it's really an essential one. Goal of the patch is only to hit this error once and by that not slowing down the site build more than really necessary. The other difficulty is that this code runs early in bootstrap and thus I don't have the possibility to log it into watchdog (at least as far as I know :) )
@pillarsdotnet: Thanks for reviewing it! I've changed that now.
Comment #4
pillarsdotnet CreditAttribution: pillarsdotnet commentedClosed as duplicate: #1307078: Fix Notice: Undefined variable: result in dmemcache_get() (line 114 of /var/www/sites/all/modules/memcache/dmemcache.inc).
Comment #5
pillarsdotnet CreditAttribution: pillarsdotnet commentedSuggestions:
Change:
To:
Change:
To:
Comment #6
das-peter CreditAttribution: das-peter commented@pillarsdotnet: Thank you again for the review :)
I agree with you
if ($c == $cluster && !isset($failed_connection_cache[$s])) {
is way more readable.However to do this I had to change this
$failed_connection_cache[$s] = FALSE;
to this$failed_connection_cache[$s] = TRUE;
. Otherwiseisset / empty
don't recognize that the array item exists. FALSE would be nice because the server is actually "false" - but I guess the readability has priority. Other opinions on that?error_log()
andst()
are indeed a nice idea - thanks!Comment #7
pillarsdotnet CreditAttribution: pillarsdotnet commentedThe functions
isset()
andempty()
do not work the same way.A variable set to
FALSE
will be both set and empty.A variable set to
NULL
will be both unset and empty.The following should output
true
.So should this:
And this:
But this will output
false
:Comment #8
das-peter CreditAttribution: das-peter commentedWow, I really wasn't aware of that - thank you for clarifying this :)
Comment #9
pillarsdotnet CreditAttribution: pillarsdotnet commentedPatch in #6 looks good to me. Using in production now.
Comment #10
pillarsdotnet CreditAttribution: pillarsdotnet commentedFound one mistake, which was my own fault:
Should be:
(sorry)
Comment #11
das-peter CreditAttribution: das-peter commentedOh, I missed that to *blush*
Thanks for letting me know - patch updated.
Comment #12
pillarsdotnet CreditAttribution: pillarsdotnet commentedGood to go.
Comment #13
BerdirSubscribe, will try to review and test this asap.
Comment #14
BerdirIs there a specific reason to not use watchdog() here? That is imho the correct function to use for messages like this, unless there is a reason why it can't be used.
If this happens, we should have already logged a message at the time the connection failed, right?
Comment #15
pillarsdotnet CreditAttribution: pillarsdotnet commentedYes. This code is invoked during bootstrap, before watchdog is available. So we have three choices:
Fail silently.
Fail while gracefully reporting an error using the only means available.
Deliberately invoke watchdog() to produce an ungraceful fatal error.
Precisely. No need to log the same error multiple times.
Comment #16
das-peter CreditAttribution: das-peter commented@berdir: Thanks for the review.
@pillarsdotnet: Thanks for answering the questions.
You guys are awesome, your responsiveness is very much appreciated :)
Comment #17
BerdirI see. Looking at watchdog(), which is defined in bootstrap.inc and therefore always available, it is basically a no-op if module_implements() is not defined. Problem is, in that case, the message won't be logged at all. Not sure about trigger_error() either, not sure what happens if e.g. a E_USER_WARNING is triggered during bootstrap.
So error_log() might very well be the only option here, but maybe you could add a quick comment explaining why it's used instead of something else?
Comment #18
das-peter CreditAttribution: das-peter commentedThank you for the review. Indeed
trigger_error()
is a good idea since it triggers the Drupal error handler.I've changed the code regarding your suggestions.
Besides that I fixed a structural flaw and I also changed the
memcache-lock.inc
.Without the change the lock seems to kill the script execution, by a to high nesting level, if the memcache isn't reachable.
Now
memcache-lock.inc
falls back to the default lock mechanism if memcache isn't available.The other idea I was thinking of is to fallback to the default cache handler if memcache isn't available. Because in my eyes this modules highest priority is to ensure the execution is not slowed down - regardless of what happens. Second priority has of course to gain a performance boost :)
Comment #19
catchtrigger_error() is good, but error_log() should be removed.
Do we really need to cache the fact that connections failed?
I'm not keen at all on doing this, conditionally defining functions is not pretty although I don't see a way around that without backporting #1225404: Modern event based lock framework proposal to D7 (which I would like to do though if it gets in).
Comment #20
das-peter CreditAttribution: das-peter commentedThanks for the review.
Comment #21
das-peter CreditAttribution: das-peter commentedOh, needs of course again a review or at least more opinions about the ugly code :D
Comment #22
catchI'd be happier with the lock.inc change if that was moved to an include maybe. At least then there's not weird indentation if the function declarations.
Comment #23
das-peter CreditAttribution: das-peter commentedWhat about this solution:
Moved code of
memcache-lock.inc
intomemcache-lock-code.inc
and replaced code inmemcache-lock.inc
with a conditional include.Code stays readable & maintainable. Only the files could be a little bit confusing. Nevertheless, even if someone accidentally uses
memcache-lock-code.inc
directly the functionality won't break.Comment #24
catchLooks much better - there's at least one comment over 80 chars though, also @TODO should be @todo.
Comment #25
das-peter CreditAttribution: das-peter commentedThanks for the hint - changed.
Comment #26
catchOK this looks fine now. Committed/pushed to 7.x-1.x, we could probably backport this to 6.x
Comment #28
Jeremy CreditAttribution: Jeremy at Tag1 Consulting commentedBack ported: