vanity 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +4 -0
 - data/lib/vanity.rb +1 -1
 - data/vanity.gemspec +2 -4
 - data/vendor/redis-0.1/LICENSE +20 -0
 - data/vendor/redis-0.1/README.markdown +36 -0
 - data/vendor/redis-0.1/Rakefile +62 -0
 - data/vendor/redis-0.1/lib/dist_redis.rb +124 -0
 - data/vendor/redis-0.1/lib/hash_ring.rb +128 -0
 - data/vendor/redis-0.1/lib/pipeline.rb +23 -0
 - data/vendor/redis-0.1/lib/redis.rb +352 -0
 - data/vendor/redis-0.1/lib/redis/raketasks.rb +1 -0
 - data/vendor/redis-0.1/spec/redis_spec.rb +524 -0
 - data/vendor/redis-0.1/spec/spec_helper.rb +4 -0
 - data/vendor/redis-0.1/tasks/redis.tasks.rb +136 -0
 - metadata +15 -13
 
    
        data/CHANGELOG
    CHANGED
    
    | 
         @@ -1,3 +1,7 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            0.3.1 (2009-11-13)
         
     | 
| 
      
 2 
     | 
    
         
            +
            * Changed: Redis 1.0 is now vendored into Vanity. This means one less
         
     | 
| 
      
 3 
     | 
    
         
            +
            dependecy ... actually two, since Redis brings with it RSpec.
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
       1 
5 
     | 
    
         
             
            0.3.0 (2009-11-13)
         
     | 
| 
       2 
6 
     | 
    
         
             
            * Added: score now includes least performing alternatives, names and values.
         
     | 
| 
       3 
7 
     | 
    
         
             
            * Added: shiny reports.
         
     | 
    
        data/lib/vanity.rb
    CHANGED
    
    | 
         @@ -1,3 +1,4 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            $LOAD_PATH.unshift File.join(File.dirname(__FILE__), "../vendor/redis-0.1/lib")
         
     | 
| 
       1 
2 
     | 
    
         
             
            require "redis"
         
     | 
| 
       2 
3 
     | 
    
         
             
            require "openssl"
         
     | 
| 
       3 
4 
     | 
    
         | 
| 
         @@ -16,7 +17,6 @@ module Vanity 
     | 
|
| 
       16 
17 
     | 
    
         
             
              end
         
     | 
| 
       17 
18 
     | 
    
         
             
            end
         
     | 
| 
       18 
19 
     | 
    
         | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
       20 
20 
     | 
    
         
             
            require "vanity/playground"
         
     | 
| 
       21 
21 
     | 
    
         
             
            require "vanity/experiment/base"
         
     | 
| 
       22 
22 
     | 
    
         
             
            require "vanity/experiment/ab_test"
         
     | 
    
        data/vanity.gemspec
    CHANGED
    
    | 
         @@ -1,6 +1,6 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            Gem::Specification.new do |spec|
         
     | 
| 
       2 
2 
     | 
    
         
             
              spec.name           = "vanity"
         
     | 
| 
       3 
     | 
    
         
            -
              spec.version        = "0.3. 
     | 
| 
      
 3 
     | 
    
         
            +
              spec.version        = "0.3.1"
         
     | 
| 
       4 
4 
     | 
    
         
             
              spec.author         = "Assaf Arkin"
         
     | 
| 
       5 
5 
     | 
    
         
             
              spec.email          = "assaf@labnotes.org"
         
     | 
| 
       6 
6 
     | 
    
         
             
              spec.homepage       = "http://assaf.github.com/vanity"
         
     | 
| 
         @@ -8,13 +8,11 @@ Gem::Specification.new do |spec| 
     | 
|
| 
       8 
8 
     | 
    
         
             
              spec.description    = "Mirror, mirror on the wall ..."
         
     | 
| 
       9 
9 
     | 
    
         
             
              spec.post_install_message = "To get started run vanity --help"
         
     | 
| 
       10 
10 
     | 
    
         | 
