instructure-redis-store 1.0.0.1.instructure1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/.travis.yml +7 -0
  2. data/CHANGELOG +311 -0
  3. data/Gemfile +34 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.md +239 -0
  6. data/Rakefile +60 -0
  7. data/VERSION +1 -0
  8. data/lib/action_controller/session/redis_session_store.rb +81 -0
  9. data/lib/active_support/cache/redis_store.rb +254 -0
  10. data/lib/cache/merb/redis_store.rb +79 -0
  11. data/lib/cache/sinatra/redis_store.rb +131 -0
  12. data/lib/i18n/backend/redis.rb +67 -0
  13. data/lib/rack/cache/redis_entitystore.rb +48 -0
  14. data/lib/rack/cache/redis_metastore.rb +40 -0
  15. data/lib/rack/session/merb.rb +32 -0
  16. data/lib/rack/session/redis.rb +88 -0
  17. data/lib/redis-store.rb +45 -0
  18. data/lib/redis/distributed_store.rb +39 -0
  19. data/lib/redis/factory.rb +46 -0
  20. data/lib/redis/store.rb +39 -0
  21. data/lib/redis/store/interface.rb +17 -0
  22. data/lib/redis/store/marshalling.rb +51 -0
  23. data/lib/redis/store/namespace.rb +62 -0
  24. data/lib/redis/store/ttl.rb +37 -0
  25. data/lib/redis/store/version.rb +12 -0
  26. data/spec/action_controller/session/redis_session_store_spec.rb +126 -0
  27. data/spec/active_support/cache/redis_store_spec.rb +426 -0
  28. data/spec/cache/merb/redis_store_spec.rb +143 -0
  29. data/spec/cache/sinatra/redis_store_spec.rb +192 -0
  30. data/spec/config/node-one.conf +417 -0
  31. data/spec/config/node-two.conf +417 -0
  32. data/spec/config/redis.conf +417 -0
  33. data/spec/i18n/backend/redis_spec.rb +72 -0
  34. data/spec/rack/cache/entitystore/pony.jpg +0 -0
  35. data/spec/rack/cache/entitystore/redis_spec.rb +124 -0
  36. data/spec/rack/cache/metastore/redis_spec.rb +259 -0
  37. data/spec/rack/session/redis_spec.rb +234 -0
  38. data/spec/redis/distributed_store_spec.rb +55 -0
  39. data/spec/redis/factory_spec.rb +110 -0
  40. data/spec/redis/store/interface_spec.rb +23 -0
  41. data/spec/redis/store/marshalling_spec.rb +119 -0
  42. data/spec/redis/store/namespace_spec.rb +76 -0
  43. data/spec/redis/store/version_spec.rb +7 -0
  44. data/spec/redis/store_spec.rb +13 -0
  45. data/spec/spec_helper.rb +43 -0
  46. data/tasks/redis.tasks.rb +235 -0
  47. metadata +249 -0
