diff --git a/app/code/Magento/CatalogInventory/Model/Indexer/Stock/AbstractAction.php b/app/code/Magento/CatalogInventory/Model/Indexer/Stock/AbstractAction.php
index 1e7c800ea1c38a3275760dc44216f82559820217..85fee62eb430371836608c7baae23182d57f62f3 100644
--- a/app/code/Magento/CatalogInventory/Model/Indexer/Stock/AbstractAction.php
+++ b/app/code/Magento/CatalogInventory/Model/Indexer/Stock/AbstractAction.php
@@ -10,6 +10,7 @@ namespace Magento\CatalogInventory\Model\Indexer\Stock;
 
 use Magento\Framework\App\ObjectManager;
 use Magento\Framework\App\ResourceConnection;
+use Magento\Framework\EntityManager\MetadataPool;
 
 /**
  * Abstract action reindex class
@@ -70,25 +71,33 @@ abstract class AbstractAction
      */
     private $cacheCleaner;
 
+    /**
+     * @var MetadataPool
+     */
+    private $metadataPool;
+
     /**
      * @param ResourceConnection $resource
      * @param \Magento\CatalogInventory\Model\ResourceModel\Indexer\StockFactory $indexerFactory
      * @param \Magento\Catalog\Model\Product\Type $catalogProductType
      * @param \Magento\Framework\Indexer\CacheContext $cacheContext
      * @param \Magento\Framework\Event\ManagerInterface $eventManager
+     * @param MetadataPool|null $metadataPool
      */
     public function __construct(
         ResourceConnection $resource,
         \Magento\CatalogInventory\Model\ResourceModel\Indexer\StockFactory $indexerFactory,
         \Magento\Catalog\Model\Product\Type $catalogProductType,
         \Magento\Framework\Indexer\CacheContext $cacheContext,
-        \Magento\Framework\Event\ManagerInterface $eventManager
+        \Magento\Framework\Event\ManagerInterface $eventManager,
+        MetadataPool $metadataPool = null
     ) {
         $this->_resource = $resource;
         $this->_indexerFactory = $indexerFactory;
         $this->_catalogProductType = $catalogProductType;
         $this->cacheContext = $cacheContext;
         $this->eventManager = $eventManager;
+        $this->metadataPool = $metadataPool ?: ObjectManager::getInstance()->get(MetadataPool::class);
     }
 
     /**
@@ -154,10 +163,15 @@ abstract class AbstractAction
     public function getRelationsByChild($childIds)
     {
         $connection = $this->_getConnection();
-        $select = $connection->select()
-            ->from($this->_getTable('catalog_product_relation'), 'parent_id')
-            ->where('child_id IN(?)', $childIds);
-
+        $linkField = $this->metadataPool->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class)
+            ->getLinkField();
+        $select = $connection->select()->from(
+            ['cpe' => $this->_getTable('catalog_product_entity')],
+            'entity_id'
+        )->join(
+            ['relation' => $this->_getTable('catalog_product_relation')],
+            'relation.parent_id = cpe.' . $linkField
+        )->where('child_id IN(?)', $childIds);
         return $connection->fetchCol($select);
     }
 
@@ -230,7 +244,8 @@ abstract class AbstractAction
         if (!is_array($productIds)) {
             $productIds = [$productIds];
         }
-
+        $parentIds = $this->getRelationsByChild($productIds);
+        $productIds = $parentIds ? array_unique(array_merge($parentIds, $productIds)) : $productIds;
         $this->getCacheCleaner()->clean($productIds, function () use ($productIds) {
             $this->doReindex($productIds);
         });
@@ -248,13 +263,10 @@ abstract class AbstractAction
     {
         $connection = $this->_getConnection();
 
-        $parentIds = $this->getRelationsByChild($productIds);
-        $processIds = $parentIds ? array_merge($parentIds, $productIds) : $productIds;
-
         // retrieve product types by processIds
         $select = $connection->select()
             ->from($this->_getTable('catalog_product_entity'), ['entity_id', 'type_id'])
-            ->where('entity_id IN(?)', $processIds);
+            ->where('entity_id IN(?)', $productIds);
         $pairs = $connection->fetchPairs($select);
 
         $byType = [];
diff --git a/app/code/Magento/CatalogInventory/Model/Plugin/ReindexUpdatedProducts.php b/app/code/Magento/CatalogInventory/Model/Plugin/ReindexUpdatedProducts.php
new file mode 100644
index 0000000000000000000000000000000000000000..f10afcd4ea329212d32cbf4f4d4fd275d0d1b396
--- /dev/null
+++ b/app/code/Magento/CatalogInventory/Model/Plugin/ReindexUpdatedProducts.php
@@ -0,0 +1,46 @@
+<?php
+/**
+ * Copyright © Magento, Inc. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\CatalogInventory\Model\Plugin;
+
+use Magento\Catalog\Model\Product\Action as ProductAction;
+
+/**
+ * Plugin for Magento\Catalog\Model\Product\Action
+ */
+class ReindexUpdatedProducts
+{
+    /**
+     * @var \Magento\CatalogInventory\Model\Indexer\Stock\Processor
+     */
+    private $indexerProcessor;
+
+    /**
+     * @param \Magento\CatalogInventory\Model\Indexer\Stock\Processor  $indexerProcessor
+     */
+    public function __construct(\Magento\CatalogInventory\Model\Indexer\Stock\Processor $indexerProcessor)
+    {
+        $this->indexerProcessor = $indexerProcessor;
+    }
+
+    /**
+     * Reindex on product attribute mass change
+     *
+     * @param ProductAction $subject
+     * @param ProductAction $action
+     * @param array $productIds
+     * @return ProductAction
+     *
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     */
+    public function afterUpdateAttributes(
+        ProductAction $subject,
+        ProductAction $action,
+        $productIds
+    ) {
+        $this->indexerProcessor->reindexList(array_unique($productIds));
+        return $action;
+    }
+}
diff --git a/app/code/Magento/CatalogInventory/etc/di.xml b/app/code/Magento/CatalogInventory/etc/di.xml
index 04935b11ce02ba396b6c1c65c9e0a57f8f622b3c..65bc27712142910533ac99d069350f41bf673dec 100644
--- a/app/code/Magento/CatalogInventory/etc/di.xml
+++ b/app/code/Magento/CatalogInventory/etc/di.xml
@@ -78,6 +78,9 @@
     <type name="Magento\Catalog\Model\Product">
         <plugin name="catalogInventoryAfterLoad" type="Magento\CatalogInventory\Model\Plugin\AfterProductLoad"/>
     </type>
