Closed (fixed)
Project:
Drupal core
Version:
8.0.x-dev
Component:
cache system
Priority:
Normal
Category:
Task
Assigned:
Unassigned
Issue tags:
Reporter:
Created:
24 May 2011 at 14:30 UTC
Updated:
29 Jul 2014 at 19:35 UTC
Jump to comment: Most recent, Most recent file
Comments
Comment #1
Anonymous (not verified) commentedyes.
Comment #2
catchHere's a patch.
For now the SQL implementation is very dumb. We don't have multiple merge capability in dbtng, so it is just foreaching over each item and calling set(). This might be enough - since it'd allow memcache and redis backends to properly implement multiple set (since they both support that natively), and we could figure out if there's some ANSI SQL that would allow the multi-insert/update to happen later on.
Comment #3
catchComment #4
Anonymous (not verified) commentedComment #5
Anonymous (not verified) commentedComment #6
catchWith tests.
Comment #8
catchWith passing tests.
Comment #9
Anonymous (not verified) commentedtwo things:
1. it's probably going to be quicker to do delete + a single multi-insert then a bunch of merge queries
2. i think the API should allow for the expire to be set per-item
attached patch does those two things.
Comment #10
berdirSubscribe. I also did this for my initial CacheArray implementation.
Looking at catch's implementation, it looks to be more intelligent and only cache the parts which are actually required but a setMultiple() might still be useful for caches where a number of items are accessed on a single request.
Comment #11
catchDelete then insert works for me, I don't think we need a fully ANSI compliant merge query for setting cache items...
I debated a bit with myself about timestamp support, adding this gives us more flexibility later. If we do that we need to change the documentation here though:
This is no longer accurate.
Comment #12
Anonymous (not verified) commentedupdated the doco as per #11.
Comment #13
c960657 commentedThe other places in cache.inc where exceptions are caught, it is done to silently ignore the database being down. But if the database is down, there is no point in doing a rollback, is there? So what is the purpose? An inline comment would be appropriate.
(I think muting these exceptions is a bit fishy - I'll consider filing a ticket about that)
In deleteMultiple() we delete in chunks of a 1,000 entries. Did you consider doing the same in setMultiple() ? The chunking was introduced in #333171-12: Optimize the field cache in order to not create SQL queries that exceed the max_allowed_packet size. I guess it is unlikely that we add that many entries at once, so personally I don't think we need chunking here.
+ $this->assertTrue($cached['cid_1']->data == $items['cid_1']['data']);
I think assertEqual() is better in this place.I suggest changing the test so the setMultiple() call will add a new entry and overwrite an existing one.
Comment #14
Anonymous (not verified) commented#13 - we could just take out the transaction all together. this is a cache, so if we fail after the delete, no code should die, things will just be a bit slower.
i've also changed the assertTrue() to assertEqual().
Comment #15
alan evans commentedI think this issue has a lot of merit, but the patch is now miles off being applicable on the current code base. Planning to take a look at converting it today. There are a number of backends to consider now (which I guess has to be an enviable position to be in).
Comment #16
alan evans commentedAttaching an attempt at incorporating these changes into the current state of core. I've needed to make a few changes:
I was unable to find a cleaner solution for MemoryBackend::setMultiple, as it always needs a foreach to fix up the incoming items (checksum and flatten tags), so might as well do the set in the foreach as well. MemoryBackend isn't the type that would hugely benefit from avoiding the foreach+set anyway.
Comment #17
berdirWondering if we should change set() in the database backend to be a wrapper of setMultiple(), just like get() is.
I'm not sure about the rules of @see in inline comments but this might not make sense Because the purpose of @see's is to be added at the end of the description on api.drupal.org, this however should stay there. methods/functions are linked anyway.
Maybe "(optional) The cache tags for this item, see Cache..."?
Assertion messages should not use t().
Comment #18
alan evans commentedMany thanks for the review!
Attaching corrections of the smaller suggestions. I don't have anything against the idea of making set a wrapper of setMultiple, but it will need to wait until I have the time to give it the care it needs. It does seem like something that would be worth keeping consistent if there's no downside (which would be worth a little checking). There is a small difference in implementations of the 2: set is a merge query, while setMultiple is a delete + insert.
Comment #19
berdirComment #20
berdir#18: 1167248-cache-setmultiple.1.patch queued for re-testing.
Comment #22
berdirAttaching a re-roll.
Converted ViewsDataCache to use this. I think we should get rid of that multiple set there and instead set the separate tables on demand, similar to CacheCollector but until then, it probably makes sense to use this.
Comment #24
berdirThis should fix the test failures.
Comment #25
dawehnerMisses starting "\".
Does it make sense to add an additional @see CacheBackendInterface::set()
Should should be probably be marked as a public function.
Is there a reason why catch exceptions even we don't do it in all the other functions?
Could we use $item += array('expire' => CacheBackend..., 'tags' => array()) , this would make it a bit easier to read.
public ...
"\"
As berdir mentioned in IRC this could have scalibility issues if you have for example 100 fields you end up with 200 potential cache tables and so inserts here.
Comment #26
berdirThanks for the great review.
- Fixed missing \
- Removed Exception, that's a left-over
- Added public
- Added defaults to $item, nice idea!
Unlike deleteMultiple(), there is no reliable way to make sure that the resulting string is not too large, a single item could be. So I think we shouldn't worry about that too much. And I want to get rid of that in case of views anyway once CacheCollector is in.
Comment #27
dawehnerThis looks really good now, though I don't feel to be in the position to RTBC it.
Comment #29
berdir...
Comment #31
berdir#29: cache-set-multiple-views-1167248-29.patch queued for re-testing.
Comment #33
berdir#29: cache-set-multiple-views-1167248-29.patch queued for re-testing.
Comment #35
berdir#29: cache-set-multiple-views-1167248-29.patch queued for re-testing.
Comment #36
sun#29: cache-set-multiple-views-1167248-29.patch queued for re-testing.
Comment #38
damien tournoud commentedWe actually want the transaction here (and in deleteMultiple), if only for performance. Without the transaction, you force the database to commit after *each* statement. With the transaction, the database can do a more efficient commit operation at the end.
Comment #39
berdirRe-rolled, ViewsDataCache no longer needs this as it has been refactored quite a bit. Also using the injected database now and starting a transaction. I think we don't need to catch exceptions/do a rollback if something goes wrong. If the delete query fails then nothing happened anyway and if the insert fails then we actually want to delete, to not have old caches lying around?
Comment #40
berdir#39: cache-set-multiple-1167248-39.patch queued for re-testing.
Comment #42
berdir#39: cache-set-multiple-1167248-39.patch queued for re-testing.
Comment #43
dawehnerShould be @inheritdoc now.
So it should be type hinted as array
should be explicit marked as public.
We do care about creating the bin, if it did not exist before. The chance is low that you start with a setMultiple but you never know.
Comment #44
berdirYeah, I'm pretty sure the last patch predates @inheritdoc and dynamic table creation, didn't expect it to still apply ;)
Comment #45
fabianx commented#39: cache-set-multiple-1167248-39.patch queued for re-testing.
Comment #46
Anonymous (not verified) commentedholy crap this thing still lives.
will reroll something in the next day or two.
Comment #47
Anonymous (not verified) commentedComment #48
alan evans commentedStraight reroll for now (patch succeeded with default fuzz), let's see how it goes and then probably still needs corrections from #43 ...
(Marking for review just for testing - most likely should be "needs work")
Comment #49
alan evans commentedComment #50
alan evans commentedStyle corrections from #43. Last comment still needs dealing with.
Comment #51
alan evans commentedLooks like there may be a little extra from the set() method that needs pulling into setMultiple also.
Comment #52
alan evans commentedComment #53
damiankloip commentedComment #54
damiankloip commentedComment #56
damiankloip commentedThis should fix that fail - was reliant on the fixed discrepancy in the return from flattenTags in MemoryBackend. Also converted a usage for this in \Drupal\Core\Config\CachedStorage.
Comment #57
wim leersLooks great! :)
Some simple remarks, but this is almost ready.
It would be valuable to have a comment here that explains the rationale for using multi delete + multi insert rather than many merge queries. (See #9, #11)
This entire chunk of code is *identical* to what's in
DatabaseBackend::doSet(). Let's just split that into a protected::prepareItemSet()method, and rename the existing::prepareItem()to::prepareItemGet()?One leading space too many.
Comment #58
damiankloip commentedThanks for the review.
Fixed the docs points. I think they are subtly different, although they reuse alot of the same code for sure. Plus we would have to call drupal_static alot more if this was extracted out? Otherwise I agree it might be nice to consider. What do you think about kicking that to a follow up?
Comment #59
wim leersSounds good.
But then:
80 col.
And in your interdiff:
Nice subtle clean-up :)
Comment #60
damiankloip commentedFixed the comment and reverted that change in doSet() I don't see an issue doing that one line here, it will go into a followup anyway... :)
Comment #61
sunLooks good to me. I agree that adding
setMultiple()makes sense. Also looks like we found an actual first use-case for it, which is even better :-)Comment #62
sunThat said, the associative array values are bit poor/strange, but we can't do anything about that here without introducing proper CacheItem objects first, and that should not hold up this patch.
Comment #63
damiankloip commentedThanks, and agreed. If we add a proper classed cache item. We can change it then.
Comment #64
wim leers#62: ooooh! Yes! Following!
Comment #65
catchNice to see this RTBC after three years.
Committed/pushed to 8.x, thanks!
We should be able to use this in the entity caching patch as well.