@@ -0,0 +1,131 @@
1
+ module Sinatra
2
+ module Cache
3
+ class << self
4
+ def register(app)
5
+ app.set :cache, RedisStore.new
6
+ end
7
+ alias_method :registered, :register
8
+ end
9
+
10
+ class RedisStore
11
+ # Instantiate the store.
12
+ #
13
+ # Example:
14
+ # RedisStore.new
15
+ # # => host: localhost, port: 6379, db: 0
16
+ #
17
+ # RedisStore.new "example.com"
18
+ # # => host: example.com, port: 6379, db: 0
19
+ #
20
+ # RedisStore.new "example.com:23682"
21
+ # # => host: example.com, port: 23682, db: 0
22
+ #
23
+ # RedisStore.new "example.com:23682/1"
24
+ # # => host: example.com, port: 23682, db: 1
25
+ #
26
+ # RedisStore.new "example.com:23682/1/theplaylist"
27
+ # # => host: example.com, port: 23682, db: 1, namespace: theplaylist
28
+ #
29
+ # RedisStore.new "localhost:6379/0", "localhost:6380/0"
30
+ # # => instantiate a cluster
31
+ def initialize(*addresses)
32
+ @data = Redis::Factory.create addresses
33
+ end
34
+
35
+ def write(key, value, options = nil)
36
+ if options && options[:unless_exist]
37
+ @data.setnx key, value, options
38
+ else
39
+ @data.set key, value, options
40
+ end
41
+ end
42
+
43
+ def read(key, options = nil)
44
+ @data.get(key, options)
45
+ end
46
+
47
+ def delete(key, options = nil)
48
+ @data.del key
49
+ end
50
+
51
+ def exist?(key, options = nil)
52
+ @data.exists key
53
+ end
54
+
55
+ # Increment a key in the store.
56
+ #
57
+ # If the key doesn't exist it will be initialized on 0.
58
+ # If the key exist but it isn't a Fixnum it will be initialized on 0.
59
+ #
60
+ # Example:
61
+ # We have two objects in cache:
62
+ # counter # => 23
63
+ # rabbit # => #<Rabbit:0x5eee6c>
64
+ #
65
+ # cache.increment "counter"
66
+ # cache.read "counter", :raw => true # => "24"
67
+ #
68
+ # cache.increment "counter", 6
69
+ # cache.read "counter", :raw => true # => "30"
70
+ #
71
+ # cache.increment "a counter"
72
+ # cache.read "a counter", :raw => true # => "1"
73
+ #
74
+ # cache.increment "rabbit"
75
+ # cache.read "rabbit", :raw => true # => "1"
76
+ def increment(key, amount = 1)
77
+ @data.incrby key, amount
78
+ end
79
+
80
+ # Decrement a key in the store
81
+ #
82
+ # If the key doesn't exist it will be initialized on 0.
83
+ # If the key exist but it isn't a Fixnum it will be initialized on 0.
84
+ #
85
+ # Example:
86
+ # We have two objects in cache:
87
+ # counter # => 23
88
+ # rabbit # => #<Rabbit:0x5eee6c>
89
+ #
90
+ # cache.decrement "counter"
91
+ # cache.read "counter", :raw => true # => "22"
92
+ #
93
+ # cache.decrement "counter", 2
94
+ # cache.read "counter", :raw => true # => "20"
95
+ #
96
+ # cache.decrement "a counter"
97
+ # cache.read "a counter", :raw => true # => "-1"
98
+ #
99
+ # cache.decrement "rabbit"
100
+ # cache.read "rabbit", :raw => true # => "-1"
101
+ def decrement(key, amount = 1)
102
+ @data.decrby key, amount
103
+ end
104
+
105
+ # Delete objects for matched keys.
106
+ #
107
+ # Example:
108
+ # cache.del_matched "rab*"
109
+ def delete_matched(matcher, options = nil)
110
+ @data.keys(matcher).each { |key| @data.del key }
111
+ end
112
+
113
+ def fetch(key, options = {})
114
+ (!options[:force] && data = read(key, options)) || block_given? && begin
115
+ data = yield
116
+ write(key, data, options)
117
+ end
118
+ data || nil
119
+ end
120
+
121
+ # Clear all the data from the store.
122
+ def clear
123
+ @data.flushdb
124
+ end
125
+
126
+ def stats
127
+ @data.info
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,67 @@
1
+ module I18n
2
+ module Backend
3
+ class Redis
4
+ include Base, Flatten
5
+ attr_accessor :store
6
+
7
+ # Instantiate the store.
8
+ #
9
+ # Example:
10
+ # RedisStore.new
11
+ # # => host: localhost, port: 6379, db: 0
12
+ #
13
+ # RedisStore.new "example.com"
14
+ # # => host: example.com, port: 6379, db: 0
15
+ #
16
+ # RedisStore.new "example.com:23682"
17
+ # # => host: example.com, port: 23682, db: 0
18
+ #
19
+ # RedisStore.new "example.com:23682/1"
20
+ # # => host: example.com, port: 23682, db: 1
21
+ #
22
+ # RedisStore.new "example.com:23682/1/theplaylist"
23
+ # # => host: example.com, port: 23682, db: 1, namespace: theplaylist
24
+ #
25
+ # RedisStore.new "localhost:6379/0", "localhost:6380/0"
26
+ # # => instantiate a cluster
27
+ def initialize(*addresses)
28
+ @store = ::Redis::Factory.create(addresses)
29
+ end
30
+
31
+ def translate(locale, key, options = {})
32
+ options[:resolve] ||= false
33
+ super locale, key, options
34
+ end
35
+
36
+ def store_translations(locale, data, options = {})
37
+ escape = options.fetch(:escape, true)
38
+ flatten_translations(locale, data, escape, false).each do |key, value|
39
+ case value
40
+ when Proc
41
+ raise "Key-value stores cannot handle procs"
42
+ else
43
+ @store.set "#{locale}.#{key}", value
44
+ end
45
+ end
46
+ end
47
+
48
+ def available_locales
49
+ locales = @store.keys.map { |k| k =~ /\./; $` }
50
+ locales.uniq!
51
+ locales.compact!
52
+ locales.map! { |k| k.to_sym }
53
+ locales
54
+ end
55
+
56
+ protected
57
+ def lookup(locale, key, scope = [], options = {})
58
+ key = normalize_flat_keys(locale, key, scope, options[:separator])
59
+ @store.get "#{locale}.#{key}"
60
+ end
61
+
62
+ def resolve_link(locale, key)
63
+ key
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,48 @@
1
+ module Rack
2
+ module Cache
3
+ class EntityStore
4
+ class RedisBase < EntityStore
5
+ # The underlying ::Redis instance used to communicate with the Redis daemon.
6
+ attr_reader :cache
7
+
8
+ extend Rack::Utils
9
+
10
+ def open(key)
11
+ data = read(key)
12
+ data && [data]
13
+ end
14
+
15
+ def self.resolve(uri)
16
+ new ::Redis::Factory.convert_to_redis_client_options(uri.to_s)
17
+ end
18
+ end
19
+
20
+ class Redis < RedisBase
21
+ def initialize(server, options = {})
22
+ @cache = ::Redis.new server
23
+ end
24
+
25
+ def exist?(key)
26
+ cache.exists key
27
+ end
28
+
29
+ def read(key)
30
+ cache.get key
31
+ end
32
+
33
+ def write(body)
34
+ buf = StringIO.new
35
+ key, size = slurp(body){|part| buf.write(part) }
36
+ [key, size] if cache.set(key, buf.string)
37
+ end
38
+
39
+ def purge(key)
40
+ cache.del key
41
+ nil
42
+ end
43
+ end
44
+
45
+ REDIS = Redis
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,40 @@
1
+ module Rack
2
+ module Cache
3
+ class MetaStore
4
+ class RedisBase < MetaStore
5
+ extend Rack::Utils
6
+
7
+ # The Redis::Store object used to communicate with the Redis daemon.
8
+ attr_reader :cache
9
+
10
+ def self.resolve(uri)
11
+ new ::Redis::Factory.convert_to_redis_client_options(uri.to_s)
12
+ end
13
+ end
14
+
15
+ class Redis < RedisBase
16
+ def initialize(server, options = {})
17
+ options[:redis_server] ||= server
18
+ @cache = ::Redis::Factory.create options
19
+ end
20
+
21
+ def read(key)
22
+ key = hexdigest(key)
23
+ cache.get(key) || []
24
+ end
25
+
26
+ def write(key, entries)
27
+ key = hexdigest(key)
28
+ cache.set(key, entries)
29
+ end
30
+
31
+ def purge(key)
32
+ cache.del(hexdigest(key))
33
+ nil
34
+ end
35
+ end
36
+
37
+ REDIS = Redis
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,32 @@
1
+ module Merb
2
+ # HACK for cyclic dependency: redis-store is required before Merb session stores
3
+ class Mash < Hash; end
4
+ class SessionContainer < Mash; class_inheritable_accessor :session_store_type end
5
+ class SessionStoreContainer < SessionContainer; end
6
+
7
+ class RedisSession < SessionStoreContainer
8
+ self.session_store_type = :redis
9
+ end
10
+
11
+ module RedisStore
12
+ def retrieve_session(session_id)
13
+ get("session:#{session_id}")
14
+ end
15
+
16
+ def store_session(session_id, data)
17
+ set("session:#{session_id}", data)
18
+ end
19
+
20
+ def delete_session(session_id)
21
+ delete("session:#{session_id}")
22
+ end
23
+ end
24
+ end
25
+
26
+ module Rack
27
+ module Session
28
+ class Redis
29
+ include Merb::RedisStore
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,88 @@
1
+ module Rack
2
+ module Session
3
+ class Redis < Abstract::ID
4
+ attr_reader :mutex, :pool
5
+ DEFAULT_OPTIONS = Abstract::ID::DEFAULT_OPTIONS.merge :redis_server => "redis://127.0.0.1:6379/0"
6
+
7
+ def initialize(app, options = {})
8
+ super
9
+ @mutex = Mutex.new
10
+ options[:redis_server] ||= @default_options[:redis_server]
11
+ @pool = ::Redis::Factory.create options
12
+ end
13
+
14
+ def generate_sid
15
+ loop do
16
+ sid = super
17
+ break sid unless @pool.get(sid)
18
+ end
19
+ end
20
+
21
+ def get_session(env, sid)
22
+ session = @pool.get(sid) if sid
23
+ @mutex.lock if env['rack.multithread']
24
+ unless sid and session
25
+ env['rack.errors'].puts("Session '#{sid.inspect}' not found, initializing...") if $VERBOSE and not sid.nil?
26
+ session = {}
27
+ sid = generate_sid
28
+ ret = @pool.set sid, session
29
+ raise "Session collision on '#{sid.inspect}'" unless ret
30
+ end
31
+ session.instance_variable_set('@old', {}.merge(session))
32
+ return [sid, session]
33
+ rescue Errno::ECONNREFUSED
34
+ warn "#{self} is unable to find server."
35
+ warn $!.inspect
36
+ return [ nil, {} ]
37
+ ensure
38
+ @mutex.unlock if env['rack.multithread']
39
+ end
40
+
41
+ def set_session(env, session_id, new_session, options)
42
+ @mutex.lock if env['rack.multithread']
43
+ session = @pool.get(session_id) rescue {}
44
+ if options[:renew] or options[:drop]
45
+ @pool.del session_id
46
+ return false if options[:drop]
47
+ session_id = generate_sid
48
+ @pool.set session_id, 0
49
+ end
50
+ old_session = new_session.instance_variable_get('@old') || {}
51
+ session = merge_sessions session_id, old_session, new_session, session
52
+ @pool.set session_id, session, options
53
+ return session_id
54
+ rescue Errno::ECONNREFUSED
55
+ warn "#{self} is unable to find server."
56
+ warn $!.inspect
57
+ return false
58
+ ensure
59
+ @mutex.unlock if env['rack.multithread']
60
+ end
61
+
62
+ def destroy_session(env, session_id, options)
63
+ options = { :renew => true }.update(options) unless options[:drop]
64
+ set_session(env, session_id, 0, options)
65
+ end
66
+
67
+ private
68
+ def merge_sessions(sid, old, new, cur=nil)
69
+ cur ||= {}
70
+ unless Hash === old and Hash === new
71
+ warn 'Bad old or new sessions provided.'
72
+ return cur
73
+ end
74
+
75
+ delete = old.keys - new.keys
76
+ warn "//@#{sid}: dropping #{delete*','}" if $DEBUG and not delete.empty?
77
+ delete.each{|k| cur.delete k }
78
+
79
+ update = new.keys.select{|k| new[k] != old[k] }
80
+ warn "//@#{sid}: updating #{update*','}" if $DEBUG and not update.empty?
81
+ update.each{|k| cur[k] = new[k] }
82
+
83
+ cur
84
+ end
85
+ end
86
+ end
87
+ end
88
+
@@ -0,0 +1,45 @@
1
+ require "redis"
2
+ require "redis/distributed"
3
+ require "redis/factory"
4
+ require "redis/store/interface"
5
+ require "redis/store/ttl"
6
+ require "redis/store/namespace"
7
+ require "redis/store/marshalling"
8
+ require "redis/store/version"
9
+ require "redis/store"
10
+ require "redis/distributed_store"
11
+
12
+ # Cache store
13
+ if defined?(Sinatra)
14
+ require "cache/sinatra/redis_store"
15
+ elsif defined?(Merb)
16
+ # HACK for cyclic dependency: redis-store is required before merb-cache
17
+ module Merb; module Cache; class AbstractStore; end end end
18
+ require "cache/merb/redis_store"
19
+ elsif defined?(ActiveSupport)
20
+ require "active_support/cache/redis_store"
21
+ end
22
+
23
+ # Rack::Session
24
+ if defined?(Rack::Session)
25
+ require "rack/session/abstract/id"
26
+ require "rack/session/redis"
27
+ if defined?(Merb)
28
+ require "rack/session/merb"
29
+ end
30
+ end
31
+
32
+ if defined?(Rails)
33
+ require "action_controller/session/redis_session_store"
34
+ end
35
+
36
+ # Rack::Cache
37
+ if defined?(Rack::Cache)
38
+ require "rack/cache/key"
39
+ require "rack/cache/redis_metastore"
40
+ require "rack/cache/redis_entitystore"
41
+ end
42
+
43
+ if defined?(I18n)
44
+ require "i18n/backend/redis"
45
+ end