Commit 67f5cb9f authored by Bas de Nooijer's avatar Bas de Nooijer

Merge branch 'release/2.4.0' into develop

parents 22103776 bf7fa1c2
......@@ -7,17 +7,28 @@ htmlHeader();
$client = new Solarium_Client($config);
$parallel = $client->getPlugin('parallelexecution');
// create two queries to execute in an array. Keys are important for fetching the results later!
$queries = array(
'instock' => $client->createSelect()->setQuery('inStock:true'),
'lowprice' => $client->createSelect()->setQuery('price:[1 TO 300]'),
);
// Add a delay param to better show the effect, as an example Solr install with
// only a dozen documents is too fast for good testing
// This param only works with the correct Solr plugin,
// see http://www.raspberry.nl/2012/01/04/solr-delay-component/
// If you don't have to plugin the example still works, just without the delay.
$customizer = $client->getPlugin('customizerequest');
$customizer->createCustomization(array(
'key' => 'delay',
'type' => 'param',
'name' => 'delay',
'value' => '500',
'persistent' => true
));
// create two queries to execute in an array. Keys are important for fetching the results later!
$queryInstock = $client->createSelect()->setQuery('inStock:true');
$queryLowprice = $client->createSelect()->setQuery('price:[1 TO 300]');
// first execute the queries the normal way and time it
$start = microtime(true);
$client->execute($queries['instock']);
$client->execute($queries['lowprice']);
$client->execute($queryInstock);
$client->execute($queryLowprice);
echo 'Execution time for normal "serial" execution of two queries: ' . round(microtime(true)-$start, 3);
......@@ -26,13 +37,15 @@ echo '<hr/>';
// now execute the two queries parallel and time it
$start = microtime(true);
$results = $parallel->execute($queries);
$parallel->addQuery('instock', $queryInstock);
$parallel->addQuery('lowprice', $queryLowprice);
$results = $parallel->execute();
echo 'Execution time for parallel execution of two queries: ' . round(microtime(true)-$start, 3);
htmlFooter();
// Note: for this example on a default Solr index (with a tiny index) the performance gain is minimal to none.
// With a bigger dataset, more complex queries or multiple solr instances the performance gain is much more.
// For testing you can use a Solr delay component (see https://github.com/basdenooijer/raspberry-solr-plugins) to
// artificially slow Solr down by an exact amount of time.
\ No newline at end of file
// Note: for this example on a default Solr index (with a tiny index) running on localhost the performance gain is
// minimal to none, sometimes even slightly slower!
// In a realworld scenario with network latency, a bigger dataset, more complex queries or multiple solr instances the
// performance gain is much more.
\ No newline at end of file
......@@ -12,7 +12,7 @@ $query->setFields(array('id'));
// get a plugin instance and apply settings
$prefetch = $client->getPlugin('prefetchiterator');
$prefetch->setPrefetch(2); //fetch 5 rows per query (for real world use this can be way higher)
$prefetch->setPrefetch(2); //fetch 2 rows per query (for real world use this can be way higher)
$prefetch->setQuery($query);
// display the total number of documents found by solr
......
......@@ -48,28 +48,91 @@
* @subpackage Plugin
*/
// @codeCoverageIgnoreStart
class Solarium_Plugin_ParallelExecution extends Solarium_Plugin_Abstract
{
/**
* Default options
*
* @var array
*/
protected $_options = array(
'curlmultiselecttimeout' => 0.1,
);
/**
* Queries (and optionally clients) to execute
*
* @var array
*/
protected $_queries = array();
/**
* Add a query to execute
*
* @param string $key
* @param Solarium_Query $query
* @param null|Solarium_Client $client
* @return Solarium_Plugin_ParallelExecution
*/
public function addQuery($key, $query, $client = null)
{
if($client == null) $client = $this->_client;
$this->_queries[$key] = array(
'query' => $query,
'client' => $client,
);
return $this;
}
/**
* Get queries (and coupled client instances)
*
* @return array
*/
public function getQueries()
{
return $this->_queries;
}
/**
* Clear all queries
*
* @return self Provides fluent interface
*/
public function clearQueries() {
$this->_queries = array();
return $this;
}
// @codeCoverageIgnoreStart
/**
* Execute queries parallel
*
* Use an array of Solarium_Query objects as input. The keys of the array are important, as they are also used in
* the result array. You can mix all querytypes in the input array.
*
* @param array $queries
* @param array $queries (deprecated, use addQuery instead)
* @return array
*/
public function execute($queries)
public function execute($queries = null)
{
$adapter = $this->_client->setAdapter('Solarium_Client_Adapter_Curl')->getAdapter();
// this is for backwards compatibility
if(is_array($queries)) {
foreach ($queries as $key => $query) {
$this->addQuery($key, $query);
}
}
// create handles and add all handles to the multihandle
$multiHandle = curl_multi_init();
$handles = array();
foreach ($queries as $key => $query) {
$request = $this->_client->createRequest($query);
foreach ($this->_queries as $key => $data) {
$request = $this->_client->createRequest($data['query']);
$adapter = $data['client']->setAdapter('Solarium_Client_Adapter_Curl')->getAdapter();
$handle = $adapter->createHandle($request);
curl_multi_add_handle($multiHandle, $handle);
$handles[$key] = $handle;
......@@ -77,9 +140,20 @@ class Solarium_Plugin_ParallelExecution extends Solarium_Plugin_Abstract
// executing multihandle (all requests)
$this->_client->triggerEvent('ParallelExecutionStart');
do {
curl_multi_exec($multiHandle, $running);
} while($running > 0);
$mrc = curl_multi_exec($multiHandle, $active);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
$timeout = $this->getOption('curlmultiselecttimeout');
while ($active && $mrc == CURLM_OK) {
if (curl_multi_select($multiHandle, $timeout) != -1) {
do {
$mrc = curl_multi_exec($multiHandle, $active);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
}
}
$this->_client->triggerEvent('ParallelExecutionEnd');
// get the results
......@@ -88,7 +162,7 @@ class Solarium_Plugin_ParallelExecution extends Solarium_Plugin_Abstract
try {
curl_multi_remove_handle($multiHandle, $handle);
$response = $adapter->getResponse($handle, curl_multi_getcontent($handle));
$results[$key] = $this->_client->createResult($queries[$key], $response);
$results[$key] = $this->_client->createResult($this->_queries[$key]['query'], $response);
} catch(Solarium_Client_HttpException $e) {
$results[$key] = $e;
}
......@@ -99,5 +173,5 @@ class Solarium_Plugin_ParallelExecution extends Solarium_Plugin_Abstract
return $results;
}
// @codeCoverageIgnoreEnd
}
// @codeCoverageIgnoreEnd
\ No newline at end of file
......@@ -70,7 +70,7 @@ class Solarium_Version
*
* @var string
*/
const VERSION = '2.3.0';
const VERSION = '2.4.0';
/**
......
<?php
/**
* Copyright 2011 Bas de Nooijer. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this listof conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the copyright holder.
*/
class Solarium_Plugin_ParallelExecutionTest extends PHPUnit_Framework_TestCase
{
/**
* @var Solarium_Plugin_ParallelExecution
*/
protected $_plugin;
public function setUp()
{
$this->_plugin = new Solarium_Plugin_ParallelExecution();
}
public function testAddAndGetQueries()
{
$client1 = new Solarium_Client();
$client2 = new Solarium_Client(array(
'adapter' => 'MyAdapter',
'adapteroptions' => array(
'host' => 'myhost',
)
)
);
$this->_plugin->init($client1, array());
$query1 = $client1->createSelect()->setQuery('test1');
$query2 = $client1->createSelect()->setQuery('test2');
$this->_plugin->addQuery(1, $query1);
$this->_plugin->addQuery(2, $query2, $client2);
$this->assertEquals(
array(
1 => array('query' => $query1, 'client' => $client1),
2 => array('query' => $query2, 'client' => $client2),
),
$this->_plugin->getQueries()
);
}
public function testClearQueries()
{
$client = new Solarium_Client();
$this->_plugin->init($client, array());
$query1 = $client->createSelect()->setQuery('test1');
$query2 = $client->createSelect()->setQuery('test2');
$this->_plugin->addQuery(1, $query1);
$this->_plugin->addQuery(2, $query2);
$this->_plugin->clearQueries();
$this->assertEquals(
array(),
$this->_plugin->getQueries()
);
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment