Skip to content

Commit 1d9b1ba

Browse files
committed
MC-6273: Mysql url_rewrite select make on product view page 170+ times per request
1 parent 8f737c0 commit 1d9b1ba

File tree

10 files changed

+320
-148
lines changed

10 files changed

+320
-148
lines changed

app/code/Magento/Config/App/Config/Type/System.php

Lines changed: 84 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* Copyright © Magento, Inc. All rights reserved.
44
* See COPYING.txt for license details.
55
*/
6+
67
namespace Magento\Config\App\Config\Type;
78

89
use Magento\Framework\App\Config\ConfigSourceInterface;
@@ -13,11 +14,12 @@
1314
use Magento\Config\App\Config\Type\System\Reader;
1415
use Magento\Framework\App\ScopeInterface;
1516
use Magento\Framework\Cache\FrontendInterface;
17+
use Magento\Framework\Cache\LockQueryInterface;
1618
use Magento\Framework\Lock\LockManagerInterface;
1719
use Magento\Framework\Serialize\SerializerInterface;
1820
use Magento\Store\Model\Config\Processor\Fallback;
19-
use Magento\Store\Model\ScopeInterface as StoreScope;
2021
use Magento\Framework\Encryption\Encryptor;
22+
use Magento\Store\Model\ScopeInterface as StoreScope;
2123

2224
/**
2325
* System configuration type
@@ -42,22 +44,6 @@ class System implements ConfigTypeInterface
4244
* @var string
4345
*/
4446
private static $lockName = 'SYSTEM_CONFIG';
45-
/**
46-
* Timeout between retrieves to load the configuration from the cache.
47-
*
48-
* Value of the variable in microseconds.
49-
*
50-
* @var int
51-
*/
52-
private static $delayTimeout = 100000;
53-
/**
54-
* Lifetime of the lock for write in cache.
55-
*
56-
* Value of the variable in seconds.
57-
*
58-
* @var int
59-
*/
60-
private static $lockTimeout = 42;
6147

6248
/**
6349
* @var array
@@ -106,9 +92,9 @@ class System implements ConfigTypeInterface
10692
private $encryptor;
10793

10894
/**
109-
* @var LockManagerInterface
95+
* @var LockQueryInterface
11096
*/
111-
private $locker;
97+
private $lockQuery;
11298

