Problem/Motivation
Looking up sources for aliases sometimes results in "not found" even if the alias exists.
Sounds similar to #2625166: redis.path: Page not found for aliased path but isn't related to whitespaces - so here's a decicated ticket :)
The scenario is as follows:
- Look up path for specific language e.g.
contact-us-now(HGET prefix:path:s:en contact-us-now) Redis_Path_PhpRedis::lookupInHash()will enable$doNoneLookup- Now if
Redis_Path_PhpRedis::lookupInHash()doesn't find a language specific item it goes and tries to find a language neutral one (HGET prefix:path:s:und contact-us-now) - But if the language neutral item was explicitly set to not existent (
Redis_Path_HashLookupInterface::VALUE_NULL=!) no return restore will happen due this code:if (!$ret && $previous) {- this again leads to returning FALSE which means "item not existent" even thought we actually just don't know if there's a language specific item.
Proposed resolution
I suggest to change the return restore condition to following:
// If the language specific item was explicitly set to not-existent
// and there's no language neutral item ensure the return is set to
// not-existent.
// OR
// If the language neutral item is explicitly set to not-existent but
// the language specific item is set to not found set the return to
// not found - this will allow a lookup of the language specific item
// and a proper cache set to not-existent if applicable.
if ((!$ret && $previous) || (self::VALUE_NULL === $ret && empty($previous))) {
// Restore null placeholder else we loose conversion to false
// and drupal_lookup_path() would attempt saving it once again.
$ret = $previous;
}
As the added comment states. If the language neutral item is explicitly set to not-existent, but the language specific item just isn't found we shouldn't skip looking up the language specific item by returning FALSE but we should do a look up and ensure the language specific item is set to the appropriate value in the cache.
This will also avoid the language neutral lookup in sub-sequent requests which means it's a tiny bit more efficient (while not leading to inconsistencies e.g. due the language specific item being evicted when running redis as LRU).
Remaining tasks
Reviews needed.
User interface changes
None
API changes
Well the return of Redis_Path_PhpRedis::lookupInHash() / Redis_Path_Predis::lookupInHash() will change in some scenarios but that's fair I guess :)
Data model changes
None.
| Comment | File | Size | Author |
|---|---|---|---|
| redis-path-handling-inconsistency.patch | 2.73 KB | das-peter |
Comments
Comment #2
czigor commentedNice catch!
The patch makes sense and looks good.
I could only reproduce the issue by manually removing entries from redis:
1. Multilingual node type, PhpRedis configured as url alias key-value store.
2. Create an English node (nid: 123) without alias and visit the node page. This creates a 'node/123' => '!' entry in the 'path:a:und' table. There's nothing added to 'path:a:en'.
3. Edit the node and add an url alias 'myalias'. This creates a 'node/123' => 'myalias' entry in the 'path:a:en' table so visiting /en/node/123 redirects to /en/myalias.
4. Remove the entry created in step 3 manually from redis. (I use Redis Desktop Manager for that.)
5. Now if I go to /en/node/123 I'm not redirected to /en/myalias, although the drupal url_alias table still has this alias.
6. Apply the patch and revisit /en/node/123. We get redirected to /en/myalias just like we should.
I don't know how this could happen without manually editing the redis entries but we see this symptom from time to time on our prod site. It might be a different issue though. Still, the patch definitely fixes a bug so it's worth committing.
Comment #3
pounardNice catch, I'm going to write the test first, then apply your patch. Thanks.
Comment #5
pounardI managed to reproduce it using a unit test.
Actually you did put the finger on a real logic bug, but there was an easier and more comprehensible way of fixing it:
This is sufficient, because we don't care if there was a $previous value or not, if language neutral is wrong, only the previous matters no matter its value.
I'll still credit you for the patch, it was not an easy one and you found the right place to fix :)
Comment #6
das-peter commented@pounard Thanks for the credit - much appreciated :)
Comment #7
memtkmcc commentedWow, great! Thanks!