| 
       11 
     | 
    
         
            -
              spec.files          = Dir["{bin,lib, 
     | 
| 
      
 11 
     | 
    
         
            +
              spec.files          = Dir["{bin,lib,vendor,test}/**/*", "CHANGELOG", "MIT-LICENSE", "README.rdoc", "vanity.gemspec"]
         
     | 
| 
       12 
12 
     | 
    
         
             
              spec.executable     = "vanity"
         
     | 
| 
       13 
13 
     | 
    
         | 
| 
       14 
14 
     | 
    
         
             
              spec.has_rdoc         = true
         
     | 
| 
       15 
15 
     | 
    
         
             
              spec.extra_rdoc_files = "README.rdoc", "CHANGELOG"
         
     | 
| 
       16 
16 
     | 
    
         
             
              spec.rdoc_options     = "--title", "Vanity #{spec.version}", "--main", "README.rdoc",
         
     | 
| 
       17 
17 
     | 
    
         
             
                                      "--webcvs", "http://github.com/assaf/#{spec.name}"
         
     | 
| 
       18 
     | 
    
         
            -
             
     | 
| 
       19 
     | 
    
         
            -
              spec.add_dependency "redis", "0.1"
         
     | 
| 
       20 
18 
     | 
    
         
             
            end
         
     | 
| 
         @@ -0,0 +1,20 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            Copyright (c) 2009 Ezra Zygmuntowicz
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            Permission is hereby granted, free of charge, to any person obtaining
         
     | 
| 
      
 4 
     | 
    
         
            +
            a copy of this software and associated documentation files (the
         
     | 
| 
      
 5 
     | 
    
         
            +
            "Software"), to deal in the Software without restriction, including
         
     | 
| 
      
 6 
     | 
    
         
            +
            without limitation the rights to use, copy, modify, merge, publish,
         
     | 
| 
      
 7 
     | 
    
         
            +
            distribute, sublicense, and/or sell copies of the Software, and to
         
     | 
| 
      
 8 
     | 
    
         
            +
            permit persons to whom the Software is furnished to do so, subject to
         
     | 
| 
      
 9 
     | 
    
         
            +
            the following conditions:
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            The above copyright notice and this permission notice shall be
         
     | 
| 
      
 12 
     | 
    
         
            +
            included in all copies or substantial portions of the Software.
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
         
     | 
| 
      
 15 
     | 
    
         
            +
            EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
         
     | 
| 
      
 16 
     | 
    
         
            +
            MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
         
     | 
| 
      
 17 
     | 
    
         
            +
            NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
         
     | 
| 
      
 18 
     | 
    
         
            +
            LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
         
     | 
| 
      
 19 
     | 
    
         
            +
            OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
         
     | 
| 
      
 20 
     | 
    
         
            +
            WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
         
     | 
| 
         @@ -0,0 +1,36 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # redis-rb
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            A ruby client library for the redis key value storage system.
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            ## Information about redis
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            Redis is a key value store with some interesting features:
         
     | 
| 
      
 8 
     | 
    
         
            +
            1. It's fast.
         
     | 
| 
      
 9 
     | 
    
         
            +
            2. Keys are strings but values can have types of "NONE", "STRING", "LIST",  or "SET".  List's can be atomically push'd, pop'd, lpush'd, lpop'd and indexed.  This allows you to store things like lists of comments under one key while retaining the ability to append comments without reading and putting back the whole list.
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            See [redis on code.google.com](http://code.google.com/p/redis/wiki/README) for more information.
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            See the build on [RunCodeRun](http://runcoderun.com/rsanheim/redis-rb)
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            ## Dependencies
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            1. rspec - 
         
     | 
| 
      
 18 
     | 
    
         
            +
            		sudo gem install rspec
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
            2. redis - 
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
            		rake redis:install
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
            2. dtach - 
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
            		rake dtach:install
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
            3. git - git is the new black.
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
            ## Setup
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
            Use the tasks mentioned above (in Dependencies) to get your machine setup.
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
            ## Examples
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
            Check the examples/ directory.  *Note* you need to have redis-server running first.
         
     | 
| 
         @@ -0,0 +1,62 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'rubygems'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'rake/gempackagetask'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'rubygems/specification'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'date'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'spec/rake/spectask'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'tasks/redis.tasks'
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            GEM = 'redis'
         
     | 
| 
      
 10 
     | 
    
         
            +
            GEM_NAME = 'redis'
         
     | 
| 
      
 11 
     | 
    
         
            +
            GEM_VERSION = '0.1'
         
     | 
| 
      
 12 
     | 
    
         
            +
            AUTHORS = ['Ezra Zygmuntowicz', 'Taylor Weibley', 'Matthew Clark', 'Brian McKinney', 'Salvatore Sanfilippo', 'Luca Guidi']
         
     | 
| 
      
 13 
     | 
    
         
            +
            EMAIL = "ez@engineyard.com"
         
     | 
| 
      
 14 
     | 
    
         
            +
            HOMEPAGE = "http://github.com/ezmobius/redis-rb"
         
     | 
| 
      
 15 
     | 
    
         
            +
            SUMMARY = "Ruby client library for redis key value storage server"
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            spec = Gem::Specification.new do |s|
         
     | 
| 
      
 18 
     | 
    
         
            +
              s.name = GEM
         
     | 
| 
      
 19 
     | 
    
         
            +
              s.version = GEM_VERSION
         
     | 
| 
      
 20 
     | 
    
         
            +
              s.platform = Gem::Platform::RUBY
         
     | 
| 
      
 21 
     | 
    
         
            +
              s.has_rdoc = true
         
     | 
| 
      
 22 
     | 
    
         
            +
              s.extra_rdoc_files = ["LICENSE"]
         
     | 
| 
      
 23 
     | 
    
         
            +
              s.summary = SUMMARY
         
     | 
| 
      
 24 
     | 
    
         
            +
              s.description = s.summary
         
     | 
| 
      
 25 
     | 
    
         
            +
              s.authors = AUTHORS
         
     | 
| 
      
 26 
     | 
    
         
            +
              s.email = EMAIL
         
     | 
| 
      
 27 
     | 
    
         
            +
              s.homepage = HOMEPAGE
         
     | 
| 
      
 28 
     | 
    
         
            +
              s.add_dependency "rspec"
         
     | 
| 
      
 29 
     | 
    
         
            +
              s.require_path = 'lib'
         
     | 
| 
      
 30 
     | 
    
         
            +
              s.autorequire = GEM
         
     | 
| 
      
 31 
     | 
    
         
            +
              s.files = %w(LICENSE README.markdown Rakefile) + Dir.glob("{lib,tasks,spec}/**/*")
         
     | 
| 
      
 32 
     | 
    
         
            +
            end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
            task :default => :spec
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
            desc "Run specs"
         
     | 
| 
      
 37 
     | 
    
         
            +
            Spec::Rake::SpecTask.new do |t|
         
     | 
| 
      
 38 
     | 
    
         
            +
              t.spec_files = FileList['spec/**/*_spec.rb']
         
     | 
| 
      
 39 
     | 
    
         
            +
              t.spec_opts = %w(-fs --color)
         
     | 
| 
      
 40 
     | 
    
         
            +
            end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
            Rake::GemPackageTask.new(spec) do |pkg|
         
     | 
| 
      
 43 
     | 
    
         
            +
              pkg.gem_spec = spec
         
     | 
| 
      
 44 
     | 
    
         
            +
            end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
            desc "install the gem locally"
         
     | 
| 
      
 47 
     | 
    
         
            +
            task :install => [:package] do
         
     | 
| 
      
 48 
     | 
    
         
            +
              sh %{sudo gem install pkg/#{GEM}-#{GEM_VERSION}}
         
     | 
| 
      
 49 
     | 
    
         
            +
            end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
            desc "create a gemspec file"
         
     | 
| 
      
 52 
     | 
    
         
            +
            task :make_spec do
         
     | 
| 
      
 53 
     | 
    
         
            +
              File.open("#{GEM}.gemspec", "w") do |file|
         
     | 
| 
      
 54 
     | 
    
         
            +
                file.puts spec.to_ruby
         
     | 
| 
      
 55 
     | 
    
         
            +
              end
         
     | 
| 
      
 56 
     | 
    
         
            +
            end
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
            desc "Run all examples with RCov"
         
     | 
| 
      
 59 
     | 
    
         
            +
            Spec::Rake::SpecTask.new(:rcov) do |t|
         
     | 
| 
      
 60 
     | 
    
         
            +
              t.spec_files = FileList['spec/**/*_spec.rb']
         
     | 
| 
      
 61 
     | 
    
         
            +
              t.rcov = true
         
     | 
| 
      
 62 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,124 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'redis'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'hash_ring'
         
     | 
| 
      
 3 
     | 
    
         
            +
            class DistRedis
         
     | 
| 
      
 4 
     | 
    
         
            +
              attr_reader :ring
         
     | 
| 
      
 5 
     | 
    
         
            +
              def initialize(opts={})
         
     | 
| 
      
 6 
     | 
    
         
            +
                hosts = []
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                db = opts[:db] || nil
         
     | 
| 
      
 9 
     | 
    
         
            +
                timeout = opts[:timeout] || nil
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                raise Error, "No hosts given" unless opts[:hosts]
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                opts[:hosts].each do |h|
         
     | 
| 
      
 14 
     | 
    
         
            +
                  host, port = h.split(':')
         
     | 
| 
      
 15 
     | 
    
         
            +
                  hosts << Redis.new(:host => host, :port => port, :db => db, :timeout => timeout)
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                @ring = HashRing.new hosts
         
     | 
| 
      
 19 
     | 
    
         
            +
              end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
              def node_for_key(key)
         
     | 
| 
      
 22 
     | 
    
         
            +
                key = $1 if key =~ /\{(.*)?\}/
         
     | 
| 
      
 23 
     | 
    
         
            +
                @ring.get_node(key)
         
     | 
| 
      
 24 
     | 
    
         
            +
              end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
              def add_server(server)
         
     | 
| 
      
 27 
     | 
    
         
            +
                server, port = server.split(':')
         
     | 
| 
      
 28 
     | 
    
         
            +
                @ring.add_node Redis.new(:host => server, :port => port)
         
     | 
| 
      
 29 
     | 
    
         
            +
              end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
              def method_missing(sym, *args, &blk)
         
     | 
| 
      
 32 
     | 
    
         
            +
                if redis = node_for_key(args.first.to_s)
         
     | 
| 
      
 33 
     | 
    
         
            +
                  redis.send sym, *args, &blk
         
     | 
| 
      
 34 
     | 
    
         
            +
                else
         
     | 
| 
      
 35 
     | 
    
         
            +
                  super
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
              end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
              def keys(glob)
         
     | 
| 
      
 40 
     | 
    
         
            +
                @ring.nodes.map do |red|
         
     | 
| 
      
 41 
     | 
    
         
            +
                  red.keys(glob)
         
     | 
| 
      
 42 
     | 
    
         
            +
                end
         
     | 
| 
      
 43 
     | 
    
         
            +
              end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
              def save
         
     | 
| 
      
 46 
     | 
    
         
            +
                on_each_node :save
         
     | 
| 
      
 47 
     | 
    
         
            +
              end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
              def bgsave
         
     | 
| 
      
 50 
     | 
    
         
            +
                on_each_node :bgsave
         
     | 
| 
      
 51 
     | 
    
         
            +
              end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
              def quit
         
     | 
| 
      
 54 
     | 
    
         
            +
                on_each_node :quit
         
     | 
| 
      
 55 
     | 
    
         
            +
              end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
              def flush_all
         
     | 
| 
      
 58 
     | 
    
         
            +
                on_each_node :flush_all
         
     | 
| 
      
 59 
     | 
    
         
            +
              end
         
     | 
| 
      
 60 
     | 
    
         
            +
              alias_method :flushall, :flush_all
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
              def flush_db
         
     | 
| 
      
 63 
     | 
    
         
            +
                on_each_node :flush_db
         
     | 
| 
      
 64 
     | 
    
         
            +
              end
         
     | 
| 
      
 65 
     | 
    
         
            +
              alias_method :flushdb, :flush_db
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
              def delete_cloud!
         
     | 
| 
      
 68 
     | 
    
         
            +
                @ring.nodes.each do |red|
         
     | 
| 
      
 69 
     | 
    
         
            +
                  red.keys("*").each do |key|
         
     | 
| 
      
 70 
     | 
    
         
            +
                    red.delete key
         
     | 
| 
      
 71 
     | 
    
         
            +
                  end
         
     | 
| 
      
 72 
     | 
    
         
            +
                end
         
     | 
| 
      
 73 
     | 
    
         
            +
              end
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
              def on_each_node(command, *args)
         
     | 
| 
      
 76 
     | 
    
         
            +
                @ring.nodes.each do |red|
         
     | 
| 
      
 77 
     | 
    
         
            +
                  red.send(command, *args)
         
     | 
| 
      
 78 
     | 
    
         
            +
                end
         
     | 
| 
      
 79 
     | 
    
         
            +
              end
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
            end
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
            if __FILE__ == $0
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
            r = DistRedis.new 'localhost:6379', 'localhost:6380', 'localhost:6381', 'localhost:6382'
         
     | 
| 
      
 87 
     | 
    
         
            +
              r['urmom'] = 'urmom'
         
     | 
| 
      
 88 
     | 
    
         
            +
              r['urdad'] = 'urdad'
         
     | 
| 
      
 89 
     | 
    
         
            +
              r['urmom1'] = 'urmom1'
         
     | 
| 
      
 90 
     | 
    
         
            +
              r['urdad1'] = 'urdad1'
         
     | 
| 
      
 91 
     | 
    
         
            +
              r['urmom2'] = 'urmom2'
         
     | 
| 
      
 92 
     | 
    
         
            +
              r['urdad2'] = 'urdad2'
         
     | 
| 
      
 93 
     | 
    
         
            +
              r['urmom3'] = 'urmom3'
         
     | 
| 
      
 94 
     | 
    
         
            +
              r['urdad3'] = 'urdad3'
         
     | 
| 
      
 95 
     | 
    
         
            +
              p r['urmom']
         
     | 
| 
      
 96 
     | 
    
         
            +
              p r['urdad']
         
     | 
| 
      
 97 
     | 
    
         
            +
              p r['urmom1']
         
     | 
| 
      
 98 
     | 
    
         
            +
              p r['urdad1']
         
     | 
| 
      
 99 
     | 
    
         
            +
              p r['urmom2']
         
     | 
| 
      
 100 
     | 
    
         
            +
              p r['urdad2']
         
     | 
| 
      
 101 
     | 
    
         
            +
              p r['urmom3']
         
     | 
| 
      
 102 
     | 
    
         
            +
              p r['urdad3']
         
     | 
| 
      
 103 
     | 
    
         
            +
             
     | 
| 
      
 104 
     | 
    
         
            +
              r.push_tail 'listor', 'foo1'
         
     | 
| 
      
 105 
     | 
    
         
            +
              r.push_tail 'listor', 'foo2'
         
     | 
| 
      
 106 
     | 
    
         
            +
              r.push_tail 'listor', 'foo3'
         
     | 
| 
      
 107 
     | 
    
         
            +
              r.push_tail 'listor', 'foo4'
         
     | 
| 
      
 108 
     | 
    
         
            +
              r.push_tail 'listor', 'foo5'
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
      
 110 
     | 
    
         
            +
              p r.pop_tail('listor')
         
     | 
| 
      
 111 
     | 
    
         
            +
              p r.pop_tail('listor')
         
     | 
| 
      
 112 
     | 
    
         
            +
              p r.pop_tail('listor')
         
     | 
| 
      
 113 
     | 
    
         
            +
              p r.pop_tail('listor')
         
     | 
| 
      
 114 
     | 
    
         
            +
              p r.pop_tail('listor')
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
              puts "key distribution:"
         
     | 
| 
      
 117 
     | 
    
         
            +
             
     | 
| 
      
 118 
     | 
    
         
            +
              r.ring.nodes.each do |red|
         
     | 
| 
      
 119 
     | 
    
         
            +
                p [red.port, red.keys("*")]
         
     | 
| 
      
 120 
     | 
    
         
            +
              end
         
     | 
| 
      
 121 
     | 
    
         
            +
              r.delete_cloud!
         
     | 
| 
      
 122 
     | 
    
         
            +
              p r.keys('*')
         
     | 
| 
      
 123 
     | 
    
         
            +
             
     | 
| 
      
 124 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,128 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'zlib'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            class HashRing
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
              POINTS_PER_SERVER = 160 # this is the default in libmemcached
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
              attr_reader :ring, :sorted_keys, :replicas, :nodes
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
              # nodes is a list of objects that have a proper to_s representation.
         
     | 
| 
      
 10 
     | 
    
         
            +
              # replicas indicates how many virtual points should be used pr. node,
         
     | 
| 
      
 11 
     | 
    
         
            +
              # replicas are required to improve the distribution.
         
     | 
| 
      
 12 
     | 
    
         
            +
              def initialize(nodes=[], replicas=POINTS_PER_SERVER)
         
     | 
| 
      
 13 
     | 
    
         
            +
                @replicas = replicas
         
     | 
| 
      
 14 
     | 
    
         
            +
                @ring = {}
         
     | 
| 
      
 15 
     | 
    
         
            +
                @nodes = []
         
     | 
| 
      
 16 
     | 
    
         
            +
                @sorted_keys = []
         
     | 
| 
      
 17 
     | 
    
         
            +
                nodes.each do |node|
         
     | 
| 
      
 18 
     | 
    
         
            +
                  add_node(node)
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
              end
         
     | 
| 
      
 21 
     | 
    
         
            +
              
         
     | 
| 
      
 22 
     | 
    
         
            +
              # Adds a `node` to the hash ring (including a number of replicas).
         
     | 
| 
      
 23 
     | 
    
         
            +
              def add_node(node)
         
     | 
| 
      
 24 
     | 
    
         
            +
                @nodes << node
         
     | 
| 
      
 25 
     | 
    
         
            +
                @replicas.times do |i|
         
     | 
| 
      
 26 
     | 
    
         
            +
                  key = Zlib.crc32("#{node}:#{i}")
         
     | 
| 
      
 27 
     | 
    
         
            +
                  @ring[key] = node
         
     | 
| 
      
 28 
     | 
    
         
            +
                  @sorted_keys << key
         
     | 
| 
      
 29 
     | 
    
         
            +
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
                @sorted_keys.sort!
         
     | 
| 
      
 31 
     | 
    
         
            +
              end
         
     | 
| 
      
 32 
     | 
    
         
            +
              
         
     | 
| 
      
 33 
     | 
    
         
            +
              def remove_node(node)
         
     | 
| 
      
 34 
     | 
    
         
            +
                @nodes.reject!{|n| n.to_s == node.to_s}
         
     | 
| 
      
 35 
     | 
    
         
            +
                @replicas.times do |i|
         
     | 
| 
      
 36 
     | 
    
         
            +
                  key = Zlib.crc32("#{node}:#{i}")
         
     | 
| 
      
 37 
     | 
    
         
            +
                  @ring.delete(key)
         
     | 
| 
      
 38 
     | 
    
         
            +
                  @sorted_keys.reject! {|k| k == key}
         
     | 
| 
      
 39 
     | 
    
         
            +
                end
         
     | 
| 
      
 40 
     | 
    
         
            +
              end
         
     | 
| 
      
 41 
     | 
    
         
            +
              
         
     | 
| 
      
 42 
     | 
    
         
            +
              # get the node in the hash ring for this key
         
     | 
| 
      
 43 
     | 
    
         
            +
              def get_node(key)
         
     | 
| 
      
 44 
     | 
    
         
            +
                get_node_pos(key)[0]
         
     | 
| 
      
 45 
     | 
    
         
            +
              end
         
     | 
| 
      
 46 
     | 
    
         
            +
              
         
     | 
| 
      
 47 
     | 
    
         
            +
              def get_node_pos(key)
         
     | 
| 
      
 48 
     | 
    
         
            +
                return [nil,nil] if @ring.size == 0
         
     | 
| 
      
 49 
     | 
    
         
            +
                crc = Zlib.crc32(key)
         
     | 
| 
      
 50 
     | 
    
         
            +
                idx = HashRing.binary_search(@sorted_keys, crc)
         
     | 
| 
      
 51 
     | 
    
         
            +
                return [@ring[@sorted_keys[idx]], idx]
         
     | 
| 
      
 52 
     | 
    
         
            +
              end
         
     | 
| 
      
 53 
     | 
    
         
            +
              
         
     | 
| 
      
 54 
     | 
    
         
            +
              def iter_nodes(key)
         
     | 
| 
      
 55 
     | 
    
         
            +
                return [nil,nil] if @ring.size == 0
         
     | 
| 
      
 56 
     | 
    
         
            +
                node, pos = get_node_pos(key)
         
     | 
| 
      
 57 
     | 
    
         
            +
                @sorted_keys[pos..-1].each do |k|
         
     | 
| 
      
 58 
     | 
    
         
            +
                  yield @ring[k]
         
     | 
| 
      
 59 
     | 
    
         
            +
                end  
         
     | 
| 
      
 60 
     | 
    
         
            +
              end
         
     | 
| 
      
 61 
     | 
    
         
            +
              
         
     | 
| 
      
 62 
     | 
    
         
            +
              class << self
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                # gem install RubyInline to use this code
         
     | 
| 
      
 65 
     | 
    
         
            +
                # Native extension to perform the binary search within the hashring.
         
     | 
| 
      
 66 
     | 
    
         
            +
                # There's a pure ruby version below so this is purely optional
         
     | 
| 
      
 67 
     | 
    
         
            +
                # for performance.  In testing 20k gets and sets, the native
         
     | 
| 
      
 68 
     | 
    
         
            +
                # binary search shaved about 12% off the runtime (9sec -> 8sec).
         
     | 
| 
      
 69 
     | 
    
         
            +
                begin
         
     | 
| 
      
 70 
     | 
    
         
            +
                  require 'inline'
         
     | 
| 
      
 71 
     | 
    
         
            +
                  inline do |builder|
         
     | 
| 
      
 72 
     | 
    
         
            +
                    builder.c <<-EOM
         
     | 
| 
      
 73 
     | 
    
         
            +
                    int binary_search(VALUE ary, unsigned int r) {
         
     | 
| 
      
 74 
     | 
    
         
            +
                        int upper = RARRAY_LEN(ary) - 1;
         
     | 
| 
      
 75 
     | 
    
         
            +
                        int lower = 0;
         
     | 
| 
      
 76 
     | 
    
         
            +
                        int idx = 0;
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                        while (lower <= upper) {
         
     | 
| 
      
 79 
     | 
    
         
            +
                            idx = (lower + upper) / 2;
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
                            VALUE continuumValue = RARRAY_PTR(ary)[idx];
         
     | 
| 
      
 82 
     | 
    
         
            +
                            unsigned int l = NUM2UINT(continuumValue);
         
     | 
| 
      
 83 
     | 
    
         
            +
                            if (l == r) {
         
     | 
| 
      
 84 
     | 
    
         
            +
                                return idx;
         
     | 
| 
      
 85 
     | 
    
         
            +
                            }
         
     | 
| 
      
 86 
     | 
    
         
            +
                            else if (l > r) {
         
     | 
| 
      
 87 
     | 
    
         
            +
                                upper = idx - 1;
         
     | 
| 
      
 88 
     | 
    
         
            +
                            }
         
     | 
| 
      
 89 
     | 
    
         
            +
                            else {
         
     | 
| 
      
 90 
     | 
    
         
            +
                                lower = idx + 1;
         
     | 
| 
      
 91 
     | 
    
         
            +
                            }
         
     | 
| 
      
 92 
     | 
    
         
            +
                        }
         
     | 
| 
      
 93 
     | 
    
         
            +
                        return upper;
         
     | 
| 
      
 94 
     | 
    
         
            +
                    }
         
     | 
| 
      
 95 
     | 
    
         
            +
                    EOM
         
     | 
| 
      
 96 
     | 
    
         
            +
                  end
         
     | 
| 
      
 97 
     | 
    
         
            +
                rescue Exception => e
         
     | 
| 
      
 98 
     | 
    
         
            +
                  # Find the closest index in HashRing with value <= the given value
         
     | 
| 
      
 99 
     | 
    
         
            +
                  def binary_search(ary, value, &block)
         
     | 
| 
      
 100 
     | 
    
         
            +
                    upper = ary.size - 1
         
     | 
| 
      
 101 
     | 
    
         
            +
                    lower = 0
         
     | 
| 
      
 102 
     | 
    
         
            +
                    idx = 0
         
     | 
| 
      
 103 
     | 
    
         
            +
             
     | 
| 
      
 104 
     | 
    
         
            +
                    while(lower <= upper) do
         
     | 
| 
      
 105 
     | 
    
         
            +
                      idx = (lower + upper) / 2
         
     | 
| 
      
 106 
     | 
    
         
            +
                      comp = ary[idx] <=> value
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
                      if comp == 0
         
     | 
| 
      
 109 
     | 
    
         
            +
                        return idx
         
     | 
| 
      
 110 
     | 
    
         
            +
                      elsif comp > 0
         
     | 
| 
      
 111 
     | 
    
         
            +
                        upper = idx - 1
         
     | 
| 
      
 112 
     | 
    
         
            +
                      else
         
     | 
| 
      
 113 
     | 
    
         
            +
                        lower = idx + 1
         
     | 
| 
      
 114 
     | 
    
         
            +
                      end
         
     | 
| 
      
 115 
     | 
    
         
            +
                    end
         
     | 
| 
      
 116 
     | 
    
         
            +
                    return upper
         
     | 
| 
      
 117 
     | 
    
         
            +
                  end
         
     | 
| 
      
 118 
     | 
    
         
            +
             
     | 
| 
      
 119 
     | 
    
         
            +
                end
         
     | 
| 
      
 120 
     | 
    
         
            +
              end
         
     | 
| 
      
 121 
     | 
    
         
            +
             
     | 
| 
      
 122 
     | 
    
         
            +
            end
         
     | 
| 
      
 123 
     | 
    
         
            +
             
     | 
| 
      
 124 
     | 
    
         
            +
            # ring = HashRing.new ['server1', 'server2', 'server3']
         
     | 
| 
      
 125 
     | 
    
         
            +
            # p ring
         
     | 
| 
      
 126 
     | 
    
         
            +
            # #
         
     | 
| 
      
 127 
     | 
    
         
            +
            # p ring.get_node "kjhjkjlkjlkkh"
         
     | 
| 
      
 128 
     | 
    
         
            +
            # 
         
     | 
| 
         @@ -0,0 +1,23 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "redis"
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            class Redis
         
     | 
| 
      
 4 
     | 
    
         
            +
              class Pipeline < Redis
         
     | 
| 
      
 5 
     | 
    
         
            +
                BUFFER_SIZE = 50_000
         
     | 
| 
      
 6 
     | 
    
         
            +
                
         
     | 
| 
      
 7 
     | 
    
         
            +
                def initialize(redis)
         
     | 
| 
      
 8 
     | 
    
         
            +
                  @redis = redis
         
     | 
| 
      
 9 
     | 
    
         
            +
                  @commands = []
         
     | 
| 
      
 10 
     | 
    
         
            +
                end
         
     | 
| 
      
 11 
     | 
    
         
            +
               
         
     | 
| 
      
 12 
     | 
    
         
            +
                def call_command(command)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  @commands << command
         
     | 
| 
      
 14 
     | 
    
         
            +
                end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                def execute
         
     | 
| 
      
 17 
     | 
    
         
            +
                  return if @commands.empty?
         
     | 
| 
      
 18 
     | 
    
         
            +
                  @redis.call_command(@commands)
         
     | 
| 
      
 19 
     | 
    
         
            +
                  @commands.clear
         
     | 
| 
      
 20 
     | 
    
         
            +
                end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
              end
         
     | 
| 
      
 23 
     | 
    
         
            +
            end
         
     |