lib/picky/backends/redis.rb in picky-4.6.3 vs lib/picky/backends/redis.rb in picky-4.6.4

- old
+ new

@@ -167,108 +167,28 @@ @@ids_script = "local intersected = redis.call('zinterstore', ARGV[1], #(KEYS), unpack(KEYS)); if intersected == 0 then redis.call('del', ARGV[1]); return {}; end local results = redis.call('zrange', ARGV[1], tonumber(ARGV[2]), tonumber(ARGV[3])); redis.call('del', ARGV[1]); return results;" require 'digest/sha1' @@ids_sent_once = nil - # Scripting version of #ids. + # Overrides _this_ method. # - class << self - def ids combinations, amount, offset - identifiers = combinations.inject([]) do |identifiers, combination| - identifiers << "#{combination.identifier}" - end - - # Assume it's using EVALSHA. - # - begin - if identifiers.size > 1 - client.evalsha @@ids_sent_once, - identifiers.size, - *identifiers, - generate_intermediate_result_id, - offset, - (offset + amount) - else - client.zrange identifiers.first, - offset, - (offset + amount) - end - rescue RuntimeError => e - # Make the server have a SHA-1 for the script. - # - @@ids_sent_once = Digest::SHA1.hexdigest @@ids_script - client.eval @@ids_script, - identifiers.size, - *identifiers, - generate_intermediate_result_id, - offset, - (offset + amount) - end - end - end + extend Scripting else - # Non-Scripting version of #ids. + # Overrides _this_ method. # - class << self - def ids combinations, amount, offset - identifiers = combinations.inject([]) do |identifiers, combination| - identifiers << "#{combination.identifier}" - end - - result_id = generate_intermediate_result_id - - # Little optimization. - # - if identifiers.size > 1 - # Intersect and store. - # - intersected = client.zinterstore result_id, identifiers - - # Return clean and early if there has been no intersection. - # - if intersected.zero? - client.del result_id - return [] - end - - # Get the stored result. - # - results = client.zrange result_id, offset, (offset + amount) - - # Delete the stored result as it was only for temporary purposes. - # - # Note: I could also not delete it, but that - # would not be clean at all. - # - client.del result_id - else - results = client.zrange identifiers.first, offset, (offset + amount) - end - - results - end - end + extend NonScripting end else - class << self - def ids combinations, _, _ - # Get the ids for each combination. - # - id_arrays = combinations.inject([]) do |total, combination| - total << combination.ids - end - - # Call the optimized C algorithm. - # - # Note: It orders the passed arrays by size. - # - Performant::Array.memory_efficient_intersect id_arrays - end - end + # Remove _this_ method and use the super + # class method from now on. + # + # Note: This fails if there are multiple + # Redis backends with different versions. + # + self.class.send :remove_method, __method__ end - - # Call the newly installed version. + # Call the newly installed / super class version. # ids combinations, amount, offset end # Generate a multiple host/process safe result id. @@ -288,9 +208,88 @@ end # Use the host and pid (generated lazily in child processes) for the result. # def generate_intermediate_result_id @intermediate_result_id ||= "#{host}:#{pid}:picky:result" + end + + # Uses Lua scripting on Redis 2.6. + # + module Scripting + def ids combinations, amount, offset + identifiers = combinations.inject([]) do |identifiers, combination| + identifiers << "#{combination.identifier}" + end + + # Assume it's using EVALSHA. + # + begin + if identifiers.size > 1 + client.evalsha @@ids_sent_once, + identifiers.size, + *identifiers, + generate_intermediate_result_id, + offset, + (offset + amount) + else + client.zrange identifiers.first, + offset, + (offset + amount) + end + rescue RuntimeError => e + # Make the server have a SHA-1 for the script. + # + @@ids_sent_once = Digest::SHA1.hexdigest @@ids_script + client.eval @@ids_script, + identifiers.size, + *identifiers, + generate_intermediate_result_id, + offset, + (offset + amount) + end + end + end + + # Does not use Lua scripting, < Redis 2.6. + # + module NonScripting + def ids combinations, amount, offset + identifiers = combinations.inject([]) do |identifiers, combination| + identifiers << "#{combination.identifier}" + end + + result_id = generate_intermediate_result_id + + # Little optimization. + # + if identifiers.size > 1 + # Intersect and store. + # + intersected = client.zinterstore result_id, identifiers + + # Return clean and early if there has been no intersection. + # + if intersected.zero? + client.del result_id + return [] + end + + # Get the stored result. + # + results = client.zrange result_id, offset, (offset + amount) + + # Delete the stored result as it was only for temporary purposes. + # + # Note: I could also not delete it, but that + # would not be clean at all. + # + client.del result_id + else + results = client.zrange identifiers.first, offset, (offset + amount) + end + + results + end end end end \ No newline at end of file