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



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



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



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



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



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%



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



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