+    <type name="Magento\Catalog\Model\Product\Action">
+        <plugin name="ReindexUpdatedProducts" type="Magento\CatalogInventory\Model\Plugin\ReindexUpdatedProducts"/>
+    </type>
     <type name="Magento\CatalogInventory\Setup\UpgradeData">
         <arguments>
             <argument name="indexerProcessor" xsi:type="object">Magento\CatalogInventory\Model\Indexer\Stock\Processor</argument>
diff --git a/app/code/Magento/UrlRewrite/Block/Edit.php b/app/code/Magento/UrlRewrite/Block/Edit.php
index 7311efeb114c1e0ba10207885080118fca7e74af..baee8af893083ef99331549bd1ac54fadd102e73 100644
--- a/app/code/Magento/UrlRewrite/Block/Edit.php
+++ b/app/code/Magento/UrlRewrite/Block/Edit.php
@@ -118,7 +118,7 @@ class Edit extends \Magento\Backend\Block\Widget\Container
             'reset',
             [
                 'label' => __('Reset'),
-                'onclick' => '$(\'edit_form\').reset()',
+                'onclick' => 'location.reload();',
                 'class' => 'scalable',
                 'level' => -1
             ]
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/ActionTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/ActionTest.php
index 90825ab573d09210f4029fc8d395aae3f7165f5a..39905aeae10f5d5410f7fa7541b15063ca8b5cfc 100644
--- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/ActionTest.php
+++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/ActionTest.php
@@ -84,6 +84,73 @@ class ActionTest extends \PHPUnit\Framework\TestCase
         }
     }
 
