Problem/Motivation
If you provide field based REST views you'll realize that they are quite slow, unless you have some caching for the entire result enabled.
Once you dive into it, you quickly realize, this is caused by having no row level field caching for REST views.
Proposed resolution
Remaining tasks
User interface changes
API changes
Data model changes
Comment | File | Size | Author |
---|---|---|---|
#25 | 2648268-25-lets_see_what_fails.patch | 1.38 KB | Wim Leers |
#22 | 2648268-22-lets_see_what_fails.patch | 709 bytes | Wim Leers |
#2 | 2648268-2.patch | 616 bytes | dawehner |
#2 | Screen Shot 2016-01-11 at 17.09.00.png | 474.42 KB | dawehner |
Comments
Comment #2
dawehnerThis helps quite a lot, see the attached screenshot.
Let's see whether this breaks stuff
Comment #3
oriol_e9gYou also need to change the code comment
// Otherwise, pass this through the field advancedRender() method.
Comment #4
dawehnerFair, let's see first, whether this breaks anything.
We need maybe add some tests around escaping etc. While implementing that in custom code, I had quite some issues around that.
Comment #5
moshe weitzman CreditAttribution: moshe weitzman at Acquia commentedWow, quite a speedup for a single line. Nice work.
Comment #6
dawehnerWell, my actual usecase was a 120 seconds view down to 1.5 seconds, but yeah, this was too crazy for a core issue
Comment #7
xjm@dawehner and I chatted briefly about this point in IRC. One concern we discussed was cache invalidation and how cache bubbling played out in the REST view. (I imagine @dawehner will post more about that but just wanted to add a note here.)
Comment #8
dawehnerRight, its all about cache invalidation. The simple usecase of a rest view, which just renders some of the fields of an entity, works fine, as each row has their cache tags. The advanced usecases are the once which cause troubles. Just imagine you embed a view inside the main view to render some fields of the current row entity. Then you would need to take into account cache tags for that referenced entity as well. All that complex bubbling logic is solved by render API, but sadly it's something we don't have in REST views.
One potential solution @jaesin and others talked about is to introduce intermediate objects, which carry around the metadata for the field rendering and finally extract the data out later, before we pass the data to the serializer to render everything.
Comment #9
Wim LeersExplain this dark magic?!
This sounds sensible, but it's hard to picture how that works exactly — especially considering how complex Views can be. Not even having taken into account how the Serializers work. I fear even a PoC would be a huge undertaking though? And could this even be done without breaking BC?
Comment #10
dawehnergetField()
calls out\Drupal\views\Plugin\views\style\StylePluginBase::renderFields
which does some render caching one day.Comment #11
Wim LeersAha, so in calling that other function, we're able to rely on a cache hit rather than doing the work. Makes sense. Thanks.
Comment #12
Wim LeersComment #13
dawehnerExactly, now the only problem is that we don't have any kind of bubbleable cacheable metadata, just the one on the row itself. I was thinking about adding an advanced option,
so you can get this single line, in case you want to and you know what you do.
Comment #14
xjmAll the core committers agreed that this issue should be major priority. We weren't entirely agreed it was a bug though, and it might be an 8.1.x issue depending on the full solution. Moving it to 8.1.x for now; if it turns out to be backportable we can look into that.
Comment #15
dawehnerTo be honest the only thing I see possible, is to make it configurable. There is no clear API layer where we could opt out of caching.
Comment #16
dawehnerThis patch so far is obviously not enough!
Comment #17
Wim Leers#2 shows a significant perf win. What was the test setup?
Comment #18
dawehnerI don't remember, but I guess its like 50 nodes in a rest feed or so. The actual site here decreased there numbers from 3 minutes to 1,5 seconds, but this was rendering the entirety of the entire site out with thousand of nodes.
Comment #19
Wim Leers:O Wow!
Comment #20
dawehnerHere is the basic approach I haven chosen for the client code:
Inside a custom field plugin which does complex stuff:
Inside DataFieldRow:
With RestFragmentData
As we cannot enforce custom field plugins to do that crazy stuff, I don't see how this could be solved automatically without opting in as site builder.
Comment #22
Wim LeersSo, AFAICT, the core problem is that
\Drupal\views\Plugin\views\style\StylePluginBase::renderFields()
does:(This was introduced in #2450897: Cache Field views row output.)
But OTOH, we did #2477157: rest_export Views display plugin does not set necessary cache metadata, which made this change to
\Drupal\rest\Plugin\views\display\RestExport::buildResponse()
:… so I wonder if bubbling isn't actually simply … working? Let's find out which code is still relying on the else-case in the first quoted code.
Comment #23
dawehnerI don't get that patch, honestly. You at least have to combine it somehow with my previous patch, because well, there is no row level caching triggered at the moment. Yes, the metadata of each row bubble to the entire view, but this is not the point of this issue to be honest, see first sentence of the issue summary.
Comment #25
Wim LeersComment #26
dawehnerTo be clear, in the custom project I was working one we had a field plugin that returned raw data, and well it worked, so requiring cache ability metadata needs to be somehow supported and opt IN for this raw data.
Comment #28
Wim LeersComment #29
dawehnerLet me clarify why I think this issue is quite problematic when we want to keep BC.
While the patch in #2 proves that the simple case actually doesn't break anything, here is the what happened on the client project while dealing with it.
The patch in #2 got implemented and boom nothing invalided anymore. We had though a custom field plugin which just rendered stuff and returned a string. This one was specifically targeted towards REST, so we haven't thought about cacheability yet at that point in time. When we introduce simply #2 we gonna hit that problem on other sites as well.
On top of that advancedRender also potentially renders via the theme() function, which includes the template used by field templates. This can be obviously be problematic
when someone has any kind of HTML in their field template.
Given to make this BC compatible we need the following steps IMHO:
Comment #30
Wim LeersAdding
tag based on #29.Everything else is opt out. Opt out is better, if it can be done without breaking BC. If that is not possible (it sounds like it is not), then opt in would be fine.
Comment #31
dawehnerWell in the case above opt OUT would have totally broken the site.
Comment #32
Wim LeersYep, that's what I thought. So then opt in it is.
Comment #35
Wim LeersAlmost a year has passed since this was last touched. Only 11 followers, half of which are the core developers on this issue. Nobody is facing this problem yet?
Deprioritizing.
The bigger problem is that you can currently only get ALL results for a REST view: there's no paging. See #2099281: [PP-1] REST views: pagination link relations and #2100637: REST views: add special handling for collections for that.
Comment #36
dawehnerI honestly don't know who came up with that myth. You can just configure a view like any other view, and use
?page=1
and paginate. What doesn't work is having the appropriate link relations in the http header, which everyone would always use, right ;)Comment #37
Wim LeersOh huh… I'd swear you told me that!
Comment #38
dawehnerMh. Well at least #2099281: [PP-1] REST views: pagination link relations is certainly not major in that case.