?
Group.php 0000666 00000013717 15125353711 0006371 0 ustar 00 <?php
require_once 'Shanty/Mongo/Connection.php';
require_once 'Shanty/Mongo/Connection/Stack.php';
/**
* @category Shanty
* @package Shanty_Mongo
* @copyright Shanty Tech Pty Ltd
* @license New BSD License
* @author Coen Hyde
*/
class Shanty_Mongo_Connection_Group
{
protected $_masters = null;
protected $_slaves = null;
public function __construct(array $connectionOptions = null)
{
$this->_masters = new Shanty_Mongo_Connection_Stack();
$this->_slaves = new Shanty_Mongo_Connection_Stack();
// add connections
if (!is_null($connectionOptions)) {
$this->addConnections($connectionOptions);
}
}
/**
* Add multiple connections at once using arrays of options
*
* @param array $connectionOptions
*/
public function addConnections($connectionOptions)
{
if ($connectionOptions instanceof Zend_Config) {
$connectionOptions = $connectionOptions->toArray();
}
$masters = array();
$masterStackOptions = array();
$slaves = array();
$slaveStackOptions = array();
$group = $this;
$addConnections = function(Shanty_Mongo_Connection_Stack $stack, array $connections) use ($group) {
foreach ($connections as $connectionData) {
$options = array_intersect_key($connectionData, array_flip(Shanty_Mongo_Connection::getAvailableOptions()));
$connection = new Shanty_Mongo_Connection($group->formatConnectionString($connectionData), $options);
if (array_key_exists('weight', $connectionData)) $weight = (int) $connectionData['weight'];
else $weight = 1;
$stack->addNode($connection, $weight);
}
};
// Lets add our masters
if (array_key_exists('master', $connectionOptions)) $masters[] = $connectionOptions['master']; // single master
elseif (array_key_exists('masters', $connectionOptions)) {
$connectionKeys = array_filter(array_keys($connectionOptions['masters']), 'is_numeric');
$masters = array_intersect_key($connectionOptions['masters'], array_flip($connectionKeys)); // only connections
$masterStackOptions = array_diff_key($connectionOptions['masters'], array_flip($connectionKeys)); // only options
}
else $masters[] = $connectionOptions; // one server
$addConnections($this->getMasters(), $masters); // Add master connections
$this->getMasters()->setOptions($masterStackOptions); // Set master stack options
// Lets add our slaves
if (array_key_exists('slave', $connectionOptions)) $slaves[] = $connectionOptions['slave']; // single slave
elseif (array_key_exists('slaves', $connectionOptions)) {
$connectionKeys = array_filter(array_keys($connectionOptions['slaves']), 'is_numeric');
$slaves = array_intersect_key($connectionOptions['slaves'], array_flip($connectionKeys)); // only connections
$slaveStackOptions = array_diff_key($connectionOptions['slaves'], array_flip($connectionKeys)); // only options
};
$addConnections($this->getSlaves(), $slaves); // Add slave connections
$this->getSlaves()->setOptions($slaveStackOptions); // Set slave stack options
}
/**
* Add a connection to a master server
*
* @param Shanty_Mongo_Connection $connection
* @param int $weight
*/
public function addMaster(Shanty_Mongo_Connection $connection, $weight = 1)
{
$this->_masters->addNode($connection, $weight);
}
/**
* Get all master connections
*
* @return Shanty_Mongo_Connection_Stack
*/
public function getMasters()
{
return $this->_masters;
}
/**
* Add a connection to a slaver server
*
* @param $connection
* @param $weight
*/
public function addSlave(Shanty_Mongo_Connection $connection, $weight = 1)
{
$this->_slaves->addNode($connection, $weight);
}
/**
* Get all slave connections
*
* @return Shanty_Mongo_Connection_Stack
*/
public function getSlaves()
{
return $this->_slaves;
}
/**
* Get a write connection
*
* @return Shanty_Mongo_Connection
*/
public function getWriteConnection()
{
// Select master
$write = $this->_masters->selectNode();
if ($write && !$write->connected) {
$write->connect();
}
return $write;
}
/**
* Get a read connection
*
* @return Shanty_Mongo_Connection
*/
public function getReadConnection()
{
if (count($this->_slaves) === 0) {
// If no slaves then get a master connection
$read = $this->getWriteConnection();
}
else {
// Select slave
$read = $this->_slaves->selectNode();
if ($read) $read->connect();
}
return $read;
}
/**
* Format a connection string
*
* @param array $connectionOptions
*
*/
public function formatConnectionString(array $connectionOptions = array())
{
// See if we are dealing with a replica set
if (array_key_exists('hosts', $connectionOptions)) $hosts = $connectionOptions['hosts'];
else $hosts = array($connectionOptions);
$connectionString = 'mongodb://';
$hostStringList = array();
foreach ($hosts as $hostOptions) {
$hostStringList[] = static::formatHostString($hostOptions);
}
$connectionString .= implode(',', $hostStringList);
// Set database
if (isset($connectionOptions['database'])) $connectionString .= '/'.$connectionOptions['database'];
return $connectionString;
}
/**
* Format a host string
*
* @param $options
* @return string
*/
public function formatHostString(array $hostOptions = array())
{
$hostString = '';
// Set username
if (isset($hostOptions['username']) && !is_null($hostOptions['username'])) {
$hostString .= $hostOptions['username'];
// Set password
if (isset($hostOptions['password']) && !is_null($hostOptions['password'])) {
$hostString .= ':'.$hostOptions['password'];
}
$hostString .= '@';
}
// Set host
if (isset($hostOptions['host']) && !is_null($hostOptions['host'])) $hostString .= $hostOptions['host'];
else $hostString .= '127.0.0.1';
// Set port
$hostString .= ':';
if (isset($hostOptions['port']) && !is_null($hostOptions['port'])) $hostString .= $hostOptions['port'];
else $hostString .= '27017';
return $hostString;
}
} Stack.php 0000666 00000011353 15125353711 0006334 0 ustar 00 <?php
/**
* @category Shanty
* @package Shanty_Mongo
* @copyright Shanty Tech Pty Ltd
* @license New BSD License
* @author Coen Hyde
*/
class Shanty_Mongo_Connection_Stack implements SeekableIterator, Countable, ArrayAccess
{
protected $_position = 0;
protected $_nodes = array();
protected $_weights = array();
protected $_options = array(
'cacheConnectionSelection' => true
);
protected $_cacheConnectionSelection = true;
protected $_cachedConnection = null;
/**
* Get an option
*
* @param string $option
*/
public function getOption($option)
{
if (!array_key_exists($option, $this->_options)) {
return null;
}
return $this->_options[$option];
}
/**
* Set an option
*
* @param string $option
* @param mixed $value
*/
public function setOption($option, $value)
{
$this->_options[$option] = $value;
}
/**
* Set Options
*
* @param array $options
*/
public function setOptions(array $options)
{
$this->_options = array_merge($this->_options, $options);
}
/**
* Add node to connection stack
*
* @param Shanty_Mongo_Connection $connection
* @param int $weight
*/
public function addNode(Shanty_Mongo_Connection $connection, $weight = 1)
{
$this->_nodes[] = $connection;
$this->_weights[] = (int) $weight;
}
/**
* Select a node from the connection stack.
*
* @return Shanty_Mongo_Connection
*/
public function selectNode()
{
if (count($this) == 0) {
// no nodes to select from
return null;
}
// Return the cached connection if available
if ($this->cacheConnectionSelection() && $this->hasCachedConnection()) {
return $this->getCachedConnection();
}
// Select a new connection
$r = mt_rand(1,array_sum($this->_weights));
$offset = 0;
foreach ($this->_weights as $k => $weight) {
$offset += $weight;
if ($r <= $offset) {
$connection = $this->_nodes[$k];
break;
}
}
// Cache the connection for later use
if ($this->cacheConnectionSelection()) {
$this->_cachedConnection = $connection;
}
return $connection;
}
/**
* Determine if this connection stack has a cached connection
*
* @return boolean
*/
public function hasCachedConnection()
{
return !is_null($this->_cachedConnection);
}
/**
* Get the cached connection
*
* @return Shanty_Mongo_Connection
*/
public function getCachedConnection()
{
return $this->_cachedConnection;
}
/**
* Get or set the flag to determine if the first connection selection should be cached
*
* @param boolean $value
*/
public function cacheConnectionSelection($value = null)
{
if (!is_null($value)) {
$this->_options['cacheConnectionSelection'] = (boolean) $value;
}
return $this->_options['cacheConnectionSelection'];
}
/**
* Seek to a particular connection
*
* @param $position
*/
public function seek($position)
{
if (!is_numeric($position)) {
require_once 'Shanty/Mongo/Exception.php';
throw new Shanty_Mongo_Exception("Position must be numeric");
}
$this->_position = $position;
if (!$this->valid()) {
throw new OutOfBoundsException("invalid seek position ($position)");
}
}
/**
* Get the current connection
*
* @return Shanty_Mongo_Connection
*/
public function current()
{
return $this->_nodes[$this->_position];
}
/**
* Get teh current key
*
* @return int
*/
public function key()
{
return $this->_position;
}
/**
* Move the pointer to the next connection
*/
public function next()
{
$this->_position +=1;
}
/**
* Rewind the pointer to the begining of the stack
*/
public function rewind()
{
$this->_position = 0;
}
/**
* Is the location of the current pointer valid
*/
public function valid()
{
return $this->offsetExists($this->_position);
}
/**
* Count all the connections
*/
public function count()
{
return count($this->_nodes);
}
/**
* Test if an offset exists
*
* @param int $offset
*/
public function offsetExists($offset)
{
return array_key_exists($offset, $this->_nodes);
}
/**
* Get an offset
*
* @param int $offset
*/
public function offsetGet($offset)
{
if (!$this->offsetExists($offset)) return null;
return $this->_nodes[$offset];
}
/**
* Set an offset
*
* @param Shanty_Mongo_Connection $offset
* @param $connection
*/
public function offsetSet($offset, $connection)
{
if (!is_numeric($offset)) {
require_once 'Shanty/Mongo/Exception.php';
throw new Shanty_Mongo_Exception("Offset must be numeric");
}
$this->_nodes[$offset] = $connection;
$this->_weights[$offset] = 1;
}
/**
* Unset an offset
*
* @param int $offset
*/
public function offsetUnset($offset)
{
unset($this->_nodes[$offset]);
unset($this->_weights[$offset]);
}
}