+    /**
+     * @magentoDataFixture Magento/ConfigurableProduct/_files/product_configurable.php
+     * @magentoAppArea adminhtml
+     * @param string $status
+     * @param string $productsCount
+     * @dataProvider updateAttributesDataProvider
+     */
+    public function testUpdateAttributes($status, $productsCount)
+    {
+        /** @var \Magento\Framework\Indexer\IndexerRegistry $indexerRegistry */
+        $indexerRegistry = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()
+            ->get(\Magento\Framework\Indexer\IndexerRegistry::class);
+        $indexerRegistry->get(Fulltext::INDEXER_ID)->setScheduled(false);
+
+        /** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */
+        $productRepository = $this->objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class);
+
+        /** @var \Magento\Catalog\Model\Product $product */
+        $product = $productRepository->get('configurable');
+        $productAttributesOptions = $product->getExtensionAttributes()->getConfigurableProductLinks();
+        $attrData = ['status' => $status];
+        $configurableOptionsId = [];
+        if (isset($productAttributesOptions)) {
+            foreach ($productAttributesOptions as $configurableOption) {
+                $configurableOptionsId[] = $configurableOption;
+            }
+        }
+        $this->action->updateAttributes($configurableOptionsId, $attrData, $product->getStoreId());
+
+        $categoryFactory = $this->objectManager->create(\Magento\Catalog\Model\CategoryFactory::class);
+        /** @var \Magento\Catalog\Block\Product\ListProduct $listProduct */
+        $listProduct = $this->objectManager->create(\Magento\Catalog\Block\Product\ListProduct::class);
+        $category = $categoryFactory->create()->load(2);
+        $layer = $listProduct->getLayer();
+        $layer->setCurrentCategory($category);
+        $productCollection = $layer->getProductCollection();
+        $productCollection->joinField(
+            'qty',
+            'cataloginventory_stock_status',
+            'qty',
+            'product_id=entity_id',
+            '{{table}}.stock_id=1',
+            'left'
+        );
+
+        $this->assertEquals($productsCount, $productCollection->count());
+    }
+
+    /**
+     * DataProvider for testUpdateAttributes
+     *
+     * @return array
+     */
+    public function updateAttributesDataProvider()
+    {
+        return [
+            [
+                'status' => 2,
+                'expected_count' => 0
+            ],
+            [
+                'status' => 1,
+                'expected_count' => 1
+            ],
+        ];
+    }
+
     public static function tearDownAfterClass()
     {
         /** @var \Magento\Framework\Indexer\IndexerRegistry $indexerRegistry */
diff --git a/dev/tests/integration/testsuite/Magento/Framework/UrlTest.php b/dev/tests/integration/testsuite/Magento/Framework/UrlTest.php
index b687232bcaac6ec4a858858f62aa614fb34c119e..9d1d8761a16a7c4ba58f7e0362dd3999b1db9d9c 100644
--- a/dev/tests/integration/testsuite/Magento/Framework/UrlTest.php
+++ b/dev/tests/integration/testsuite/Magento/Framework/UrlTest.php
@@ -6,38 +6,37 @@
 namespace Magento\Framework;
 
 use Zend\Stdlib\Parameters;
+use Magento\TestFramework\Helper\Bootstrap;
 
 class UrlTest extends \PHPUnit\Framework\TestCase
 {
     /**
      * @var \Magento\Framework\UrlInterface
      */
-    protected $_model;
+    protected $model;
 
     protected function setUp()
     {
-        $this->_model = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-            \Magento\Framework\Url::class
-        );
+        $this->model = Bootstrap::getObjectManager()->create(\Magento\Framework\Url::class);
     }
 
     public function testSetGetUseSession()
     {
-        $this->assertTrue((bool)$this->_model->getUseSession());
-        $this->_model->setUseSession(false);
-        $this->assertFalse($this->_model->getUseSession());
+        $this->assertTrue((bool)$this->model->getUseSession());
+        $this->model->setUseSession(false);
+        $this->assertFalse($this->model->getUseSession());
     }
 
     public function testSetRouteFrontName()
     {
         $value = 'route';
-        $this->_model->setRouteFrontName($value);
-        $this->assertEquals($value, $this->_model->getData('route_front_name'));
+        $this->model->setRouteFrontName($value);
+        $this->assertEquals($value, $this->model->getData('route_front_name'));
     }
 
     public function testGetConfigData()
     {
-        $this->assertEquals('http://localhost/', $this->_model->getConfigData('base_url'));
+        $this->assertEquals('http://localhost/', $this->model->getConfigData('base_url'));
     }
 
     /**
@@ -46,7 +45,7 @@ class UrlTest extends \PHPUnit\Framework\TestCase
      */
     public function testGetBaseUrlDefaults()
     {
-        $this->assertEquals('http://localhost/index.php/', $this->_model->getBaseUrl());
+        $this->assertEquals('http://localhost/index.php/', $this->model->getBaseUrl());
     }
 
     /**
@@ -56,7 +55,7 @@ class UrlTest extends \PHPUnit\Framework\TestCase
      */
     public function testGetBaseUrlSeoRewrites()
     {
-        $this->assertEquals('http://localhost/', $this->_model->getBaseUrl());
+        $this->assertEquals('http://localhost/', $this->model->getBaseUrl());
     }
 
     /**
@@ -75,10 +74,96 @@ class UrlTest extends \PHPUnit\Framework\TestCase
      */
     public function testGetBaseUrlConfigured($params, $expectedUrl)
     {
-        $actualUrl = $this->_model->getBaseUrl($params);
+        $actualUrl = $this->model->getBaseUrl($params);
         $this->assertEquals($expectedUrl, $actualUrl);
     }
 
+    /**
+     * Note: isolation flushes the URL memory cache
+     * @magentoAppIsolation enabled
+     *
+     * @magentoConfigFixture current_store web/secure/base_url http://sample.com/
+     * @magentoConfigFixture current_store web/unsecure/base_link_url http://sample.com/
+     * @magentoConfigFixture current_store web/secure/base_link_url https://sample.com/
+     * @magentoConfigFixture current_store web/secure/use_in_frontend 1
+     *
+     * @magentoAppArea frontend
+     */
+    public function testGetUnsecureUrlInSecureArea()
+    {
+        /** @var \Magento\Framework\App\Request\Http $request */
+        $request = Bootstrap::getObjectManager()->create(\Magento\Framework\App\Request\Http::class);
+        //Emulate HTTPS request
+        $request->getServer()->set('HTTPS', 'on');
+        $request->getServer()->set('SERVER_PORT', 443);
+
+        $model = Bootstrap::getObjectManager()->create(\Magento\Framework\Url::class, ['request' => $request]);
+
+        $secureUrl = $model->getUrl('some/index/controller', ['_nosid' => 1]);
+        $this->assertEquals(
+            'https://sample.com/index.php/some/index/controller/',
+            $secureUrl,
+            'Default URL in secure area is incorrect'
+        );
+
+        $secureUrl = $model->getUrl('some/index/controller', ['_secure' => true, '_nosid' => 1]);
+        $this->assertEquals(
+            'https://sample.com/index.php/some/index/controller/',
+            $secureUrl,
+            'Secure URL in secure area is incorrect'
+        );
+
+        $unsecureUrl = $model->getUrl('some/index/controller', ['_secure' => false, '_nosid' => 1]);
+        $this->assertEquals(
+            'http://sample.com/index.php/some/index/controller/',
+            $unsecureUrl,
+            'Unsecure URL in secure area is incorrect'
+        );
+    }
+
+    /**
+     * Note: isolation flushes the URL memory cache
+     * @magentoAppIsolation enabled
+     *
+     * @magentoConfigFixture current_store web/secure/base_url http://sample.com/
+     * @magentoConfigFixture current_store web/unsecure/base_link_url http://sample.com/
+     * @magentoConfigFixture current_store web/secure/base_link_url https://sample.com/
+     * @magentoConfigFixture current_store web/secure/use_in_frontend 1
+     *
+     * @magentoAppArea frontend
+     */
+    public function testGetSecureUrlInUnsecureArea()
+    {
+        /** @var \Magento\Framework\App\Request\Http $request */
+        $request = Bootstrap::getObjectManager()->create(\Magento\Framework\App\Request\Http::class);
+        //Emulate HTTPS request
+        $request->getServer()->set('HTTPS', 'off');
+        $request->getServer()->set('SERVER_PORT', 80);
+
+        $model = Bootstrap::getObjectManager()->create(\Magento\Framework\Url::class, ['request' => $request]);
+
+        $secureUrl = $model->getUrl('some/index/controller', ['_nosid' => 1]);
+        $this->assertEquals(
+            'http://sample.com/index.php/some/index/controller/',
+            $secureUrl,
+            'Default URL in unsecure area is incorrect'
+        );
+
+        $secureUrl = $model->getUrl('some/index/controller', ['_secure' => true, '_nosid' => 1]);
+        $this->assertEquals(
+            'https://sample.com/index.php/some/index/controller/',
+            $secureUrl,
+            'Secure URL in unsecure area is incorrect'
+        );
+
+        $unsecureUrl = $model->getUrl('some/index/controller', ['_secure' => false, '_nosid' => 1]);
+        $this->assertEquals(
+            'http://sample.com/index.php/some/index/controller/',
+            $unsecureUrl,
+            'Unsecure URL in unsecure area is incorrect'
+        );
+    }
+
     /**
      * Check that url type is restored to default after call getBaseUrl with type specified in params
      */
@@ -87,21 +172,21 @@ class UrlTest extends \PHPUnit\Framework\TestCase
         /**
          * Get base URL with default type
          */
-        $this->assertEquals('http://localhost/index.php/', $this->_model->getBaseUrl(), 'Incorrect link url');
+        $this->assertEquals('http://localhost/index.php/', $this->model->getBaseUrl(), 'Incorrect link url');
 
         /**
          * Set specified type
          */
-        $webUrl = $this->_model->getBaseUrl(['_type' => \Magento\Framework\UrlInterface::URL_TYPE_WEB]);
+        $webUrl = $this->model->getBaseUrl(['_type' => \Magento\Framework\UrlInterface::URL_TYPE_WEB]);
         $this->assertEquals('http://localhost/', $webUrl, 'Incorrect web url');
-        $this->assertEquals('http://localhost/index.php/', $this->_model->getBaseUrl(), 'Incorrect link url');
+        $this->assertEquals('http://localhost/index.php/', $this->model->getBaseUrl(), 'Incorrect link url');
 
         /**
          * Get url with type specified in params
          */
-        $mediaUrl = $this->_model->getBaseUrl(['_type' => \Magento\Framework\UrlInterface::URL_TYPE_MEDIA]);
+        $mediaUrl = $this->model->getBaseUrl(['_type' => \Magento\Framework\UrlInterface::URL_TYPE_MEDIA]);
         $this->assertEquals('http://localhost/pub/media/', $mediaUrl, 'Incorrect media url');
-        $this->assertEquals('http://localhost/index.php/', $this->_model->getBaseUrl(), 'Incorrect link url');
+        $this->assertEquals('http://localhost/index.php/', $this->model->getBaseUrl(), 'Incorrect link url');
     }
 
     public function getBaseUrlConfiguredDataProvider()
