Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/develop' into pr-sprint-15
Browse files Browse the repository at this point in the history
  • Loading branch information
melnikovi committed Apr 25, 2017
2 parents e4d1952 + c3cb46a commit 065d18b
Show file tree
Hide file tree
Showing 20 changed files with 1,018 additions and 98 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,24 @@ abstract class AbstractAction
protected $_eavDecimalFactory;

/**
* @var array
*/
private $frontendResources;

/**
* AbstractAction constructor.
* @param \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\DecimalFactory $eavDecimalFactory
* @param \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\SourceFactory $eavSourceFactory
* @param array $frontendResources
*/
public function __construct(
\Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\DecimalFactory $eavDecimalFactory,
\Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\SourceFactory $eavSourceFactory
\Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\SourceFactory $eavSourceFactory,
$frontendResources = []
) {
$this->_eavDecimalFactory = $eavDecimalFactory;
$this->_eavSourceFactory = $eavSourceFactory;
$this->frontendResources = $frontendResources;
}

/**
Expand Down Expand Up @@ -84,16 +93,67 @@ public function getIndexer($type)
* Reindex entities
*
* @param null|array|int $ids
* @throws \Exception
* @return void
*/
public function reindex($ids = null)
{
foreach ($this->getIndexers() as $indexer) {
foreach ($this->getIndexers() as $type => $indexer) {
if ($ids === null) {
$indexer->reindexAll();
} else {
if (!is_array($ids)) {
$ids = [$ids];
}
$ids = $this->processRelations($indexer, $ids);
$indexer->reindexEntities($ids);
$resource = isset($this->frontendResources[$type])
? $this->frontendResources[$type]
: $this->frontendResources['default'];
$destinationTable = $resource->getMainTable();
$this->syncData($indexer, $destinationTable, $ids);
}
}
}

/**
* Synchronize data between index storage and original storage
*
* @param \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\AbstractEav $indexer
* @param string $destinationTable
* @param array $ids
* @throws \Exception
* @return void
*/
protected function syncData($indexer, $destinationTable, $ids)
{
$connection = $indexer->getConnection();
$connection->beginTransaction();
try {
// remove old index
$where = $connection->quoteInto('entity_id IN(?)', $ids);
$connection->delete($destinationTable, $where);
// insert new index
$indexer->insertFromTable($indexer->getIdxTable(), $destinationTable);
$connection->commit();
} catch (\Exception $e) {
$connection->rollBack();
throw $e;
}
}

/**
* Retrieve product relations by children and parent
*
* @param \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\AbstractEav $indexer
* @param array $ids
*
* @return $ids
*/
protected function processRelations($indexer, $ids)
{
$parentIds = $indexer->getRelationsByChild($ids);
$childIds = $indexer->getRelationsByParent($ids);
return array_unique(array_merge($ids, $childIds, $parentIds));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,49 @@
*/
class Full extends \Magento\Catalog\Model\Indexer\Product\Eav\AbstractAction
{
/**
* @var \Magento\Framework\EntityManager\MetadataPool
*/
private $metadataPool;

/**
* @var \Magento\Framework\Indexer\BatchProviderInterface
*/
private $batchProvider;

/**
* @var \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\BatchSizeCalculator
*/
private $batchSizeCalculator;

/**
* @param \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\DecimalFactory $eavDecimalFactory
* @param \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\SourceFactory $eavSourceFactory
* @param \Magento\Framework\EntityManager\MetadataPool|null $metadataPool
* @param \Magento\Framework\Indexer\BatchProviderInterface|null $batchProvider
* @param \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\BatchSizeCalculator $batchSizeCalculator
* @param array $frontendResources
*/
public function __construct(
\Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\DecimalFactory $eavDecimalFactory,
\Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\SourceFactory $eavSourceFactory,
\Magento\Framework\EntityManager\MetadataPool $metadataPool = null,
\Magento\Framework\Indexer\BatchProviderInterface $batchProvider = null,
\Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\BatchSizeCalculator $batchSizeCalculator = null,
array $frontendResources = []
) {
parent::__construct($eavDecimalFactory, $eavSourceFactory, $frontendResources);
$this->metadataPool = $metadataPool ?: \Magento\Framework\App\ObjectManager::getInstance()->get(
\Magento\Framework\EntityManager\MetadataPool::class
);
$this->batchProvider = $batchProvider ?: \Magento\Framework\App\ObjectManager::getInstance()->get(
\Magento\Framework\Indexer\BatchProviderInterface::class
);
$this->batchSizeCalculator = $batchSizeCalculator ?: \Magento\Framework\App\ObjectManager::getInstance()->get(
\Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\BatchSizeCalculator::class
);
}

/**
* Execute Full reindex
*
Expand All @@ -21,9 +64,58 @@ class Full extends \Magento\Catalog\Model\Indexer\Product\Eav\AbstractAction
public function execute($ids = null)
{
try {
$this->reindex();
foreach ($this->getIndexers() as $indexerName => $indexer) {
$connection = $indexer->getConnection();
$mainTable = $indexer->getMainTable();
$connection->truncateTable($mainTable);
$entityMetadata = $this->metadataPool->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class);
$batches = $this->batchProvider->getBatches(
$connection,
$entityMetadata->getEntityTable(),
$entityMetadata->getIdentifierField(),
$this->batchSizeCalculator->estimateBatchSize($connection, $indexerName)
);

foreach ($batches as $batch) {
/** @var \Magento\Framework\DB\Select $select */
$select = $connection->select();
$select->distinct(true);
$select->from(['e' => $entityMetadata->getEntityTable()], $entityMetadata->getIdentifierField());
$entityIds = $this->batchProvider->getBatchIds($connection, $select, $batch);
if (!empty($entityIds)) {
$indexer->reindexEntities($this->processRelations($indexer, $entityIds));
$this->syncData($indexer, $mainTable);
}
}
}
} catch (\Exception $e) {
throw new \Magento\Framework\Exception\LocalizedException(__($e->getMessage()), $e);
}
}

