instructure-redis-store 1.0.0.1.instructure1

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.
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