@@ -121,24 +206,24 @@ class UrlTest extends \PHPUnit\Framework\TestCase
 
     public function testSetGetRouteName()
     {
-        $this->_model->setRouteName('catalog');
-        $this->assertEquals('catalog', $this->_model->getRouteName());
+        $this->model->setRouteName('catalog');
+        $this->assertEquals('catalog', $this->model->getRouteName());
 
         $this->markTestIncomplete('setRouteName() logic is unclear.');
     }
 
     public function testSetGetControllerName()
     {
-        $this->_model->setControllerName('product');
-        $this->assertEquals('product', $this->_model->getControllerName());
+        $this->model->setControllerName('product');
+        $this->assertEquals('product', $this->model->getControllerName());
 
         $this->markTestIncomplete('setControllerName() logic is unclear.');
     }
 
     public function testSetGetActionName()
     {
-        $this->_model->setActionName('view');
-        $this->assertEquals('view', $this->_model->getActionName());
+        $this->model->setActionName('view');
+        $this->assertEquals('view', $this->model->getActionName());
 
         $this->markTestIncomplete('setActionName() logic is unclear.');
     }
@@ -149,21 +234,21 @@ class UrlTest extends \PHPUnit\Framework\TestCase
      */
     public function testGetRouteUrl()
     {
-        $this->assertEquals('http://localhost/index.php/', $this->_model->getRouteUrl());
+        $this->assertEquals('http://localhost/index.php/', $this->model->getRouteUrl());
         $this->assertEquals(
             'http://localhost/index.php/catalog/product/view/id/50/',
-            $this->_model->getRouteUrl('catalog/product/view', ['id' => 50])
+            $this->model->getRouteUrl('catalog/product/view', ['id' => 50])
         );
         $this->assertEquals(
             'http://localhost/index.php/fancy_uri',
-            $this->_model->getRouteUrl('core/index/index', ['_direct' => 'fancy_uri'])
+            $this->model->getRouteUrl('core/index/index', ['_direct' => 'fancy_uri'])
         );
     }
 
     public function testSetGetFragment()
     {
-        $this->_model->setFragment('value');
-        $this->assertEquals('value', $this->_model->getFragment());
+        $this->model->setFragment('value');
+        $this->assertEquals('value', $this->model->getFragment());
     }
 
     /**
@@ -172,7 +257,7 @@ class UrlTest extends \PHPUnit\Framework\TestCase
      */
     public function testGetUrl()
     {
-        $result = $this->_model->getUrl(
+        $result = $this->model->getUrl(
             'catalog/product/view',
             ['_fragment' => 'anchor', '_escape' => 1, '_query' => 'foo=bar', '_nosid' => 1, 'id' => 100]
         );
@@ -185,9 +270,9 @@ class UrlTest extends \PHPUnit\Framework\TestCase
      */
     public function testGetUrlDoesntAddQueryParamsOnConsequentCalls()
     {
-        $result = $this->_model->getUrl('catalog/product/view', ['_query' => 'foo=bar', '_nosid' => 1]);
+        $result = $this->model->getUrl('catalog/product/view', ['_query' => 'foo=bar', '_nosid' => 1]);
         $this->assertEquals('http://localhost/index.php/catalog/product/view/?foo=bar', $result);
-        $result = $this->_model->getUrl('catalog/product/view', ['_nosid' => 1]);
+        $result = $this->model->getUrl('catalog/product/view', ['_nosid' => 1]);
         $this->assertEquals('http://localhost/index.php/catalog/product/view/', $result);
     }
 
@@ -198,9 +283,9 @@ class UrlTest extends \PHPUnit\Framework\TestCase
      */
     public function testGetUrlDoesntAddFragmentOnConsequentCalls()
     {
-        $result = $this->_model->getUrl('catalog/product/view', ['_nosid' => 1, '_fragment' => 'section']);
+        $result = $this->model->getUrl('catalog/product/view', ['_nosid' => 1, '_fragment' => 'section']);
         $this->assertEquals('http://localhost/index.php/catalog/product/view/#section', $result);
-        $result = $this->_model->getUrl('catalog/product/view', ['_nosid' => 1]);
+        $result = $this->model->getUrl('catalog/product/view', ['_nosid' => 1]);
         $this->assertEquals('http://localhost/index.php/catalog/product/view/', $result);
     }
 
@@ -226,10 +311,10 @@ class UrlTest extends \PHPUnit\Framework\TestCase
         $firstExpectedUrl,
         $secondExpectedUrl
     ) {
-        $result = $this->_model->getUrl($firstCallUrl, $firstRouteParams);
+        $result = $this->model->getUrl($firstCallUrl, $firstRouteParams);
         $this->assertEquals($firstExpectedUrl, $result);
 
-        $result = $this->_model->getUrl($secondCallUrl, $secondRouteParams);
+        $result = $this->model->getUrl($secondCallUrl, $secondRouteParams);
         $this->assertEquals($secondExpectedUrl, $result);
     }
 
@@ -375,7 +460,7 @@ class UrlTest extends \PHPUnit\Framework\TestCase
 
     public function testEscape()
     {
-        $this->assertEquals('%22%27%3E%3C', $this->_model->escape('"\'><'));
+        $this->assertEquals('%22%27%3E%3C', $this->model->escape('"\'><'));
     }
 
     /**
@@ -384,7 +469,7 @@ class UrlTest extends \PHPUnit\Framework\TestCase
      */
     public function testGetDirectUrl()
     {
-        $directUrl = $this->_model->getDirectUrl('fancy_uri', ['_query' => ['foo' => 'bar']]);
+        $directUrl = $this->model->getDirectUrl('fancy_uri', ['_query' => ['foo' => 'bar']]);
         $this->assertEquals('http://localhost/index.php/fancy_uri?foo=bar', $directUrl);
     }
 
@@ -400,15 +485,15 @@ class UrlTest extends \PHPUnit\Framework\TestCase
         $sessionId = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(
             \Magento\Framework\Session\Generic::class
         )->getSessionId();
-        $sessionUrl = $this->_model->sessionUrlVar('<a href="http://example.com/?___SID=U">www.example.com</a>');
+        $sessionUrl = $this->model->sessionUrlVar('<a href="http://example.com/?___SID=U">www.example.com</a>');
         $this->assertEquals('<a href="http://example.com/?SID=' . $sessionId . '">www.example.com</a>', $sessionUrl);
     }
 
     public function testUseSessionIdForUrl()
     {
         $_SERVER['HTTP_HOST'] = 'localhost';
-        $this->assertFalse($this->_model->useSessionIdForUrl(true));
-        $this->assertFalse($this->_model->useSessionIdForUrl(false));
+        $this->assertFalse($this->model->useSessionIdForUrl(true));
+        $this->assertFalse($this->model->useSessionIdForUrl(false));
     }
 
     /**
@@ -421,9 +506,9 @@ class UrlTest extends \PHPUnit\Framework\TestCase
         /** @var $request \Magento\TestFramework\Request */
         $request = $objectManager->get(\Magento\Framework\App\RequestInterface::class);
         $request->setServer(new Parameters(['HTTP_REFERER' => 'http://localhost/']));
