Skip to content

Commit 78ca274

Browse files
authored
Merge pull request #2731 from magento-performance/MAGETWO-64467
### Stories * [MAGETWO-91869](https://jira.corp.magento.com/browse/MAGETWO-91869) [Indexer optimizations][Base Implementation] Tables sharding / segmentation for price indexer * [MAGETWO-64467](https://jira.corp.magento.com/browse/MAGETWO-64467) [Indexer optimizations] Tables sharding / segmentation for price indexer
2 parents 8405bd2 + 6c78b57 commit 78ca274

File tree

64 files changed

+4456
-301
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+4456
-301
lines changed
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
namespace Magento\Catalog\Console\Command;
7+
8+
use Magento\Catalog\Model\Indexer\Product\Price\DimensionModeConfiguration;
9+
use Symfony\Component\Console\Input\InputInterface;
10+
use Symfony\Component\Console\Output\OutputInterface;
11+
use Symfony\Component\Console\Input\InputOption;
12+
use Symfony\Component\Console\Input\InputArgument;
13+
use Magento\Framework\Exception\LocalizedException;
14+
use Magento\Indexer\Console\Command\AbstractIndexerCommand;
15+
use Magento\Framework\App\ObjectManagerFactory;
16+
use Magento\Catalog\Model\Indexer\Product\Price\ModeSwitcher;
17+
use Magento\Framework\App\Config\ScopeConfigInterface;
18+
use Magento\Framework\App\Config\ConfigResource\ConfigInterface;
19+
use Magento\Framework\App\Cache\TypeListInterface;
20+
21+
/**
22+
* Command to change price indexer dimensions mode
23+
*
24+
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
25+
*/
26+
class PriceIndexerDimensionsModeSetCommand extends AbstractIndexerCommand
27+
{
28+
const INPUT_KEY_MODE = 'mode';
29+
30+
/**
31+
* ScopeConfigInterface
32+
*
33+
* @var ScopeConfigInterface
34+
*/
35+
private $configReader;
36+
37+
/**
38+
* ConfigInterface
39+
*
40+
* @var ConfigInterface
41+
*/
42+
private $configWriter;
43+
44+
/**
45+
* TypeListInterface
46+
*
47+
* @var TypeListInterface
48+
*/
49+
private $cacheTypeList;
50+
51+
/**
52+
* ModeSwitcher
53+
*
54+
* @var ModeSwitcher
55+
*/
56+
private $modeSwitcher;
57+
58+
/**
59+
* @param ObjectManagerFactory $objectManagerFactory
60+
* @param ScopeConfigInterface $configReader
61+
* @param ConfigInterface $configWriter
62+
* @param TypeListInterface $cacheTypeList
63+
* @param ModeSwitcher $modeSwitcher
64+
*/
65+
public function __construct(
66+
ObjectManagerFactory $objectManagerFactory,
67+
ScopeConfigInterface $configReader,
68+
ConfigInterface $configWriter,
69+
TypeListInterface $cacheTypeList,
70+
ModeSwitcher $modeSwitcher
71+
) {
72+
$this->configReader = $configReader;
73+
$this->configWriter = $configWriter;
74+
$this->cacheTypeList = $cacheTypeList;
75+
$this->modeSwitcher = $modeSwitcher;
76+
parent::__construct($objectManagerFactory);
77+
}
78+
79+
/**
80+
* {@inheritdoc}
81+
*/
82+
protected function configure()
83+
{
84+
$this->setName('indexer:set-dimensions-mode:catalog_product_price')
85+
->setDescription('Set Indexer Dimensions Mode')
86+
->setDefinition($this->getInputList());
87+
88+
parent::configure();
89+
}
90+
91+
/**
92+
* {@inheritdoc}
93+
*/
94+
protected function execute(InputInterface $input, OutputInterface $output)
95+
{
96+
$errors = $this->validate($input);
97+
98+
if ($errors) {
99+
throw new \InvalidArgumentException(implode(PHP_EOL, $errors));
100+
}
101+
102+
$returnValue = \Magento\Framework\Console\Cli::RETURN_SUCCESS;
103+
104+
$indexer = $this->getObjectManager()->get(\Magento\Indexer\Model\Indexer::class);
105+
$indexer->load(\Magento\Catalog\Model\Indexer\Product\Price\Processor::INDEXER_ID);
106+
107+
try {
108+
$currentMode = $input->getArgument(self::INPUT_KEY_MODE);
109+
$previousMode = $this->configReader->getValue(ModeSwitcher::XML_PATH_PRICE_DIMENSIONS_MODE) ?:
110+
DimensionModeConfiguration::DIMENSION_NONE;
111+
112+
if ($previousMode !== $currentMode) {
113+
//Create new tables and move data
114+
$this->modeSwitcher->createTables($currentMode);
115+
$this->modeSwitcher->moveData($currentMode, $previousMode);
116+
117+
//Change config options
118+
$this->configWriter->saveConfig(ModeSwitcher::XML_PATH_PRICE_DIMENSIONS_MODE, $currentMode);
119+
$this->cacheTypeList->cleanType('config');
120+
$indexer->invalidate();
121+
122+
//Delete old tables
123+
$this->modeSwitcher->dropTables($previousMode);
124+
125+
$output->writeln(
126+
'Dimensions mode for indexer ' . $indexer->getTitle() . ' was changed from \''
127+
. $previousMode . '\' to \'' . $currentMode . '\''
128+
);
129+
} else {
130+
$output->writeln('Dimensions mode for indexer ' . $indexer->getTitle() . ' has not been changed');
131+
}
132+
} catch (LocalizedException $e) {
133+
$output->writeln($e->getMessage() . PHP_EOL);
134+
// we must have an exit code higher than zero to indicate something was wrong
135+
$returnValue = \Magento\Framework\Console\Cli::RETURN_FAILURE;
136+
} catch (\Exception $e) {
137+
$output->writeln($indexer->getTitle() . " indexer process unknown error:" . PHP_EOL);
138+
$output->writeln($e->getMessage() . PHP_EOL);
139+
// we must have an exit code higher than zero to indicate something was wrong
140+
$returnValue = \Magento\Framework\Console\Cli::RETURN_FAILURE;
141+
}
142+
143+
return $returnValue;
144+
}
145+
146+
/**
147+
* Get list of arguments for the command
148+
*
149+
* @return InputOption[]
150+
*/
151+
public function getInputList(): array
152+
{
153+
$modeOptions[] = new InputArgument(
154+
self::INPUT_KEY_MODE,
155+
InputArgument::REQUIRED,
156+
'Indexer dimensions mode ['. DimensionModeConfiguration::DIMENSION_NONE
157+
. '|' . DimensionModeConfiguration::DIMENSION_WEBSITE
158+
. '|' . DimensionModeConfiguration::DIMENSION_CUSTOMER_GROUP
159+
. '|' . DimensionModeConfiguration::DIMENSION_WEBSITE_AND_CUSTOMER_GROUP .']'
160+
);
161+
return $modeOptions;
162+
}
163+
164+
/**
165+
* Check if all admin options are provided
166+
*
167+
* @param InputInterface $input
168+
* @return string[]
169+
*/
170+
public function validate(InputInterface $input): array
171+
{
172+
$errors = [];
173+
174+
$acceptedModeValues = ' Accepted values for ' . self::INPUT_KEY_MODE . ' are \''
175+
. DimensionModeConfiguration::DIMENSION_NONE . '\', \''
176+
. DimensionModeConfiguration::DIMENSION_WEBSITE . '\', \''
177+
. DimensionModeConfiguration::DIMENSION_CUSTOMER_GROUP . '\', \''
178+
. DimensionModeConfiguration::DIMENSION_WEBSITE_AND_CUSTOMER_GROUP . '\'';
179+
180+
$inputMode = $input->getArgument(self::INPUT_KEY_MODE);
181+
if (!$inputMode) {
182+
$errors[] = 'Missing argument \'' . self::INPUT_KEY_MODE .'\'.' . $acceptedModeValues;
183+
} elseif (!in_array(
184+
$inputMode,
185+
[
186+
DimensionModeConfiguration::DIMENSION_NONE,
187+
DimensionModeConfiguration::DIMENSION_WEBSITE,
188+
DimensionModeConfiguration::DIMENSION_CUSTOMER_GROUP,
189+
DimensionModeConfiguration::DIMENSION_WEBSITE_AND_CUSTOMER_GROUP
190+
]
191+
)) {
192+
$errors[] = $acceptedModeValues;
193+
}
194+
return $errors;
195+
}
196+
}