/**
* @inheritdoc
*/
protected function syncData($indexer, $destinationTable, $ids = null)
{
$connection = $indexer->getConnection();
$connection->beginTransaction();
try {
$sourceTable = $indexer->getIdxTable();
$sourceColumns = array_keys($connection->describeTable($sourceTable));
$targetColumns = array_keys($connection->describeTable($destinationTable));
$select = $connection->select()->from($sourceTable, $sourceColumns);
$query = $connection->insertFromSelect(
$select,
$destinationTable,
$targetColumns,
\Magento\Framework\DB\Adapter\AdapterInterface::INSERT_ON_DUPLICATE
);
$connection->query($query);
$connection->commit();
} catch (\Exception $e) {
$connection->rollBack();
throw $e;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -94,41 +94,11 @@ public function reindexAll()
*/
public function reindexEntities($processIds)
{
$connection = $this->getConnection();

$this->clearTemporaryIndexTable();

if (!is_array($processIds)) {
$processIds = [$processIds];
}

$parentIds = $this->getRelationsByChild($processIds);
if ($parentIds) {
$processIds = array_unique(array_merge($processIds, $parentIds));
}
$childIds = $this->getRelationsByParent($processIds);
if ($childIds) {
$processIds = array_unique(array_merge($processIds, $childIds));
}

$this->_prepareIndex($processIds);
$this->_prepareRelationIndex($processIds);
$this->_removeNotVisibleEntityFromIndex();

$connection->beginTransaction();
try {
// remove old index
$where = $connection->quoteInto('entity_id IN(?)', $processIds);
$mainTable = $this->frontendResource->getMainTable();
$connection->delete($this->frontendResource->getMainTable(), $where);

// insert new index
$this->insertFromTable($this->getIdxTable(), $mainTable);
$connection->commit();
} catch (\Exception $e) {
$connection->rollBack();
throw $e;
}
return $this;
}

Expand Down Expand Up @@ -238,7 +208,8 @@ protected function _prepareRelationIndexSelect($parentIds = null)
]
);
if ($parentIds !== null) {
$select->where('e.entity_id IN(?)', $parentIds);
$ids = implode(',', array_map('intval', $parentIds));
$select->where("e.entity_id IN({$ids})");
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/

namespace Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav;

use Magento\Framework\DB\Adapter\AdapterInterface;
use Magento\Framework\Exception\NoSuchEntityException;

/**
* Composite batch size calculator for EAV related indexers.
*
* Can be configured to provide batch sizes for different indexer types.
*/
class BatchSizeCalculator
{
/**
* @var array
*/
private $batchSizes;

/**
* @var \Magento\Framework\Indexer\BatchSizeManagement[]
*/
private $batchSizeManagers;

/**
* @param array $batchSizes preferable sizes (number of rows in batch) of batches per index type
* @param array $batchSizeManagers batch managers per index type
*/
public function __construct(
array $batchSizes,
array $batchSizeManagers
) {
$this->batchSizes = $batchSizes;
$this->batchSizeManagers = $batchSizeManagers;
}

/**
* Estimate batch size and ensure that database will be able to handle it properly.
*
* @param AdapterInterface $connection
* @param string $indexerTypeId unique identifier of the indexer
* @return int estimated batch size
* @throws NoSuchEntityException thrown if indexer identifier is not recognized
*/
public function estimateBatchSize(
AdapterInterface $connection,
$indexerTypeId
) {
if (!isset($this->batchSizes[$indexerTypeId])) {
throw NoSuchEntityException::singleField('indexTypeId', $indexerTypeId);
}
$this->batchSizeManagers[$indexerTypeId]->ensureBatchSize($connection, $this->batchSizes[$indexerTypeId]);

return $this->batchSizes[$indexerTypeId];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/

namespace Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav;

use Magento\Store\Api\StoreManagementInterface;
use Magento\Framework\Indexer\IndexTableRowSizeEstimatorInterface;
use Magento\Framework\EntityManager\MetadataPool;
use Magento\Catalog\Api\Data\ProductInterface;

/**
* Estimator of the EAV decimal index table row size.
*
* Estimates the amount of memory required to store the index data of the product
* with the highest number of attributes/values.
*
* Can be used with batch size manager to ensure that the batch will be handled correctly by the database.
* @see \Magento\Framework\Indexer\BatchSizeManagement
*/
class DecimalRowSizeEstimator implements IndexTableRowSizeEstimatorInterface
{
/**
* @var Decimal
*/
private $indexerResource;

/**
* @var StoreManagementInterface
*/
private $storeManagement;

/**
* @var MetadataPool
*/
private $metadataPool;

/**
* @param StoreManagementInterface $storeManagement
* @param Decimal $indexerResource
* @param MetadataPool $metadataPool
*/
public function __construct(
StoreManagementInterface $storeManagement,
Decimal $indexerResource,
MetadataPool $metadataPool
) {
$this->storeManagement = $storeManagement;
$this->indexerResource = $indexerResource;
$this->metadataPool = $metadataPool;
}

/**
* @inheritdoc
*/
public function estimateRowSize()
{
$connection = $this->indexerResource->getConnection();
$entityIdField = $this->metadataPool->getMetadata(ProductInterface::class)->getLinkField();

$valueSelect = $connection->select();
$valueSelect->from(
['value_table' => $this->indexerResource->getTable('catalog_product_entity_decimal')],
['count' => new \Zend_Db_Expr('count(value_table.value_id)')]
);
$valueSelect->group([$entityIdField, 'store_id']);

$maxSelect = $connection->select();
$maxSelect->from(
['max_value' => $valueSelect],
['count' => new \Zend_Db_Expr('MAX(count)')]
);
$maxRowsPerStore = $connection->fetchOne($maxSelect);

return ceil($maxRowsPerStore * $this->storeManagement->getCount() * 500);
}
}
Loading

0 comments on commit 065d18b

Please sign in to comment.