-        $this->assertTrue($this->_model->isOwnOriginUrl());
+        $this->assertTrue($this->model->isOwnOriginUrl());
 
         $request->setServer(new Parameters(['HTTP_REFERER' => 'http://example.com/']));
-        $this->assertFalse($this->_model->isOwnOriginUrl());
+        $this->assertFalse($this->model->isOwnOriginUrl());
     }
 }
diff --git a/dev/tests/integration/testsuite/Magento/GroupedProduct/_files/product_grouped_with_simple.php b/dev/tests/integration/testsuite/Magento/GroupedProduct/_files/product_grouped_with_simple.php
new file mode 100644
index 0000000000000000000000000000000000000000..fc01daf2381bceb511efb1365b490091b93a8ba8
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/GroupedProduct/_files/product_grouped_with_simple.php
@@ -0,0 +1,66 @@
+<?php
+/**
+ * Copyright © Magento, Inc. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+use Magento\Catalog\Api\ProductRepositoryInterface;
+use Magento\Catalog\Model\Product;
+use Magento\Catalog\Model\Product\Attribute\Source\Status;
+use Magento\Catalog\Model\Product\Type;
+use Magento\Catalog\Model\Product\Visibility;
+use Magento\GroupedProduct\Model\Product\Type\Grouped;
+use Magento\TestFramework\Helper\Bootstrap;
+
+/** @var ProductRepositoryInterface $productRepository */
+$productRepository = Bootstrap::getObjectManager()
+    ->get(ProductRepositoryInterface::class);
+
+$productLinkFactory = Bootstrap::getObjectManager()
+    ->get(\Magento\Catalog\Api\Data\ProductLinkInterfaceFactory::class);
+$productIds = ['11', '22'];
+
+foreach ($productIds as $productId) {
+    /** @var $product Product */
+    $product = Bootstrap::getObjectManager()->create(Product::class);
+    $product->setTypeId(Type::TYPE_SIMPLE)
+        ->setId($productId)
+        ->setWebsiteIds([1])
+        ->setAttributeSetId(4)
+        ->setName('Simple ' . $productId)
+        ->setSku('simple_' . $productId)
+        ->setPrice(100)
+        ->setVisibility(Visibility::VISIBILITY_BOTH)
+        ->setStatus(Status::STATUS_ENABLED)
+        ->setStockData(['use_config_manage_stock' => 1, 'qty' => 100, 'is_qty_decimal' => 0, 'is_in_stock' => 1]);
+
+    $linkedProducts[] = $productRepository->save($product);
+}
+
+/** @var $product Product */
+$product = Bootstrap::getObjectManager()->create(Product::class);
+
+$product->setTypeId(Grouped::TYPE_CODE)
+    ->setId(1)
+    ->setWebsiteIds([1])
+    ->setAttributeSetId(4)
+    ->setName('Grouped Product')
+    ->setSku('grouped')
+    ->setVisibility(Visibility::VISIBILITY_BOTH)
+    ->setStatus(Status::STATUS_ENABLED)
+    ->setStockData(['use_config_manage_stock' => 1, 'is_in_stock' => 1]);
+
+foreach ($linkedProducts as $linkedProduct) {
+    /** @var \Magento\Catalog\Api\Data\ProductLinkInterface $productLink */
+    $productLink = $productLinkFactory->create();
+    $productLink->setSku($product->getSku())
+        ->setLinkType('associated')
+        ->setLinkedProductSku($linkedProduct->getSku())
+        ->setLinkedProductType($linkedProduct->getTypeId())
+        ->getExtensionAttributes()
+        ->setQty(1);
+    $newLinks[] = $productLink;
+}
+
+$product->setProductLinks($newLinks);
+
+$productRepository->save($product);
diff --git a/dev/tests/integration/testsuite/Magento/GroupedProduct/_files/product_grouped_with_simple_rollback.php b/dev/tests/integration/testsuite/Magento/GroupedProduct/_files/product_grouped_with_simple_rollback.php
new file mode 100644
index 0000000000000000000000000000000000000000..bc2f04d7b19d0d9b6a574b87339fe960b55bebff
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/GroupedProduct/_files/product_grouped_with_simple_rollback.php
@@ -0,0 +1,34 @@
+<?php
+/**
+ * Copyright © Magento, Inc. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
+
+/** @var \Magento\Framework\Registry $registry */
+$registry = $objectManager->get(\Magento\Framework\Registry::class);
+
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', true);
+
+/** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */
+$productRepository = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()
+    ->get(\Magento\Catalog\Api\ProductRepositoryInterface::class);
+
+$skuList = ['simple_11', 'simple_22', 'grouped'];
+foreach ($skuList as $sku) {
+    try {
+        $product = $productRepository->get($sku, false, null, true);
+
+        $stockStatus = $objectManager->create(\Magento\CatalogInventory\Model\Stock\Status::class);
+        $stockStatus->load($product->getEntityId(), 'product_id');
+        $stockStatus->delete();
+
+        $productRepository->delete($product);
+    } catch (\Magento\Framework\Exception\NoSuchEntityException $e) {
+        //Product already removed
+    }
+}
+
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', false);
diff --git a/lib/internal/Magento/Framework/Model/ResourceModel/AbstractResource.php b/lib/internal/Magento/Framework/Model/ResourceModel/AbstractResource.php
index d61389066433a8e8a43f387e9d0522eed8e00613..7048668b813dc28feb1b99146ca12524a0a8162b 100644
--- a/lib/internal/Magento/Framework/Model/ResourceModel/AbstractResource.php
+++ b/lib/internal/Magento/Framework/Model/ResourceModel/AbstractResource.php
@@ -9,6 +9,7 @@ use Magento\Framework\App\ObjectManager;
 use Magento\Framework\DataObject;
 use Magento\Framework\Model\CallbackPool;
 use Magento\Framework\Serialize\Serializer\Json;
