Commit 29076983 authored by Bas de Nooijer's avatar Bas de Nooijer

Added loadbalancer plugin, including a unittest and example

parent c0bbb200
<?php
require('init.php');
htmlHeader();
// create a client instance and get loadbalancer plugin instance
$client = new Solarium_Client($config);
$loadbalancer = $client->getPlugin('loadbalancer');
// apply loadbalancer settings
$optionsSolrOne = array('host' => '127.0.0.1', 'port' => 8983);
$optionsSolrTwo = array('host' => '127.0.0.1', 'port' => 7574);
$loadbalancer->addServer('solr1', $optionsSolrOne, 100);
$loadbalancer->addServer('solr2', $optionsSolrTwo, 200);
$loadbalancer->addServer('solr3', $optionsSolrTwo, 1);
// create a basic query to execute
$query = $client->createSelect();
// execute the query multiple times, displaying the server for each execution
for($i=1; $i<=8; $i++) {
$resultset = $client->select($query);
echo 'Query execution #' . $i . '<br/>';
echo 'NumFound: ' . $resultset->getNumFound(). '<br/>';
echo 'Server: ' . $loadbalancer->getLastServerKey() .'<hr/>';
}
// force a server for a query (normally solr 3 is extremely unlikely based on it's weight)
$loadbalancer->forceServerForNextQuery('solr3');
$resultset = $client->select($query);
echo 'Query execution with server forced to solr3<br/>';
echo 'NumFound: ' . $resultset->getNumFound(). '<br/>';
echo 'Server: ' . $loadbalancer->getLastServerKey() .'<hr/>';
// test a ping query
$query = $client->createPing();
$client->ping($query);
echo 'Loadbalanced ping query, should display a loadbalancing server:<br/>';
echo 'Ping server: ' . $loadbalancer->getLastServerKey() .'<hr/>';
// exclude ping query from loadbalancing
$loadbalancer->addBlockedQueryType(Solarium_Client::QUERYTYPE_PING);
$client->ping($query);
echo 'Non-loadbalanced ping query, should not display a loadbalancing server:<br/>';
echo 'Ping server: ' . $loadbalancer->getLastServerKey() .'<hr/>';
htmlFooter();
\ No newline at end of file
......@@ -110,6 +110,11 @@
<li><a href="6.3-placeholder-syntax.php">6.3 Placeholder syntax</a></li>
</ul>
<li>7. Plugins</li>
<ul style="list-style:none;">
<li><a href="7.1-plugin-loadbalancer.php">7.1 Loadbalancer</a></li>
</ul>
</ul>
</body>
</html>
\ No newline at end of file
This diff is collapsed.
<?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.
*
* @copyright Copyright 2011 Bas de Nooijer <solarium@raspberry.nl>
* @license http://github.com/basdenooijer/solarium/raw/master/COPYING
* @link http://www.solarium-project.org/
*
* @package Solarium
*/
/**
* Weighted random choice class
*
* For use in the loadbalancer plugin
*
* @package Solarium
* @subpackage Plugin
*/
class Solarium_Plugin_Loadbalancer_WeightedRandomChoice
{
/**
* Total weight of all choices
*
* @var int
*/
protected $_totalWeight = 0;
/**
* Choices total lookup array
*
* @var array
*/
protected $_lookup = array();
/**
* Values lookup array
*
* @var array
*/
protected $_values = array();
/**
* Constructor
*
* @param array $choices
*/
public function __construct($choices)
{
$i = 0;
foreach($choices AS $key => $weight) {
if ($weight <= 0) throw new Solarium_Exception('Weight must be greater than zero');
$this->_totalWeight += $weight;
$this->_lookup[$i] = $this->_totalWeight;
$this->_values[$i] = $key;
$i++;
}
}
/**
* Get a (weighted) random entry
*
* @return string
*/
public function getRandom()
{
return $this->_values[$this->_getKey()];
}
/**
* Get a (weighted) random entry key
*
* @return int
*/
protected function _getKey()
{
$random = mt_rand(1, $this->_totalWeight);
$high = count($this->_lookup)-1;
$low = 0;
while ( $low < $high ) {
$probe = (int)(($high + $low) / 2);
if ($this->_lookup[$probe] < $random) {
$low = $probe + 1;
} else if ($this->_lookup[$probe] > $random) {
$high = $probe - 1;
} else {
return $probe;
}
}
if ( $low != $high ) {
return $random;
} else {
if ($this->_lookup[$low] >= $random) {
return $low;
} else {
return $low+1;
}
}
}
}
\ No newline at end of file
<?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_Loadbalancer_WeightedRandomChoiceTest extends PHPUnit_Framework_TestCase
{
public function testGetRandom()
{
$choices = array('key1' => 1, 'key2' => 2, 'key3' => 3);
$randomizer = new Solarium_Plugin_Loadbalancer_WeightedRandomChoice($choices);
$choice = $randomizer->getRandom();
$this->assertTrue(
array_key_exists($choice, $choices)
);
$counts = array('key1' => 0, 'key2' => 0, 'key3' => 0);
for ($i = 0; $i<1000; $i++) {
$choice = $randomizer->getRandom();
$counts[$choice]++;
}
$this->assertTrue($counts['key1'] < $counts['key2']);
$this->assertTrue($counts['key2'] < $counts['key3']);
}
}
\ 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