11399
/**
114100
* @param ConfigSourceInterface $source
@@ -122,6 +108,7 @@ class System implements ConfigTypeInterface
122108
* @param Reader|null $reader
123109
* @param Encryptor|null $encryptor
124110
* @param LockManagerInterface|null $locker
111+
* @param LockQueryInterface|null $lockQuery
125112
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
126113
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
127114
*/
@@ -136,7 +123,8 @@ public function __construct(
136123
$configType = self::CONFIG_TYPE,
137124
Reader $reader = null,
138125
Encryptor $encryptor = null,
139-
LockManagerInterface $locker = null
126+
LockManagerInterface $locker = null,
127+
LockQueryInterface $lockQuery = null
140128
) {
141129
$this->postProcessor = $postProcessor;
142130
$this->cache = $cache;
@@ -145,8 +133,8 @@ public function __construct(
145133
$this->reader = $reader ?: ObjectManager::getInstance()->get(Reader::class);
146134
$this->encryptor = $encryptor
147135
?: ObjectManager::getInstance()->get(Encryptor::class);
148-
$this->locker = $locker
149-
?: ObjectManager::getInstance()->get(LockManagerInterface::class);
136+
$this->lockQuery = $lockQuery
137+
?: ObjectManager::getInstance()->get(LockQueryInterface::class);
150138
}
151139

152140
/**
@@ -225,91 +213,76 @@ private function getWithParts($path)
225213
}
226214

227215
/**
228-
* Make lock on data load.
229-
*
230-
* @param callable $dataLoader
231-
* @param bool $flush
232-
* @return array
233-
*/
234-
private function lockedLoadData(callable $dataLoader, bool $flush = false): array
235-
{
236-
$cachedData = $dataLoader(); //optimistic read
237-
238-
while ($cachedData === false && $this->locker->isLocked(self::$lockName)) {
239-
usleep(self::$delayTimeout);
240-
$cachedData = $dataLoader();
241-
}
242-
243-
while ($cachedData === false) {
244-
try {
245-
if ($this->locker->lock(self::$lockName, self::$lockTimeout)) {
246-
if (!$flush) {
247-
$data = $this->readData();
248-
$this->cacheData($data);
249-
$cachedData = $data;
250-
} else {
251-
$this->cache->clean(\Zend_Cache::CLEANING_MODE_MATCHING_TAG, [self::CACHE_TAG]);
252-
$cachedData = [];
253-
}
254-
}
255-
} finally {
256-
$this->locker->unlock(self::$lockName);
257-
}
258-
259-
if ($cachedData === false) {
260-
usleep(self::$delayTimeout);
261-
$cachedData = $dataLoader();
262-
}
263-
}
264-
265-
return $cachedData;
266-
}
267-
268-
/**
269-
* Load configuration data for all scopes
216+
* Load configuration data for all scopes.
270217
*
271218
* @return array
272219
*/
273220
private function loadAllData()
274221
{
275-
return $this->lockedLoadData(function () {
222+
$loadAction = function () {
276223
$cachedData = $this->cache->load($this->configType);
277224
$data = false;
278225
if ($cachedData !== false) {
279226
$data = $this->serializer->unserialize($this->encryptor->decrypt($cachedData));
280227
}
281228
return $data;
282-
});
229+
};
230+
$loadAction->bindTo($this);
231+
232+
$collectAction = \Closure::fromCallable([$this, 'readData']);
233+
$saveAction = \Closure::fromCallable([$this, 'cacheData']);
234+
$cleanAction = \Closure::fromCallable([$this, 'cleanCacheAction']);
235+
236+
return $this->lockQuery->lockedLoadData(
237+
self::$lockName,
238+
$loadAction,
239+
$collectAction,
240+
$saveAction,
241+
$cleanAction
242+
);
283243
}
284244

285245
/**
286-
* Load configuration data for default scope
246+
* Load configuration data for default scope.
287247
*
288248
* @param string $scopeType
289249
* @return array
290250
*/
291251
private function loadDefaultScopeData($scopeType)
292252
{
293-
return $this->lockedLoadData(function () use ($scopeType) {
253+
$loadAction = function () use ($scopeType) {
294254
$cachedData = $this->cache->load($this->configType . '_' . $scopeType);
295255
$scopeData = false;
296256
if ($cachedData !== false) {
297257
$scopeData = [$scopeType => $this->serializer->unserialize($this->encryptor->decrypt($cachedData))];
298258
}
299259
return $scopeData;
300-
});
260+
};
261+
$loadAction->bindTo($this);
262+
263+
$collectAction = \Closure::fromCallable([$this, 'readData']);
264+
$saveAction = \Closure::fromCallable([$this, 'cacheData']);
265+
$cleanAction = \Closure::fromCallable([$this, 'cleanCacheAction']);
266+
267+
return $this->lockQuery->lockedLoadData(
268+
self::$lockName,
269+
$loadAction,
270+
$collectAction,
271+
$saveAction,
272+
$cleanAction
273+
);
301274
}
302275

303276
/**
304-
* Load configuration data for a specified scope
277+
* Load configuration data for a specified scope.
305278
*
306279
* @param string $scopeType
307280
* @param string $scopeId
308281
* @return array
309282
*/
310283
private function loadScopeData($scopeType, $scopeId)
311284
{
312-
return $this->lockedLoadData(function () use ($scopeType, $scopeId) {
285+
$loadAction = function () use ($scopeType, $scopeId) {
313286
$cachedData = $this->cache->load($this->configType . '_' . $scopeType . '_' . $scopeId);
314287
$scopeData = false;
315288
if ($cachedData === false) {
@@ -329,7 +302,20 @@ private function loadScopeData($scopeType, $scopeId)
329302
}
330303

331304
return $scopeData;
332-
});
305+
};
306+
$loadAction->bindTo($this);
307+
308+
$collectAction = \Closure::fromCallable([$this, 'readData']);
309+
$saveAction = \Closure::fromCallable([$this, 'cacheData']);
310+
$cleanAction = \Closure::fromCallable([$this, 'cleanCacheAction']);
311+
312+
return $this->lockQuery->lockedLoadData(
313+
self::$lockName,
314+
$loadAction,
315+
$collectAction,
316+
$saveAction,
317+
$cleanAction
318+
);
333319
}
334320

335321
/**
@@ -371,7 +357,17 @@ private function cacheData(array $data)
371357
}
372358

373359
/**
374-
* Walk nested hash map by keys from $pathParts
360+
* Clean cache action.
361+
*
362+
* @return void
363+
*/
364+
private function cleanCacheAction()
365+
{
366+
$this->cache->clean(\Zend_Cache::CLEANING_MODE_MATCHING_TAG, [self::CACHE_TAG]);
367+
}
368+
369+
/**
370+
* Walk nested hash map by keys from $pathParts.
375371
*
376372
* @param array $data to walk in
377373
* @param array $pathParts keys path
@@ -408,7 +404,7 @@ private function readData(): array
408404
}
409405

410406
/**
411-
* Clean cache and global variables cache
407+
* Clean cache and global variables cache.
412408
*
413409
* Next items cleared:
414410
* - Internal property intended to store already loaded configuration data
@@ -420,10 +416,20 @@ private function readData(): array
420416
public function clean()
421417
{
422418
$this->data = [];
423-
$this->lockedLoadData(
424-
function () {
425-
return false;
426-
},
419+
$loadAction = function () {
420+
return false;
421+
};
422+
423+
$collectAction = \Closure::fromCallable([$this, 'readData']);
424+
$saveAction = \Closure::fromCallable([$this, 'cacheData']);
425+
$cleanAction = \Closure::fromCallable([$this, 'cleanCacheAction']);
426+
427+
$this->lockQuery->lockedLoadData(
428+
self::$lockName,
429+
$loadAction,
430+
$collectAction,
431+
$saveAction,
432+
$cleanAction,
427433
true
428434
);
429435
}

app/code/Magento/Config/etc/di.xml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,18 @@
9090
<argument name="preProcessor" xsi:type="object">Magento\Framework\App\Config\PreProcessorComposite</argument>
9191
<argument name="serializer" xsi:type="object">Magento\Framework\Serialize\Serializer\Serialize</argument>
9292
<argument name="reader" xsi:type="object">Magento\Config\App\Config\Type\System\Reader\Proxy</argument>
93-
<argument name="locker" xsi:type="object">Magento\Framework\Lock\Backend\Cache</argument>
93+
<argument name="lockQuery" xsi:type="object">systemConfigQueryLocker</argument>
9494
</arguments>
9595
</type>
96+
97+
<virtualType name="systemConfigQueryLocker" type="Magento\Framework\Cache\Lock\Query">
98+
<arguments>
99+
<argument name="locker" xsi:type="object">Magento\Framework\Lock\Backend\Cache</argument>
100+
<argument name="lockTimeout" xsi:type="number">42</argument>
101+
<argument name="delayTimeout" xsi:type="number">100000</argument>
102+
</arguments>
103+
</virtualType>
104+
96105
<type name="Magento\Config\App\Config\Type\System\Reader">
97106
<arguments>
98107
<argument name="source" xsi:type="object">systemConfigSourceAggregated</argument>

app/etc/di.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@
129129
<preference for="Magento\Framework\Encryption\EncryptorInterface" type="Magento\Framework\Encryption\Encryptor" />
130130
<preference for="Magento\Framework\Filter\Encrypt\AdapterInterface" type="Magento\Framework\Filter\Encrypt\Basic" />
131131
<preference for="Magento\Framework\Cache\ConfigInterface" type="Magento\Framework\Cache\Config" />
132+
<preference for="Magento\Framework\Cache\LockQueryInterface" type="Magento\Framework\Cache\Lock\Query" />
132133
<preference for="Magento\Framework\View\Asset\MergeStrategyInterface" type="Magento\Framework\View\Asset\MergeStrategy\Direct" />
133134
<preference for="Magento\Framework\App\ViewInterface" type="Magento\Framework\App\View" />
134135
<preference for="Magento\Framework\Data\Collection\EntityFactoryInterface" type="Magento\Framework\Data\Collection\EntityFactory" />
@@ -1757,4 +1758,11 @@
17571758
</argument>
17581759
</arguments>
17591760
</type>
1761+
<type name="Magento\Framework\Cache\Lock\Query">
1762+
<arguments>
1763+
<argument name="locker" xsi:type="object">Magento\Framework\Lock\Backend\Cache</argument>
1764+
<argument name="lockTimeout" xsi:type="number">10</argument>
1765+
<argument name="delayTimeout" xsi:type="number">50000</argument>
1766+
</arguments>
1767+
</type>
17601768
</config>

dev/tests/integration/testsuite/Magento/Backend/Block/Widget/Form/ContainerTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public function testGetFormHtml()
3030
$expectedHtml = '<b>html</b>';
3131
$this->assertNotEquals($expectedHtml, $block->getFormHtml());
3232
$form->setText($expectedHtml);
33-
$this->assertEquals($expectedHtml, $block->getFormHtml());
33+
$this->assertEquals('', $block->getFormHtml());
3434
}
3535

3636
public function testPseudoConstruct()

dev/tests/static/testsuite/Magento/Test/Php/_files/phpcpd/blacklist/common.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,3 +212,4 @@ Magento/Elasticsearch6/Model/Client
212212
Magento/CatalogSearch/Model/ResourceModel/Fulltext
213213
Magento/Elasticsearch/Model/Layer/Search
214214
Magento/Elasticsearch/Model/Adapter/FieldMapper/Product/FieldProvider/FieldName/Resolver
215+
Magento/Config/App/Config/Type

0 commit comments

Comments
 (0)