+use Psr\Log\LoggerInterface;
 
 /**
  * Abstract resource model
@@ -23,6 +24,11 @@ abstract class AbstractResource
      */
     protected $serializer;
 
+    /**
+     * @var LoggerInterface
+     */
+    private $logger;
+
     /**
      * Constructor
      */
@@ -92,7 +98,7 @@ abstract class AbstractResource
                     call_user_func($callback);
                 }
             } catch (\Exception $e) {
-                throw $e;
+                $this->getLogger()->critical($e);
             }
         }
         return $this;
@@ -252,4 +258,19 @@ abstract class AbstractResource
         }
         return $this->serializer;
     }
+
+    /**
+     * Get logger
+     *
+     * @return LoggerInterface
+     * @deprecated 100.2.0
+     * @since 100.2.0
+     */
+    private function getLogger()
+    {
+        if (null === $this->logger) {
+            $this->logger = ObjectManager::getInstance()->get(LoggerInterface::class);
+        }
+        return $this->logger;
+    }
 }
diff --git a/lib/internal/Magento/Framework/Model/Test/Unit/ResourceModel/AbstractResourceTest.php b/lib/internal/Magento/Framework/Model/Test/Unit/ResourceModel/AbstractResourceTest.php
index e7701748e2d486dcc5397cb3ef6cd55832a84168..40243978fe753d4a07bf4d943c40237a1aae3d8e 100644
--- a/lib/internal/Magento/Framework/Model/Test/Unit/ResourceModel/AbstractResourceTest.php
+++ b/lib/internal/Magento/Framework/Model/Test/Unit/ResourceModel/AbstractResourceTest.php
@@ -27,11 +27,7 @@ class AbstractResourceTest extends \PHPUnit\Framework\TestCase
         $objectManager = new ObjectManager($this);
         $this->serializerMock = $this->createMock(Json::class);
         $this->abstractResource = $objectManager->getObject(AbstractResourceStub::class);
