* @since 1.22
*/
class HashRing {
+ /** @var Array (location => weight) */
+ protected $sourceMap = array();
/** @var Array (location => (start, end)) */
protected $ring = array();
* @param array $map (location => weight)
*/
public function __construct( array $map ) {
- $sum = array_sum( $map );
- if ( !count( $map ) || $sum <= 0 ) {
+ $map = array_filter( $map, function( $w ) { return $w > 0; } );
+ if ( !count( $map ) ) {
throw new MWException( "Ring is empty or all weights are zero." );
}
+ $this->sourceMap = $map;
// Sort the locations based on the hash of their names
$hashes = array();
foreach ( $map as $location => $weight ) {
return strcmp( $hashes[$a], $hashes[$b] );
} );
// Fit the map to weight-proportionate one with a space of size RING_SIZE
+ $sum = array_sum( $map );
$standardMap = array();
foreach ( $map as $location => $weight ) {
$standardMap[$location] = (int)floor( $weight / $sum * self::RING_SIZE );
}
return $locations;
}
+
+ /**
+ * Get the map of locations to weight (ignores 0-weight items)
+ *
+ * @return array
+ */
+ public function getLocationWeights() {
+ return $this->sourceMap;
+ }
+
+ /**
+ * Get a new hash ring with a location removed from the ring
+ *
+ * @param string $location
+ * @return HashRing|bool Returns false if no non-zero weighted spots are left
+ */
+ public function newWithoutLocation( $location ) {
+ $map = $this->sourceMap;
+ unset( $map[$location] );
+ if ( count( $map ) ) {
+ return new self( $map );
+ }
+ return false;
+ }
}