From aaa88a7dacd1ccb6b1f53f4ae6c42861b61fe574 Mon Sep 17 00:00:00 2001 From: Leigh Caplan Date: Sat, 16 Aug 2014 22:36:00 -0700 Subject: [PATCH 1/4] Support non-contiguous user ids and different groups per feature. --- lib/rollout.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rollout.rb b/lib/rollout.rb index 37eb03e..2c3f288 100644 --- a/lib/rollout.rb +++ b/lib/rollout.rb @@ -89,6 +89,6 @@ def user_within_active_percentage?(feature, user) percentage = percentage(feature) return false if percentage.nil? - user.id % 10 < percentage.to_i / 10 + (user.id.hash + feature.hash) % 100 < percentage.to_i end end From 392cf1e78de0fb39a273cc3e3a89a78c67a70a69 Mon Sep 17 00:00:00 2001 From: Leigh Caplan Date: Sun, 17 Aug 2014 12:00:38 -0700 Subject: [PATCH 2/4] Better, repeatable hashing. --- lib/rollout.rb | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/rollout.rb b/lib/rollout.rb index 2c3f288..7f5f922 100644 --- a/lib/rollout.rb +++ b/lib/rollout.rb @@ -89,6 +89,17 @@ def user_within_active_percentage?(feature, user) percentage = percentage(feature) return false if percentage.nil? - (user.id.hash + feature.hash) % 100 < percentage.to_i + (integer_hash(user.id) + integer_hash(feature)) % 100 < percentage.to_i + end + + def integer_hash(obj) + str = obj.to_s + + hash = Digest::SHA1.hexdigest(str) + + # only take 20 digits + hash = hash[0..19] + + hash.to_i(16) end end From d26f2d7f84e87ac82c383f25a84cbae0e3c74672 Mon Sep 17 00:00:00 2001 From: Leigh Caplan Date: Sun, 17 Aug 2014 12:04:11 -0700 Subject: [PATCH 3/4] Nicer hash wrappers. --- lib/rollout.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/rollout.rb b/lib/rollout.rb index 7f5f922..e483b92 100644 --- a/lib/rollout.rb +++ b/lib/rollout.rb @@ -89,7 +89,11 @@ def user_within_active_percentage?(feature, user) percentage = percentage(feature) return false if percentage.nil? - (integer_hash(user.id) + integer_hash(feature)) % 100 < percentage.to_i + combined_hash(user.id, feature) % 100 < percentage.to_i + end + + def combined_hash(*objects) + objects.inject(0) { |m,o| m + integer_hash(o) } end def integer_hash(obj) From b522931c37ec270743180415a982c7cc4d8b06e0 Mon Sep 17 00:00:00 2001 From: Leigh Caplan Date: Mon, 18 Aug 2014 10:05:09 -0700 Subject: [PATCH 4/4] Use CRC32 --- lib/rollout.rb | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/lib/rollout.rb b/lib/rollout.rb index e483b92..f1c901d 100644 --- a/lib/rollout.rb +++ b/lib/rollout.rb @@ -1,3 +1,5 @@ +require 'zlib' + class Rollout attr_accessor :redis, :groups @@ -97,13 +99,6 @@ def combined_hash(*objects) end def integer_hash(obj) - str = obj.to_s - - hash = Digest::SHA1.hexdigest(str) - - # only take 20 digits - hash = hash[0..19] - - hash.to_i(16) + Zlib.crc32 obj.to_s end end