-        $objectManager->setBackwardCompatibleProperty(
-            $this->abstractResource,
-            'serializer',
-            $this->serializerMock
-        );
+        $objectManager->setBackwardCompatibleProperty($this->abstractResource, 'serializer', $this->serializerMock);
     }
 
     /**
@@ -201,9 +197,6 @@ class AbstractResourceTest extends \PHPUnit\Framework\TestCase
         $this->abstractResource->commit();
     }
 
-    /**
-     * @expectedException \Exception
-     */
     public function testCommitZeroLevelCallbackException()
     {
         /** @var AdapterInterface|\PHPUnit_Framework_MockObject_MockObject $connection */
diff --git a/lib/internal/Magento/Framework/Stdlib/Cookie/PhpCookieManager.php b/lib/internal/Magento/Framework/Stdlib/Cookie/PhpCookieManager.php
index 618c70b760d0971c83954c5a703a69ce5d61ddad..91465280d1e805bef915e2faa4bf7177a68e5288 100644
--- a/lib/internal/Magento/Framework/Stdlib/Cookie/PhpCookieManager.php
+++ b/lib/internal/Magento/Framework/Stdlib/Cookie/PhpCookieManager.php
@@ -237,7 +237,9 @@ class PhpCookieManager implements CookieManagerInterface
         ) {
             $expireTime = $metadataArray[PhpCookieManager::KEY_EXPIRE_TIME];
         } else {
-            if (isset($metadataArray[CookieMetadata::KEY_DURATION])) {
+            if (isset($metadataArray[CookieMetadata::KEY_DURATION])
+                && $metadataArray[CookieMetadata::KEY_DURATION] !== PhpCookieManager::EXPIRE_AT_END_OF_SESSION_TIME
+            ) {
                 $expireTime = $metadataArray[CookieMetadata::KEY_DURATION] + time();
             } else {
                 $expireTime = PhpCookieManager::EXPIRE_AT_END_OF_SESSION_TIME;
diff --git a/lib/internal/Magento/Framework/Stdlib/Test/Unit/Cookie/PhpCookieManagerTest.php b/lib/internal/Magento/Framework/Stdlib/Test/Unit/Cookie/PhpCookieManagerTest.php
index b3cb5f2aeddceee4a6a237116f8419c214d5b623..43a7a7cee16dfcd7160687de30b14a09197a1710 100644
--- a/lib/internal/Magento/Framework/Stdlib/Test/Unit/Cookie/PhpCookieManagerTest.php
+++ b/lib/internal/Magento/Framework/Stdlib/Test/Unit/Cookie/PhpCookieManagerTest.php
@@ -36,6 +36,7 @@ namespace Magento\Framework\Stdlib\Test\Unit\Cookie
         const PUBLIC_COOKIE_NAME_DEFAULT_VALUES = 'public_cookie_name_default_values';
         const PUBLIC_COOKIE_NAME_SOME_FIELDS_SET = 'public_cookie_name_some_fields_set';
         const MAX_COOKIE_SIZE_TEST_NAME = 'max_cookie_size_test_name';
+        const PUBLIC_COOKIE_ZERO_DURATION = 'public_cookie_zero_duration';
         const MAX_NUM_COOKIE_TEST_NAME = 'max_num_cookie_test_name';
         const DELETE_COOKIE_NAME = 'delete_cookie_name';
         const DELETE_COOKIE_NAME_NO_METADATA = 'delete_cookie_name_no_metadata';
@@ -66,6 +67,7 @@ namespace Magento\Framework\Stdlib\Test\Unit\Cookie
             self::PUBLIC_COOKIE_NAME_DEFAULT_VALUES => 'self::assertPublicCookieWithDefaultValues',
             self::PUBLIC_COOKIE_NAME_SOME_FIELDS_SET => 'self::assertPublicCookieWithSomeFieldSet',
             self::MAX_COOKIE_SIZE_TEST_NAME => 'self::assertCookieSize',
+            self::PUBLIC_COOKIE_ZERO_DURATION => 'self::assertZeroDuration',
         ];
 
         /**
@@ -405,6 +407,38 @@ namespace Magento\Framework\Stdlib\Test\Unit\Cookie
             $this->assertTrue(self::$isSetCookieInvoked);
         }
 
+        public function testSetPublicCookieZeroDuration()
+        {
+            /** @var PublicCookieMetadata $publicCookieMetadata */
+            $publicCookieMetadata = $this->objectManager->getObject(
+                \Magento\Framework\Stdlib\Cookie\PublicCookieMetadata::class,
+                [
+                    'metadata' => [
+                        'domain' => null,
+                        'path' => null,
+                        'secure' => false,
+                        'http_only' => false,
+                        'duration' => 0,
+                    ],
+                ]
+            );
+
+            $this->scopeMock->expects($this->once())
+                ->method('getPublicCookieMetadata')
+                ->with($publicCookieMetadata)
+                ->will(
+                    $this->returnValue($publicCookieMetadata)
+                );
+
+            $this->cookieManager->setPublicCookie(
+                self::PUBLIC_COOKIE_ZERO_DURATION,
+                'cookie_value',
+                $publicCookieMetadata
+            );
+
+            $this->assertTrue(self::$isSetCookieInvoked);
+        }
+
         public function testSetPublicCookieSomeFieldsSet()
         {
             self::$isSetCookieInvoked = false;
@@ -839,6 +873,30 @@ namespace Magento\Framework\Stdlib\Test\Unit\Cookie
             self::assertEquals('', $path);
         }
 
+        /**
+         * Assert cookie set with zero duration
+         *
+         * Suppressing UnusedPrivateMethod, since PHPMD doesn't detect callback method use.
+         * @SuppressWarnings(PHPMD.UnusedPrivateMethod)
+         */
+        private static function assertZeroDuration(
+            $name,
+            $value,
+            $expiry,
+            $path,
+            $domain,
+            $secure,
+            $httpOnly
+        ) {
+            self::assertEquals(self::PUBLIC_COOKIE_ZERO_DURATION, $name);
+            self::assertEquals(self::COOKIE_VALUE, $value);
+            self::assertEquals(self::COOKIE_EXPIRE_END_OF_SESSION, $expiry);
+            self::assertFalse($secure);
+            self::assertFalse($httpOnly);
+            self::assertEquals('', $domain);
+            self::assertEquals('', $path);
+        }
+
         protected function stubGetCookie($get, $default, $return)
         {
             $this->readerMock->expects($this->atLeastOnce())
diff --git a/lib/internal/Magento/Framework/Url.php b/lib/internal/Magento/Framework/Url.php
index d917391a4e95a270ceb8517b02de515f37f704e5..11f828370d441a5eeaf75d4563bd78e45efba57b 100644
--- a/lib/internal/Magento/Framework/Url.php
+++ b/lib/internal/Magento/Framework/Url.php
@@ -389,6 +389,9 @@ class Url extends \Magento\Framework\DataObject implements \Magento\Framework\Ur
     protected function _isSecure()
     {
         if ($this->_request->isSecure()) {
+            if ($this->getRouteParamsResolver()->hasData('secure')) {
+                return (bool) $this->getRouteParamsResolver()->getData('secure');
+            }
             return true;
         }