Problem/Motivation

In \Drupal\search_api\Entity\Index::setHasReindexed(), a call to \Drupal::state()->set() is made regardless of the current state. As a result, performing bulk operations on multiple indexed entities could result in a lot of state sets (seems like two per Node create/update), which is a complex operation which results in a lot of database operations.

My team is having performance issues as a result of this, and would prefer it if Search API only updated the state if the operation is necessary.

Proposed resolution

Check the existing state has_reindexed state before updating it, to avoid multiple unnecessary database writes while updating entities.

Remaining tasks

Review the provided patch.

User interface changes

None.

API changes

None.

Data model changes

None.

CommentFileSizeAuthor
search-api-avoid-state-set.patch576 bytessamuel.mortenson

Comments

samuel.mortenson created an issue. See original summary.

borisson_’s picture

Status: Needs review » Reviewed & tested by the community

This looks like a solid improvement and it passes all the tests, I don't think we need to have a new test for this either.

drunken monkey’s picture

Well, it's not as bad as the IS suggests, unless I'm mistaken: setHasReindexed() is only called when the nodes are actually indexed, not when they are only updated and marked for indexing (unless I'm mistaken) – and in this case, I'm pretty sure the indexing operation will take far more time than the writes to the state variable. Also, I'm really not sure where the two writes would come from.
Before committing this (and I guess it makes sense in any case – doing sometimes a read and a write is still better than always writing, unless the "only read" case is rare enough) it would be great to get to the bottom of this and make sure there isn't some other bug.

Can you confirm that you have "Index items immediately" enabled for the index? And could you find out from where setHasReindexed() is called (twice) for you?

samuel.mortenson’s picture

Can you confirm that you have "Index items immediately" enabled for the index? And could you find out from where setHasReindexed() is called (twice) for you?

Yes, "Index items immediately" is enabled for my index. I tried to replicate the two re-indexes problem on a standard Drupal site and couldn't get something working.On the site I noticed this issue on, the callers of setHasReindexed are search_api_entity_update and search_api_node_access_records_alter. Maybe this occurs when entity access isn't cached? We use a lot of contrib modules so it's hard to track down.

drunken monkey’s picture

Status: Reviewed & tested by the community » Fixed

Thanks a lot for reporting back with this information!
It seems it's called twice because nodes will actually be indexed twice under these circumstances!
See #2922525: Index items only at end of page request for a proposed fix.

In any case, as said, I think this makes the problem a lot less critical: indexing takes quite some time and resources in any case, so having one or two database writes on top of that won't really matter one way or the other.
Still, as also said, no argument against improving performance a little bit.

Committed.
Thanks again, everyone!

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.