app/code/Magento/Catalog/Model/Indexer/Category/Product/TableMaintainer.php

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,11 @@
1111
use Magento\Framework\Search\Request\Dimension;
1212
use Magento\Framework\DB\Adapter\AdapterInterface;
1313
use Magento\Catalog\Model\Indexer\Category\Product\AbstractAction;
14-
use Magento\Framework\Indexer\ScopeResolver\IndexScopeResolver as TableResolver;
14+
use Magento\Framework\Search\Request\IndexScopeResolverInterface as TableResolver;
1515

16+
/**
17+
* Class encapsulate logic of work with tables per store in Category Product indexer
18+
*/
1619
class TableMaintainer
1720
{
1821
/**
@@ -88,6 +91,8 @@ private function getTable($table)
8891
* @param string $newTableName
8992
*
9093
* @return void
94+
*
95+
* @throws \Zend_Db_Exception
9196
*/
9297
private function createTable($mainTableName, $newTableName)
9398
{
@@ -132,6 +137,8 @@ public function getMainTable(int $storeId)
132137
* @param $storeId
133138
*
134139
* @return void
140+
*
141+
* @throws \Zend_Db_Exception
135142
*/
136143
public function createTablesForStore(int $storeId)
137144
{
@@ -202,9 +209,14 @@ public function createMainTmpTable(int $storeId)
202209
* @param $storeId
203210
*
204211
* @return string
212+
*
213+
* @throws \Magento\Framework\Exception\NoSuchEntityException
205214
*/
206215
public function getMainTmpTable(int $storeId)
207216
{
217+
if (!isset($this->mainTmpTable[$storeId])) {
218+
throw new \Magento\Framework\Exception\NoSuchEntityException('Temporary table does not exist');
219+
}
208220
return $this->mainTmpTable[$storeId];
209221
}
210222
}

0 commit comments

Comments
 (0)