All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.split.engine.splitter.Splitter Maven / Gradle / Ivy

package io.split.engine.splitter;

import io.split.client.dtos.Partition;
import io.split.client.utils.MurmurHash3;
import io.split.grammar.Treatments;

import java.util.List;

/**
 * These set of functions figure out which treatment a key should see.
 *
 * @author adil
 */
public class Splitter {
    private static final int ALGO_LEGACY = 1;
    private static final int ALGO_MURMUR = 2;

    public static String getTreatment(String key, int seed, List partitions, int algo) {

        // 1. when there are no partitions, we just return control
        if (partitions.isEmpty()) {
            return Treatments.CONTROL;
        }


        if (hundredPercentOneTreatment(partitions)) {
            return partitions.get(0).treatment;
        }

        return getTreatment(bucket(hash(key, seed, algo)), partitions);
    }

    static long hash(String key, int seed, int algo) {
        switch (algo) {
            case ALGO_MURMUR:
                return murmur_hash(key, seed);
            case ALGO_LEGACY:
            default:
                return legacy_hash(key, seed);
        }
    }

    /*package private*/
    static long murmur_hash(String key, int seed) {
        return MurmurHash3.murmurhash3_x86_32(key, 0, key.length(), seed);
    }

    /**
     * Returns a bucket between 1 and 100, inclusive.
     * @param key
     * @param seed
     * @return bucket >= 1 && bucket <= 100
     */
    public static int getBucket(String key, int seed, int algo) {
        return bucket(hash(key, seed, algo));
    }

    /*package private*/
    static int legacy_hash(String key, int seed) {
        int h = 0;
        for (int i = 0; i < key.length(); i++) {
            h = 31 * h + key.charAt(i);
        }
        return h ^ seed;
    }

    /**
     * @param bucket
     * @param partitions MUST HAVE more than one partitions.
     * @return
     */
    private static String getTreatment(int bucket, List partitions) {

        int bucketsCoveredThusFar = 0;

        for (Partition partition : partitions) {
            bucketsCoveredThusFar += partition.size;

            if (bucketsCoveredThusFar >= bucket) {
                return partition.treatment;
            }
        }

        return Treatments.CONTROL;
    }

    /*package private*/
    static int bucket(long hash) {
        return (int) (Math.abs(hash % 100) + 1);
    }


    private static boolean hundredPercentOneTreatment(List partitions) {
        if (partitions.size() != 1) {
            return false;
        }

        return (partitions.get(0).size == 100);
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy