redis_ring 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ pkg/*
2
+ *.gem
3
+ .bundle
4
+ .rvmrc
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in redis_ring.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,34 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ redis_ring (0.0.1)
5
+ json
6
+ sinatra
7
+
8
+ GEM
9
+ remote: http://rubygems.org/
10
+ specs:
11
+ diff-lcs (1.1.2)
12
+ json (1.5.1)
13
+ mocha (0.9.12)
14
+ rack (1.2.1)
15
+ rspec (2.5.0)
16
+ rspec-core (~> 2.5.0)
17
+ rspec-expectations (~> 2.5.0)
18
+ rspec-mocks (~> 2.5.0)
19
+ rspec-core (2.5.1)
20
+ rspec-expectations (2.5.0)
21
+ diff-lcs (~> 1.1.2)
22
+ rspec-mocks (2.5.0)
23
+ sinatra (1.1.3)
24
+ rack (~> 1.1)
25
+ tilt (>= 1.2.2, < 2.0)
26
+ tilt (1.2.2)
27
+
28
+ PLATFORMS
29
+ ruby
30
+
31
+ DEPENDENCIES
32
+ mocha
33
+ redis_ring!
34
+ rspec
data/MIT-LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Adam Pohorecki, http://adam.pohorecki.pl/
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.
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core'
5
+ require 'rspec/core/rake_task'
6
+
7
+ desc "Run all specs"
8
+ RSpec::Core::RakeTask.new(:spec) do |t|
9
+ t.pattern = "./spec/**/*_spec.rb"
10
+ t.rspec_opts = ["--profile --color"]
11
+ end
data/bin/redis-ring ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.push File.expand_path("../../lib", __FILE__)
4
+
5
+ require 'redis_ring'
6
+
7
+ RedisRing::CLI.new(ARGV).run
@@ -0,0 +1,32 @@
1
+ # By default RedisRing tries to guess the local IP address
2
+ # setting host_name should be necessary only if that is not possible
3
+ #host_name: localhost
4
+
5
+ # This is the port on which RedisRing publishes it's HTTP interface
6
+ # The Redis instances use ring_size next ports
7
+ base_port: 6400
8
+
9
+ # The number of Redis instances to start. Morte means more memory overhead (about 1MB per instance),
10
+ # but more means also easier moving around parts of the database
11
+ ring_size: 32
12
+
13
+ # By default which redis-server is used. Overwrite this setting if redis-server is not in PATH
14
+ #redis_path: /path/to/redis-server
15
+
16
+ # By default config/redis.conf.erb from the gem is used, but you can also supply your own.
17
+ # You can also change the redis server settings using the shared_config.conf file in base directory
18
+ #redis_config_template_path: /path/to/redis.conf.erb
19
+
20
+ # You can specify how much should Virtual Memory take in bytes (overall, not per Redis instance)
21
+ total_vm_size: 8589934592 #8GB
22
+ vm_page_size: 32
23
+
24
+ # This is the root directory under which all files will be stored
25
+ base_directory: /var/lib/redis
26
+
27
+ # Like with Virtual Memory, you can also specify how much memory all the Redis instances should take together
28
+ total_max_memory: 1073741824 # 1GB
29
+
30
+ # This is the password that will be used by all Redis instances. Remember that a huge number of passwords can be
31
+ # chacked in a second, so use a strong one. By default there is no password.
32
+ #password: letmein
@@ -0,0 +1,49 @@
1
+ daemonize no
2
+
3
+ port <%= port %>
4
+ logfile <%= log_file %>
5
+ dir <%= working_directory %>
6
+ vm-swap-file <%= vm_swap_file %>
7
+ vm-max-memory <%= vm_max_memory %>
8
+ vm-pages <%= vm_pages %>
9
+ vm-page-size <%= vm_page_size %>
10
+ dbfilename <%= db_file_name %>
11
+ appendfilename <%= aof_file_name %>
12
+ # slaveof <masterip> <masterport>
13
+ <% if password %>
14
+ requirepass <%= password %>
15
+ <% end %>
16
+
17
+ timeout 300
18
+
19
+ loglevel notice
20
+
21
+ databases 2048
22
+
23
+ save 900 1
24
+ save 300 10
25
+ save 60 10000
26
+
27
+ rdbcompression yes
28
+
29
+ # maxclients 128
30
+ # maxmemory <bytes>
31
+
32
+ appendonly no
33
+
34
+ # The name of the append only file (default: "appendonly.aof")
35
+
36
+ # appendfsync always
37
+ appendfsync everysec
38
+ # appendfsync no
39
+
40
+ vm-enabled yes
41
+ vm-max-threads 4
42
+
43
+ glueoutputbuf yes
44
+ hash-max-zipmap-entries 64
45
+ hash-max-zipmap-value 512
46
+
47
+ activerehashing yes
48
+
49
+ include <%= common_config_path %>
@@ -0,0 +1,47 @@
1
+ module RedisRing
2
+
3
+ class Application
4
+
5
+ attr_reader :shards, :configuration
6
+
7
+ def initialize(configuration)
8
+ @configuration = configuration
9
+ @shards = {}
10
+ end
11
+
12
+ def start
13
+ self.stop
14
+
15
+ @configuration.ring_size.times do |shard_number|
16
+ shard_conf = ShardConfig.new(shard_number, configuration)
17
+ @shards[shard_number] = Shard.new(shard_conf)
18
+ end
19
+
20
+ @shards.each do |shard_no, shard|
21
+ shard.start
22
+ end
23
+ end
24
+
25
+ def stop
26
+ @shards.each do |shard_no, shard|
27
+ shard.stop
28
+ end
29
+ @shards = {}
30
+ end
31
+
32
+ def shards_hash
33
+ shards_hash = {}
34
+ shards.each do |shard_no, shard|
35
+ shards_hash[shard_no] = { :host => shard.host, :port => shard.port, :status => shard.status }
36
+ end
37
+
38
+ return { :count => configuration.ring_size, :shards => shards_hash }
39
+ end
40
+
41
+ class << self
42
+ attr_accessor :instance
43
+ end
44
+
45
+ end
46
+
47
+ end
@@ -0,0 +1,53 @@
1
+ module RedisRing
2
+
3
+ class CLI
4
+
5
+ COMMANDS = [:help, :start]
6
+
7
+ attr_reader :argv
8
+
9
+ def initialize(argv)
10
+ @argv = argv
11
+ end
12
+
13
+ def run
14
+ command = argv[0]
15
+ if command.nil? || !COMMANDS.include?(command.to_sym)
16
+ usage
17
+ exit(1)
18
+ else
19
+ send(command, *argv[1..-1])
20
+ exit(0)
21
+ end
22
+ end
23
+
24
+ protected
25
+
26
+ def help
27
+ usage
28
+ end
29
+
30
+ def usage
31
+ puts <<USAGE
32
+ Usage:
33
+ #{$0} command [arguments]
34
+
35
+ Commands:
36
+ help - prints this message
37
+
38
+ start [config_file] - starts application
39
+ USAGE
40
+ end
41
+
42
+ def start(config_file = nil)
43
+ config = config_file ? Configuration.from_yml_file(config_file) : Configuration.new
44
+
45
+ Application.instance = Application.new(config)
46
+ Application.instance.start
47
+
48
+ WebInterface.run!(:port => config.base_port)
49
+ end
50
+
51
+ end
52
+
53
+ end
@@ -0,0 +1,79 @@
1
+ module RedisRing
2
+
3
+ class ConfigurationError < StandardError; end
4
+ class RedisNotFound < ConfigurationError; end
5
+ class UnknownConfigurationParameter < ConfigurationError; end
6
+
7
+ class Configuration
8
+
9
+ PARAMETERS = [:host_name, :base_port, :ring_size, :redis_path, :redis_config_template_path,
10
+ :total_vm_size, :base_directory, :password, :total_max_memory, :vm_page_size]
11
+
12
+ attr_reader *PARAMETERS
13
+
14
+ def initialize(params = {})
15
+ set_params(params)
16
+ set_defaults
17
+ validate!
18
+ end
19
+
20
+ def self.from_yml_file(file_name)
21
+ return from_yml(File.read(file_name))
22
+ end
23
+
24
+ def self.from_yml(string)
25
+ args = YAML::load(string)
26
+ return new(args)
27
+ end
28
+
29
+ protected
30
+
31
+ attr_writer *PARAMETERS
32
+
33
+ def set_params(params)
34
+ params.each do |param, value|
35
+ if PARAMETERS.include?(param.to_sym)
36
+ self.send("#{param}=", value)
37
+ else
38
+ raise UnknownConfigurationParameter.new("Unknown configuration parameter: #{param.inspect}")
39
+ end
40
+ end
41
+ end
42
+
43
+ def set_defaults
44
+ self.host_name ||= guess_host_name
45
+ self.base_port ||= 6400
46
+ self.ring_size ||= 32
47
+ self.redis_path ||= locate_redis
48
+ self.redis_config_template_path ||= default_redis_config_template_path
49
+ self.total_vm_size ||= 8 * 1024 * 1024 * 1024 # 8GB
50
+ self.base_directory ||= "/var/lib/redis"
51
+ self.total_max_memory ||= 1024 * 1024 * 1024 # 1GB
52
+ self.vm_page_size ||= 32
53
+ end
54
+
55
+ def validate!
56
+ raise RedisNotFound.new("redis_path is invalid (not found)") unless File.file?(redis_path)
57
+ end
58
+
59
+ def guess_host_name
60
+ orig, Socket.do_not_reverse_lookup = Socket.do_not_reverse_lookup, true # turn off reverse DNS resolution temporarily
61
+ UDPSocket.open do |s|
62
+ s.connect '64.233.187.99', 1
63
+ return s.addr.last
64
+ end
65
+ ensure
66
+ Socket.do_not_reverse_lookup = orig
67
+ end
68
+
69
+ def locate_redis
70
+ return %x[which redis-server].strip
71
+ end
72
+
73
+ def default_redis_config_template_path
74
+ File.expand_path('../../../config/redis.conf.erb', __FILE__)
75
+ end
76
+
77
+ end
78
+
79
+ end
@@ -0,0 +1,61 @@
1
+ module RedisRing
2
+
3
+ class Shard
4
+
5
+ attr_reader :shard_config, :pid
6
+
7
+ def initialize(shard_config)
8
+ @shard_config = shard_config
9
+ @status = :stopped
10
+ end
11
+
12
+ def shard_number
13
+ shard_config.shard_number
14
+ end
15
+
16
+ def host
17
+ shard_config.host
18
+ end
19
+
20
+ def port
21
+ shard_config.port
22
+ end
23
+
24
+ def status
25
+ if @status == :stopped
26
+ return alive? ? :stopping : :stopped
27
+ elsif @status == :started
28
+ return alive? ? :running : :dead
29
+ else
30
+ raise RuntimeException.new("Unknown status: #{@status.inspect}")
31
+ end
32
+ end
33
+
34
+ def start
35
+ shard_config.save
36
+ @pid = fork_redis_server
37
+ @status = :started
38
+ end
39
+
40
+ def stop
41
+ send_kill_signal
42
+ @status = :stopped
43
+ end
44
+
45
+ protected
46
+
47
+ def alive?
48
+ @pid && File.exist?("/proc/#{@pid}")
49
+ end
50
+
51
+ def fork_redis_server
52
+ spawn(shard_config.redis_path, shard_config.config_file_name)
53
+ end
54
+
55
+ def send_kill_signal
56
+ system("kill -QUIT #{pid}")
57
+ end
58
+
59
+ end
60
+
61
+ end
@@ -0,0 +1,93 @@
1
+ module RedisRing
2
+
3
+ class ShardConfig
4
+
5
+ attr_reader :shard_number, :configuration
6
+
7
+ def initialize(shard_number, configuration)
8
+ @shard_number = shard_number
9
+ @configuration = configuration
10
+ end
11
+
12
+ def render
13
+ template = ERB.new(File.read(configuration.redis_config_template_path))
14
+ return template.result(binding)
15
+ end
16
+
17
+ def save
18
+ FileUtils.mkdir_p(working_directory)
19
+
20
+ ['configs', 'logs', 'vm_files', 'db_files'].each do |dir_name|
21
+ FileUtils.mkdir_p(File.join(configuration.base_directory, dir_name))
22
+ end
23
+
24
+ FileUtils.touch(common_config_path) unless File.exist?(common_config_path)
25
+
26
+ File.open(config_file_name, 'w') { |f| f.write(render) }
27
+ end
28
+
29
+ def config_file_name
30
+ File.join(configuration.base_directory, 'configs', "shard-#{shard_number}.conf")
31
+ end
32
+
33
+ def host
34
+ configuration.host_name
35
+ end
36
+
37
+ def port
38
+ configuration.base_port + shard_number + 1
39
+ end
40
+
41
+ def redis_path
42
+ configuration.redis_path
43
+ end
44
+
45
+ def log_file
46
+ File.expand_path(file('logs', "shard-#{shard_number}.log"), working_directory)
47
+ end
48
+
49
+ def working_directory
50
+ "#{configuration.base_directory}/work/shard-#{shard_number}"
51
+ end
52
+
53
+ def vm_swap_file
54
+ file('vm_files', "shard-#{shard_number}.swap")
55
+ end
56
+
57
+ def vm_max_memory
58
+ configuration.total_max_memory / configuration.ring_size
59
+ end
60
+
61
+ def vm_pages
62
+ configuration.total_vm_size / configuration.vm_page_size / configuration.ring_size
63
+ end
64
+
65
+ def vm_page_size
66
+ configuration.vm_page_size
67
+ end
68
+
69
+ def db_file_name
70
+ file('db_files', "shard-#{shard_number}.rdb")
71
+ end
72
+
73
+ def aof_file_name
74
+ file('db_files', "shard-#{shard_number}.aof")
75
+ end
76
+
77
+ def password
78
+ configuration.password
79
+ end
80
+
81
+ def common_config_path
82
+ File.join(configuration.base_directory, "shared_config.conf")
83
+ end
84
+
85
+ protected
86
+
87
+ def file(*parts)
88
+ File.join('..', '..', *parts)
89
+ end
90
+
91
+ end
92
+
93
+ end
@@ -0,0 +1,3 @@
1
+ module RedisRing
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,16 @@
1
+ module RedisRing
2
+
3
+ class WebInterface < Sinatra::Base
4
+
5
+ get "/" do
6
+ "RedisRing is running"
7
+ end
8
+
9
+ get "/shards" do
10
+ content_type :json
11
+ Application.instance.shards_hash.to_json
12
+ end
13
+
14
+ end
15
+
16
+ end
data/lib/redis_ring.rb ADDED
@@ -0,0 +1,14 @@
1
+ require 'socket'
2
+ require 'yaml'
3
+ require 'erb'
4
+ require 'fileutils'
5
+
6
+ require 'sinatra'
7
+ require 'json'
8
+
9
+ require 'redis_ring/configuration'
10
+ require 'redis_ring/shard_config'
11
+ require 'redis_ring/shard'
12
+ require 'redis_ring/application'
13
+ require 'redis_ring/web_interface'
14
+ require 'redis_ring/cli'
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "redis_ring/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "redis_ring"
7
+ s.version = RedisRing::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Adam Pohorecki"]
10
+ s.email = ["adam@pohorecki.pl"]
11
+ s.homepage = "http://github.com/psyho/redis_ring"
12
+ s.summary = %q{A simplistic solution to redis sharding}
13
+ s.description = %q{RedisRing is a solution to run multiple small Redis instances intead of a single large one.}
14
+
15
+ s.rubyforge_project = "redis_ring"
16
+
17
+ s.add_dependency 'sinatra'
18
+ s.add_dependency 'json'
19
+
20
+ s.add_development_dependency 'rspec'
21
+ s.add_development_dependency 'mocha'
22
+
23
+ s.files = `git ls-files`.split("\n")
24
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
25
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
26
+ s.require_paths = ["lib"]
27
+ end
@@ -0,0 +1,23 @@
1
+ require File.expand_path("../../spec_helper", __FILE__)
2
+
3
+ describe RedisRing::Application do
4
+
5
+ describe "#shards_hash" do
6
+ before(:each) do
7
+ RedisRing::Shard.any_instance.stubs(:fork_redis_server => 123)
8
+ RedisRing::ShardConfig.any_instance.stubs(:save)
9
+ RedisRing::ShardConfig.any_instance.stubs(:alive? => true)
10
+
11
+ @application = RedisRing::Application.new(RedisRing::Configuration.new)
12
+ @application.start
13
+ end
14
+
15
+ it "should return all shards" do
16
+ shard_hash = @application.shards_hash
17
+
18
+ shard_hash[:count].should == @application.configuration.ring_size
19
+ shard_hash[:shards].size.should == @application.configuration.ring_size
20
+ end
21
+ end
22
+
23
+ end
@@ -0,0 +1,82 @@
1
+ require File.expand_path("../../spec_helper", __FILE__)
2
+
3
+ describe RedisRing::Configuration do
4
+ describe "defaults" do
5
+ before(:each) do
6
+ @config = RedisRing::Configuration.new
7
+ end
8
+
9
+ it "should have default port" do
10
+ @config.base_port.should_not be_nil
11
+ @config.base_port.should be_an_instance_of(Fixnum)
12
+ end
13
+
14
+ it "should have default host" do
15
+ @config.host_name.should_not be_nil
16
+ @config.host_name.should =~ /\d+\.\d+\.\d+.\d+/
17
+ end
18
+
19
+ it "should have default ring_size" do
20
+ @config.ring_size.should_not be_nil
21
+ @config.base_port.should be_an_instance_of(Fixnum)
22
+ @config.base_port.should > 0
23
+ end
24
+
25
+ it "should have default redis_path" do
26
+ @config.redis_path.should_not be_nil
27
+ File.exist?(@config.redis_path).should be_true
28
+ end
29
+
30
+ it "should have default redis_config_template_path" do
31
+ @config.redis_config_template_path.should_not be_nil
32
+ File.exist?(@config.redis_config_template_path).should be_true
33
+ end
34
+
35
+ it "should have default total_vm_size" do
36
+ @config.total_vm_size.should_not be_nil
37
+ @config.total_vm_size.should > 0
38
+ end
39
+
40
+ it "should have default base_directory" do
41
+ @config.base_directory.should_not be_nil
42
+ end
43
+
44
+ it "should have no password by default" do
45
+ @config.password.should be_nil
46
+ end
47
+
48
+ it "should have default total_memory" do
49
+ @config.total_max_memory.should_not be_nil
50
+ @config.total_max_memory.should > 0
51
+ end
52
+
53
+ it "should have default vm_page_size" do
54
+ @config.vm_page_size.should_not be_nil
55
+ @config.vm_page_size.should > 0
56
+ end
57
+ end
58
+
59
+ it "should rise RedisNotFound exception if redis-server not found" do
60
+ lambda {
61
+ RedisRing::Configuration.new(:redis_path => '/this/does/not/exist')
62
+ }.should raise_exception(RedisRing::RedisNotFound)
63
+ end
64
+
65
+ it "should rise UnknownConfigurationParameter exception if an unknown configuration parameter is given" do
66
+ lambda {
67
+ RedisRing::Configuration.new(:unknown_parameter => 'some value')
68
+ }.should raise_exception(RedisRing::UnknownConfigurationParameter)
69
+ end
70
+
71
+ it "should load yml config" do
72
+ yml_string = <<-YML
73
+ base_port: 666
74
+ base_directory: /home/psyho/redis
75
+ YML
76
+
77
+ config = RedisRing::Configuration.from_yml(yml_string)
78
+
79
+ config.base_port.should == 666
80
+ config.base_directory.should == '/home/psyho/redis'
81
+ end
82
+ end
@@ -0,0 +1,13 @@
1
+ require File.expand_path("../../spec_helper", __FILE__)
2
+
3
+ describe RedisRing::ShardConfig do
4
+ it "should render redis config with default config variables" do
5
+ config = RedisRing::Configuration.new
6
+ shard_config = RedisRing::ShardConfig.new(0, config)
7
+
8
+ redis_conf = shard_config.render
9
+
10
+ redis_conf.should include((config.base_port + 1).to_s)
11
+ redis_conf.should include(config.base_directory)
12
+ end
13
+ end
@@ -0,0 +1,49 @@
1
+ require File.expand_path("../../spec_helper", __FILE__)
2
+
3
+ describe RedisRing::Shard do
4
+
5
+ describe "possible statuses" do
6
+ before(:each) do
7
+ @shard = RedisRing::Shard.new(RedisRing::ShardConfig.new(0, RedisRing::Configuration.new))
8
+ @pid = 123
9
+ @shard.shard_config.stubs(:save)
10
+ @shard.stubs(:fork_redis_server => @pid)
11
+ @shard.stubs(:send_kill_signal)
12
+ end
13
+
14
+ it "should be stopped initially" do
15
+ @shard.status.should == :stopped
16
+ end
17
+
18
+ it "should be running if started and alive" do
19
+ @shard.stubs(:alive? => true)
20
+ @shard.start
21
+
22
+ @shard.status.should == :running
23
+ end
24
+
25
+ it "should be stopping if started then stopped but still alive" do
26
+ @shard.stubs(:alive? => true)
27
+ @shard.start
28
+ @shard.stop
29
+
30
+ @shard.status.should == :stopping
31
+ end
32
+
33
+ it "should be stopped if started then stopped and not alive" do
34
+ @shard.stubs(:alive? => false)
35
+ @shard.start
36
+ @shard.stop
37
+
38
+ @shard.status.should == :stopped
39
+ end
40
+
41
+ it "should be dead if started but not alive" do
42
+ @shard.stubs(:alive? => false)
43
+ @shard.start
44
+
45
+ @shard.status.should == :dead
46
+ end
47
+ end
48
+
49
+ end
@@ -0,0 +1,8 @@
1
+ $:.push File.expand_path("../lib", __FILE__)
2
+
3
+ require 'redis_ring'
4
+
5
+ RSpec.configure do |c|
6
+ c.color_enabled = true
7
+ c.mock_with :mocha
8
+ end
metadata ADDED
@@ -0,0 +1,137 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: redis_ring
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Adam Pohorecki
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-03-08 00:00:00 +01:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: sinatra
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 0
30
+ version: "0"
31
+ type: :runtime
32
+ version_requirements: *id001
33
+ - !ruby/object:Gem::Dependency
34
+ name: json
35
+ prerelease: false
36
+ requirement: &id002 !ruby/object:Gem::Requirement
37
+ none: false
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ segments:
42
+ - 0
43
+ version: "0"
44
+ type: :runtime
45
+ version_requirements: *id002
46
+ - !ruby/object:Gem::Dependency
47
+ name: rspec
48
+ prerelease: false
49
+ requirement: &id003 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ segments:
55
+ - 0
56
+ version: "0"
57
+ type: :development
58
+ version_requirements: *id003
59
+ - !ruby/object:Gem::Dependency
60
+ name: mocha
61
+ prerelease: false
62
+ requirement: &id004 !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ segments:
68
+ - 0
69
+ version: "0"
70
+ type: :development
71
+ version_requirements: *id004
72
+ description: RedisRing is a solution to run multiple small Redis instances intead of a single large one.
73
+ email:
74
+ - adam@pohorecki.pl
75
+ executables:
76
+ - redis-ring
77
+ extensions: []
78
+
79
+ extra_rdoc_files: []
80
+
81
+ files:
82
+ - .gitignore
83
+ - Gemfile
84
+ - Gemfile.lock
85
+ - MIT-LICENSE.txt
86
+ - Rakefile
87
+ - bin/redis-ring
88
+ - config/redis-ring.sample.yml
89
+ - config/redis.conf.erb
90
+ - lib/redis_ring.rb
91
+ - lib/redis_ring/application.rb
92
+ - lib/redis_ring/cli.rb
93
+ - lib/redis_ring/configuration.rb
94
+ - lib/redis_ring/shard.rb
95
+ - lib/redis_ring/shard_config.rb
96
+ - lib/redis_ring/version.rb
97
+ - lib/redis_ring/web_interface.rb
98
+ - redis_ring.gemspec
99
+ - spec/redis_ring/application_spec.rb
100
+ - spec/redis_ring/configuration_spec.rb
101
+ - spec/redis_ring/shard_config_spec.rb
102
+ - spec/redis_ring/shard_spec.rb
103
+ - spec/spec_helper.rb
104
+ has_rdoc: true
105
+ homepage: http://github.com/psyho/redis_ring
106
+ licenses: []
107
+
108
+ post_install_message:
109
+ rdoc_options: []
110
+
111
+ require_paths:
112
+ - lib
113
+ required_ruby_version: !ruby/object:Gem::Requirement
114
+ none: false
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ segments:
119
+ - 0
120
+ version: "0"
121
+ required_rubygems_version: !ruby/object:Gem::Requirement
122
+ none: false
123
+ requirements:
124
+ - - ">="
125
+ - !ruby/object:Gem::Version
126
+ segments:
127
+ - 0
128
+ version: "0"
129
+ requirements: []
130
+
131
+ rubyforge_project: redis_ring
132
+ rubygems_version: 1.3.7
133
+ signing_key:
134
+ specification_version: 3
135
+ summary: A simplistic solution to redis sharding
136
+ test_files: []
137
+