redis_pipeliner 0.0.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/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in redis_pipeliner.gemspec
4
+ gemspec
5
+
data/README.md ADDED
@@ -0,0 +1,49 @@
1
+ # Ruby gem for easily pipelining REDIS commands
2
+ https://github.com/mrdanadams/redis_pipeliner
3
+
4
+ (Inspired by this blog post on [5-10x Speed Ups by Pipeling Multiple REDIS Commands in Ruby](http://mrdanadams.com/2012/pipeline-redis-commands-ruby/) by [Dan Adams](http://mrdanadams.com).)
5
+
6
+ [Pipelining in REDIS](https://github.com/redis/redis-rb#pipelining) is a great way to stay performant when executing multiple commands. It should also be easy to use.
7
+
8
+ ## Usage
9
+
10
+ Basic usage involves:
11
+
12
+ 1. Enqueueing a number of REDIS commands inside a `pipelined` block
13
+ 2. Doing something with the results either afterwards or inside blocks specific to each command.
14
+
15
+ Ex: (a bit contrived...)
16
+
17
+ ```ruby
18
+ # Put a bunch of values in a few different hashes
19
+ redis = Redis.connect
20
+ redis.hset "h1", "foo", 1
21
+ redis.hset "h2", "bar", 2
22
+ redis.hest "h3", "baz", 3
23
+
24
+ # Get the values pipelined and sum them up
25
+ values = RedisPipeliner.pipeline redis do |p|
26
+ # This would normally be 3 round-trips
27
+ p.enqueue redis.hget("h1", "foo")
28
+ p.enqueue redis.hget("h2", "bar")
29
+ p.enqueue redis.hget("h3", "baz")
30
+ end
31
+ values.map(&:to_i).inject(&:+).should == 6
32
+ ```
33
+
34
+ You can also pass in a block to be called for each value rather than operating on the values afterwards:
35
+
36
+ ```ruby
37
+ results = []
38
+ RedisPipeliner.pipeline redis do |p|
39
+ [%w(h1 foo), %w(h2 bar), %w(h3 baz)].each do |pair|
40
+ p.enqueue redis.hget(pair[0], pair[1]) do |value|
41
+ # referencing pair inside the block
42
+ results << pair[1] + value
43
+ end
44
+ end
45
+ end
46
+ results.first.should == "foo1"
47
+ ```
48
+
49
+ See the specs for executable examples.
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,44 @@
1
+ module RedisPipeliner
2
+ # Enqueues commands in a pipeline and waits until they are finished.
3
+ # Usage pattern is to call #enqueue with each REDIS future and a block to process it,
4
+ # then call #wait outside the Redis.pipelined call.
5
+ class Pipeliner
6
+ def initialize(redis)
7
+ @redis = redis
8
+ @commands = []
9
+ end
10
+
11
+ # Adds a command (a Future, actually) with an option block to call when the Future has been realized.
12
+ def enqueue(future, &proc)
13
+ @commands << { future: future, callback: proc }
14
+ end
15
+
16
+ # Blocks until all Futures have been realized and returns the values.
17
+ # This should be called _outside_ the Redis.pipelined call.
18
+ # Note that the value enqueue is the REDIS return value, not the value returned by any passed block.
19
+ # Nil values will be included in the return values (if that's what REDIS gives us).
20
+ def values
21
+ return @values unless @values.nil?
22
+
23
+ @values = []
24
+ @commands.each do |cmd|
25
+ while cmd[:future].value.is_a?(Redis::FutureNotReady)
26
+ sleep(1.0 / 100.0)
27
+ end
28
+
29
+ v = cmd[:future].value
30
+ cmd[:callback].call(v) unless cmd[:callback].nil?
31
+ @values << v
32
+ end
33
+
34
+ @values
35
+ end
36
+
37
+ # Returns the enqueue REDIS commands
38
+ def commands
39
+ @commands.map {|h| h[:future] }
40
+ end
41
+
42
+ alias_method :wait, :values
43
+ end
44
+ end
@@ -0,0 +1,3 @@
1
+ module RedisPipeliner
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,17 @@
1
+ require "redis_pipeliner/version"
2
+ require "redis"
3
+ require "redis_pipeliner/pipeliner"
4
+
5
+ module RedisPipeliner
6
+ class << self
7
+ # Convenience for creating a pipeline, enqueueing, and blocking until the results are processed.
8
+ def pipeline(redis, &proc)
9
+ pipeliner = RedisPipeliner::Pipeliner.new(redis)
10
+ redis.pipelined do
11
+ proc.call pipeliner
12
+ end
13
+
14
+ pipeliner.values
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "redis_pipeliner/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "redis_pipeliner"
7
+ s.version = RedisPipeliner::VERSION
8
+ s.authors = ["Dan Adams"]
9
+ s.email = ["mr.danadams@gmail.com"]
10
+ s.homepage = "https://github.com/mrdanadams/redis_pipeliner"
11
+ s.summary = %q{Easy pipelining of REDIS commands}
12
+ s.description = %q{Easy pipelining of REDIS commands}
13
+
14
+ s.rubyforge_project = "redis_pipeliner"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_dependency "redis"
22
+ s.add_development_dependency "rspec"
23
+ s.add_development_dependency "pry"
24
+ end
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+
3
+ describe RedisPipeliner do
4
+ let :redis do
5
+ Redis.connect
6
+ end
7
+
8
+ it 'supports basic usage' do
9
+ redis.del "testhash"
10
+ redis.hset "testhash", "bar", 1
11
+ redis.hset "testhash", "foo", 2
12
+
13
+ redis.hmget("testhash", "foo", "bar").map(&:to_i).inject(&:+).should == 3
14
+
15
+ total = 0
16
+ values = RedisPipeliner.pipeline redis do |pipe|
17
+ %w(bar foo).each do |key|
18
+ pipe.enqueue redis.hget("testhash", key) do |result|
19
+ total += result.to_i
20
+ end
21
+ end
22
+ end
23
+ values.map(&:to_i).inject(&:+).should == 3
24
+ end
25
+
26
+ it 'can reference variables outside the proce' do
27
+ redis.del "testhash"
28
+ redis.hset "testhash", "bar", 1
29
+ redis.hset "testhash", "foo", 2
30
+
31
+ results = []
32
+ RedisPipeliner.pipeline redis do |pipe|
33
+ %w(bar foo).each do |key|
34
+ pipe.enqueue redis.hget("testhash", key) do |result|
35
+ results << key+result
36
+ end
37
+ end
38
+ end
39
+
40
+ results.should == %w(bar1 foo2)
41
+ end
42
+
43
+ it 'should pipelines commands and return values' do
44
+ redis.del "testhash"
45
+ redis.hset "testhash", "bar", 1
46
+ redis.hset "testhash", "foo", 2
47
+
48
+ pipeliner = RedisPipeliner::Pipeliner.new(redis)
49
+ redis.pipelined do
50
+ %w(bar foo).each do |key|
51
+ # allows not having a block
52
+ pipeliner.enqueue redis.hget("testhash", key)
53
+ end
54
+ end
55
+
56
+ pipeliner.commands.first.value.should_not be_nil # you can't test this class for type...
57
+
58
+ pipeliner.values.map(&:to_i).inject(&:+).should == 3
59
+ pipeliner.values.should === pipeliner.values
60
+ end
61
+ end
@@ -0,0 +1,20 @@
1
+ require 'redis_pipeliner'
2
+ require 'pry'
3
+
4
+ # This file was generated by the `rspec --init` command. Conventionally, all
5
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
6
+ # Require this file using `require "spec_helper"` to ensure that it is only
7
+ # loaded once.
8
+ #
9
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
10
+ RSpec.configure do |config|
11
+ config.treat_symbols_as_metadata_keys_with_true_values = true
12
+ config.run_all_when_everything_filtered = true
13
+ config.filter_run :focus
14
+
15
+ # Run specs in random order to surface order dependencies. If you find an
16
+ # order dependency and want to debug it, you can fix the order by providing
17
+ # the seed, which is printed after each run.
18
+ # --seed 1234
19
+ config.order = 'random'
20
+ end
metadata ADDED
@@ -0,0 +1,106 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: redis_pipeliner
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Dan Adams
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-01-05 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: redis
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rspec
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: pry
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ description: Easy pipelining of REDIS commands
63
+ email:
64
+ - mr.danadams@gmail.com
65
+ executables: []
66
+ extensions: []
67
+ extra_rdoc_files: []
68
+ files:
69
+ - .gitignore
70
+ - .rspec
71
+ - Gemfile
72
+ - README.md
73
+ - Rakefile
74
+ - lib/redis_pipeliner.rb
75
+ - lib/redis_pipeliner/pipeliner.rb
76
+ - lib/redis_pipeliner/version.rb
77
+ - redis_pipeliner.gemspec
78
+ - spec/pipeliner_spec.rb
79
+ - spec/spec_helper.rb
80
+ homepage: https://github.com/mrdanadams/redis_pipeliner
81
+ licenses: []
82
+ post_install_message:
83
+ rdoc_options: []
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ none: false
88
+ requirements:
89
+ - - ! '>='
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ required_rubygems_version: !ruby/object:Gem::Requirement
93
+ none: false
94
+ requirements:
95
+ - - ! '>='
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ requirements: []
99
+ rubyforge_project: redis_pipeliner
100
+ rubygems_version: 1.8.24
101
+ signing_key:
102
+ specification_version: 3
103
+ summary: Easy pipelining of REDIS commands
104
+ test_files:
105
+ - spec/pipeliner_spec.rb
106
+ - spec/spec_helper.rb