Exception: SplitIoClient::Splitter

Inherits:
NoMethodError
  • Object
show all
Defined in:
lib/splitclient-rb/engine/evaluator/splitter.rb

Overview

Misc class in charge of providing hash functions and determination of treatment based on concept of buckets based on provided key

Instance Method Summary collapse

Constructor Details

#initializeSplitter

Returns a new instance of Splitter.



7
8
9
10
11
12
13
14
# File 'lib/splitclient-rb/engine/evaluator/splitter.rb', line 7

def initialize
  @murmur_hash = case RUBY_PLATFORM
  when 'java' 
    Proc.new { |key, seed| Java::MurmurHash3.murmurhash3_x86_32(key, seed) }
  else
    Proc.new { |key, seed| Digest::MurmurHashMRI3_x86_32.rawdigest(key, [seed].pack('L')) }
  end
end

Instance Method Details

#bucket(hash_value) ⇒ Object

returns bucket value for the given hash value

Parameters:

  • hash_value (string)

    hash value



119
120
121
# File 'lib/splitclient-rb/engine/evaluator/splitter.rb', line 119

def bucket(hash_value)
  (hash_value.abs % 100) + 1
end

#count_hash(key, seed, legacy) ⇒ Object

returns a hash value for the give key, seed pair

Parameters:

  • key (String)

    user key

  • seed (Fixnum)

    seed for the user key



54
55
56
# File 'lib/splitclient-rb/engine/evaluator/splitter.rb', line 54

def count_hash(key, seed, legacy)
  legacy ? legacy_hash(key, seed) : murmur_hash(key, seed)
end

#get_treatment(id, seed, partitions, legacy_algo) ⇒ Object

gets the appropriate treatment based on id, seed and partition value

Parameters:

  • id (string)

    user key

  • seed (number)

    seed for the user key

  • partitions (object)

    array of partitions



34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/splitclient-rb/engine/evaluator/splitter.rb', line 34

def get_treatment(id, seed, partitions, legacy_algo)
  legacy = [1, nil].include?(legacy_algo)

  if partitions.empty?
    return SplitIoClient::Engine::Models::Treatment::CONTROL
  end

  if hundred_percent_one_treatment?(partitions)
    return (partitions.first).treatment
  end

  return get_treatment_for_key(bucket(count_hash(id, seed, legacy)), partitions)
end

#get_treatment_for_key(bucket, partitions) ⇒ Object

returns the treatment for a bucket given the partitions

Parameters:

  • bucket (number)

    bucket value

  • parittions (object)

    array of partitions



101
102
103
104
105
106
107
108
109
110
111
# File 'lib/splitclient-rb/engine/evaluator/splitter.rb', line 101

def get_treatment_for_key(bucket, partitions)
  buckets_covered_thus_far = 0
  partitions.each do |p|
    unless p.is_empty?
      buckets_covered_thus_far += p.size
      return p.treatment if buckets_covered_thus_far >= bucket
    end
  end

  return SplitIoClient::Engine::Models::Treatment::CONTROL
end

#hundred_percent_one_treatment?(partitions) ⇒ boolean

Checks if the partiotion size is 100%

Parameters:

  • partitions (object)

    array of partitions

Returns:

  • (boolean)

    true if partition is 100% false otherwise



22
23
24
# File 'lib/splitclient-rb/engine/evaluator/splitter.rb', line 22

def hundred_percent_one_treatment?(partitions)
  (partitions.size != 1) ? false : (partitions.first.size == 100)
end

#legacy_hash(key, seed) ⇒ Object



62
63
64
65
66
67
68
69
70
# File 'lib/splitclient-rb/engine/evaluator/splitter.rb', line 62

def legacy_hash(key, seed)
  h = 0

  for i in 0..key.length-1
    h = to_int32(31 * h + key[i].ord)
  end

  h^seed
end

#murmur_hash(key, seed) ⇒ Object



58
59
60
# File 'lib/splitclient-rb/engine/evaluator/splitter.rb', line 58

def murmur_hash(key, seed)
  @murmur_hash.call(key, seed)
end

#to_int32(number) ⇒ int

misc method to convert ruby number to int 32 since overflow is handled different to java

Parameters:

  • number (number)

    ruby number value

Returns:

  • (int)

    returns the int 32 value of the provided number



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/splitclient-rb/engine/evaluator/splitter.rb', line 78

def to_int32(number)
  begin
    sign = number < 0 ? -1 : 1
    abs = number.abs
    return 0 if abs == 0 || abs == Float::INFINITY
  rescue
    return 0
  end

  pos_int = sign * abs.floor
  int_32bit = pos_int % 2**32

  return int_32bit - 2**32 if int_32bit >= 2**31
  int_32bit
end