/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.usergrid.persistence.core.shard;
import com.google.common.hash.Funnel;
import com.google.common.hash.HashCode;
import com.google.common.hash.HashFunction;
import com.google.common.hash.Hashing;
/**
* Simple utility to locate which bucket an element should be located based on it's funnel
*
*/
public class ShardLocator<T> {
/**
* Use the murmur 3 hash
*/
private static final HashFunction HASHER = Hashing.murmur3_128();
private final int totalBuckets;
private final Funnel<T> funnel;
public ShardLocator( final Funnel<T> funnel, final int totalBuckets ) {
this.funnel = funnel;
this.totalBuckets = totalBuckets;
}
/**
* Locate the bucket number given the value, the funnel and the total buckets.
*
* Assigns to {@code hashCode} a "bucket" in the range {@code [0, buckets)}, in a uniform manner that minimizes the
* need for remapping as {@code buckets} grows. That is, {@code consistentHash(h, n)} equals:
*
* <ul> <li>{@code n - 1}, with approximate probability {@code 1/n} <li>{@code consistentHash(h, n - 1)}, otherwise
* (probability {@code 1 - 1/n}) </ul>
*
* <p>See the <a href="http://en.wikipedia.org/wiki/Consistent_hashing">wikipedia article on consistent hashing</a>
* for more information.
*
* <p>See <a href="http://arxiv.org/pdf/1406.2294v1.pdf">this paper</a> for more details on the algorithm</p>
*
*
* Note that after testing, increasing buckets does NOT yield the expected results. You will need an algorithm
* that manually walks a tree. See
*
*/
public int getBucket( T value ) {
final HashCode hashCode = HASHER.hashObject( value, funnel );
int owningIndex = Hashing.consistentHash( hashCode, totalBuckets );
return owningIndex;
}
}