Skip to content

Commit 68f6aa7

Browse files
committed
MC-41819: Pagination breaks when the shared catalogue is enabled
- Fix cache is not cleaned after indexer "catalogsearch_fulltext" is executed
1 parent f25fc03 commit 68f6aa7

File tree

12 files changed

+662
-202
lines changed

12 files changed

+662
-202
lines changed

app/code/Magento/Indexer/Model/Indexer/CacheCleaner.php

Lines changed: 37 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -7,56 +7,61 @@
77

88
namespace Magento\Indexer\Model\Indexer;
99

10-
use Magento\Framework\App\CacheInterface;
11-
use Magento\Framework\Event\Manager as EventManager;
1210
use Magento\Framework\Indexer\ActionInterface;
13-
use Magento\Framework\Indexer\CacheContext;
1411

1512
/**
1613
* Clean cache for reindexed entities after executed action.
1714
*/
1815
class CacheCleaner
1916
{
2017
/**
21-
* @var EventManager
18+
* @var DeferredCacheCleaner
2219
*/
23-
private $eventManager;
20+
private $cacheCleaner;
2421

2522
/**
26-
* @var CacheContext
23+
* @param DeferredCacheCleaner $cacheCleaner
2724
*/
28-
private $cacheContext;
25+
public function __construct(
26+
DeferredCacheCleaner $cacheCleaner
27+
) {
28+
$this->cacheCleaner = $cacheCleaner;
29+
}
2930

3031
/**
31-
* @var CacheInterface
32+
* Defer cache cleaning until after execute full
33+
*
34+
* @param ActionInterface $subject
35+
* @return void
36+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
3237
*/
33-
private $appCache;
38+
public function beforeExecuteFull(ActionInterface $subject)
39+
{
40+
$this->cacheCleaner->start();
41+
}
3442

3543
/**
36-
* @param EventManager $eventManager
37-
* @param CacheContext $cacheContext
38-
* @param CacheInterface $appCache
44+
* Clean cache after full reindex full
45+
*
46+
* @param ActionInterface $subject
47+
* @return void
48+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
3949
*/
40-
public function __construct(
41-
EventManager $eventManager,
42-
CacheContext $cacheContext,
43-
CacheInterface $appCache
44-
) {
45-
$this->eventManager = $eventManager;
46-
$this->cacheContext = $cacheContext;
47-
$this->appCache = $appCache;
50+
public function afterExecuteFull(ActionInterface $subject)
51+
{
52+
$this->cacheCleaner->flush();
4853
}
4954

5055
/**
51-
* Clean cache after full reindex.
56+
* Defer cache cleaning until after execute list
5257
*
5358
* @param ActionInterface $subject
5459
* @return void
5560
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
5661
*/
57-
public function afterExecuteFull(ActionInterface $subject)
62+
public function beforeExecuteList(ActionInterface $subject)
5863
{
59-
$this->cleanCache();
64+
$this->cacheCleaner->start();
6065
}
6166

6267
/**
@@ -68,34 +73,30 @@ public function afterExecuteFull(ActionInterface $subject)
6873
*/
6974
public function afterExecuteList(ActionInterface $subject)
7075
{
71-
$this->cleanCache();
76+
$this->cacheCleaner->flush();
7277
}
7378

7479
/**
75-
* Clean cache after reindexed row.
80+
* Defer cache cleaning until after execute row
7681
*
7782
* @param ActionInterface $subject
7883
* @return void
7984
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
8085
*/
81-
public function afterExecuteRow(ActionInterface $subject)
86+
public function beforeExecuteRow(ActionInterface $subject)
8287
{
83-
$this->cleanCache();
88+
$this->cacheCleaner->start();
8489
}
8590

8691
/**
87-
* Clean cache.
92+
* Clean cache after reindexed row.
8893
*
94+
* @param ActionInterface $subject
8995
* @return void
96+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
9097
*/
91-
private function cleanCache()
98+
public function afterExecuteRow(ActionInterface $subject)
9299
{
93-
$this->eventManager->dispatch('clean_cache_by_tags', ['object' => $this->cacheContext]);
94-
95-
$identities = $this->cacheContext->getIdentities();
96-
if (!empty($identities)) {
97-
$this->appCache->clean($identities);
98-
$this->cacheContext->flush();
99-
}
100+
$this->cacheCleaner->flush();
100101
}
101102
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Indexer\Model\Indexer;
9+
10+
use Magento\Framework\Indexer\CacheContext;
11+
12+
/**
13+
* Defer cache tags registration if cache context is deferred
14+
*/
15+
class DeferCacheCleaning
16+
{
17+
/**
18+
* @var DeferredCacheContext
19+
*/
20+
private $deferredCacheContext;
21+
22+
/**
23+
* @param DeferredCacheContext $deferredCacheContext
24+
*/
25+
public function __construct(
26+
DeferredCacheContext $deferredCacheContext
27+
) {
28+
$this->deferredCacheContext = $deferredCacheContext;
29+
}
30+
31+
/**
32+
* Defer cache tags registration if cache context is deferred
33+
*
34+
* @param CacheContext $subject
35+
* @param callable $proceed
36+
* @param string $cacheTag
37+
* @param array $ids
38+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
39+
*/
40+
public function aroundRegisterEntities(
41+
CacheContext $subject,
42+
callable $proceed,
43+
string $cacheTag,
44+
array $ids
45+
): CacheContext {
46+
if ($this->deferredCacheContext->isActive()) {
47+
$this->deferredCacheContext->registerEntities($cacheTag, $ids);
48+
} else {
49+
$proceed($cacheTag, $ids);
50+
}
51+
return $subject;
52+
}
53+
54+
/**
55+
* Defer cache tags registration if cache context is deferred
56+
*
57+
* @param CacheContext $subject
58+
* @param callable $proceed
59+
* @param array $cacheTags
60+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
61+
*/
62+
public function aroundRegisterTags(
63+
CacheContext $subject,
64+
callable $proceed,
65+
array $cacheTags
66+
): CacheContext {
67+
if ($this->deferredCacheContext->isActive()) {
68+
$this->deferredCacheContext->registerTags($cacheTags);
69+
} else {
70+
$proceed($cacheTags);
71+
}
72+
return $subject;
73+
}
74+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Indexer\Model\Indexer;
9+
10+
use Magento\Framework\App\CacheInterface;
11+
use Magento\Framework\Event\Manager as EventManager;
12+
use Magento\Framework\Indexer\CacheContext;
13+
14+
/**
15+
* Deferred cache cleaner for indexers
16+
*/
17+
class DeferredCacheCleaner
18+
{
19+
/**
20+
* @var EventManager
21+
*/
22+
private $eventManager;
23+
24+
/**
25+
* @var CacheInterface
26+
*/
27+
private $appCache;
28+
29+
/**
30+
* @var DeferredCacheContext
31+
*/
32+
private $deferredCacheContext;
33+
34+
/**
35+
* @var CacheContext
36+
*/
37+
private $cacheContext;
38+
39+
/**
40+
* @param EventManager $eventManager
41+
* @param CacheInterface $appCache
42+
* @param DeferredCacheContext $deferredCacheContext
43+
* @param CacheContext $cacheContext
44+
*/
45+
public function __construct(
46+
EventManager $eventManager,
47+
CacheInterface $appCache,
48+
DeferredCacheContext $deferredCacheContext,
49+
CacheContext $cacheContext
50+
) {
51+
$this->eventManager = $eventManager;
52+
$this->deferredCacheContext = $deferredCacheContext;
53+
$this->appCache = $appCache;
54+
$this->cacheContext = $cacheContext;
55+
}
56+
57+
/**
58+
* Defer cache cleaning until flush() is called
59+
*
60+
* @see flush()
61+
*/
62+
public function start(): void
63+
{
64+
$this->deferredCacheContext->start();
65+
}
66+
67+
/**
68+
* Flush cache
69+
*/
70+
public function flush(): void
71+
{
72+
$this->deferredCacheContext->commit();
73+
$this->eventManager->dispatch('clean_cache_by_tags', ['object' => $this->cacheContext]);
74+
$identities = $this->cacheContext->getIdentities();
75+
if (!empty($identities)) {
76+
$this->appCache->clean($identities);
77+
$this->cacheContext->flush();
78+
}
79+
}
80+
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Indexer\Model\Indexer;
9+
10+
use Magento\Framework\Indexer\CacheContext;
11+
12+
/**
13+
* Deferred cache context for indexers
14+
*/
15+
class DeferredCacheContext
16+
{
17+
/**
18+
* @var CacheContext
19+
*/
20+
private $cacheContext;
21+
22+
/**
23+
* @var array
24+
*/
25+
private $tags = [];
26+
27+
/**
28+
* @var array
29+
*/
30+
private $entities = [];
31+
32+
/**
33+
* @var int
34+
*/
35+
private $level = 0;
36+
37+
/**
38+
* @param CacheContext $cacheContext
39+
*/
40+
public function __construct(CacheContext $cacheContext)
41+
{
42+
$this->cacheContext = $cacheContext;
43+
}
44+
45+
/**
46+
* Register entity Ids
47+
*
48+
* @param string $cacheTag
49+
* @param array $ids
50+
*/
51+
public function registerEntities(string $cacheTag, array $ids): void
52+
{
53+
if ($this->isActive()) {
54+
$this->entities[$cacheTag] = array_merge($this->tags[$cacheTag] ?? [], $ids);
55+
}
56+
}
57+
58+
/**
59+
* Register entity tags
60+
*
61+
* @param array $cacheTags
62+
*/
63+
public function registerTags(array $cacheTags): void
64+
{
65+
if ($this->isActive()) {
66+
$this->tags = array_merge($this->tags, $cacheTags);
67+
}
68+
}
69+
70+
/**
71+
* Defer any subsequent cache tags registration until commit() is called
72+
*
73+
* @see commit()
74+
*/
75+
public function start(): void
76+
{
77+
if (!$this->isActive()) {
78+
$this->entities = [];
79+
$this->tags = [];
80+
$this->level = 0;
81+
}
82+
++$this->level;
83+
}
84+
85+
/**
86+
* Register all buffered cache tags since the first call of start()
87+
*
88+
* @see start()
89+
*/
90+
public function commit(): void
91+
{
92+
$level = $this->level--;
93+
if ($level === 1) {
94+
if ($this->tags) {
95+
$this->cacheContext->registerTags($this->tags);
96+
}
97+
foreach ($this->entities as $cacheTag => $entityIds) {
98+
$this->cacheContext->registerEntities($cacheTag, $entityIds);
99+
}
100+
}
101+
}
102+
103+
/**
104+
* Check if cache tags registration is deferred
105+
*
106+
* @return bool
107+
*/
108+
public function isActive(): bool
109+
{
110+
return $this->level > 0;
111+
}
112+
}

0 commit comments

Comments
 (0)