caching_with_tags 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
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem 'rails', '>3.0.0'
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,21 @@
1
+ $:.push File.expand_path("../lib", __FILE__)
2
+ require "caching_with_tags/version"
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "caching_with_tags"
6
+ s.version = CachingWithTags::VERSION
7
+ s.authors = ["Vitaly Tsevan"]
8
+ s.email = ["vzevan@gmail.com"]
9
+ s.homepage = ""
10
+ s.summary = %q{Realisation of cache tagging for rails}
11
+ s.description = %q{Realisation of cache tagging for rails}
12
+
13
+ s.files = `git ls-files`.split("\n")
14
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
15
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
16
+ s.require_paths = ["lib"]
17
+
18
+ # specify any dependencies here; for example:
19
+ # s.add_development_dependency "rspec"
20
+ s.add_runtime_dependency "rails"
21
+ end
@@ -0,0 +1,6 @@
1
+ require 'rails'
2
+ require 'active_support'
3
+
4
+ require "caching_with_tags/version"
5
+ require "caching_with_tags/store"
6
+ require "caching_with_tags/railtie"
@@ -0,0 +1,8 @@
1
+ class Railtie < ::Rails::Railtie
2
+ initializer 'caching_with_tags.on_rails_init' do
3
+ ActiveSupport.on_load :before_configuration do
4
+ ActiveSupport.send :include, CachingWithTags::StoreMethods
5
+ ActiveSupport.send :include, CachingWithTags::EntryMethods
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,135 @@
1
+ module CachingWithTags
2
+ module StoreMethods
3
+ class ActiveSupport::Cache::Store
4
+ def read(name, options = nil)
5
+ options = merged_options(options)
6
+ key = namespaced_key(name, options)
7
+ instrument(:read, name, options) do |payload|
8
+ ########patched
9
+ entry = read_entry(key, options)
10
+ entry = nil if entry && entry.tags && !tags_actual?(entry.tags)
11
+ #######patch end
12
+
13
+ if entry
14
+ if entry.expired?
15
+ delete_entry(key, options)
16
+ payload[:hit] = false if payload
17
+ nil
18
+ else
19
+ payload[:hit] = true if payload
20
+ entry.value
21
+ end
22
+ else
23
+ payload[:hit] = false if payload
24
+ nil
25
+ end
26
+ end
27
+ end
28
+
29
+ def fetch(name, options = nil)
30
+ if block_given?
31
+ options = merged_options(options)
32
+ key = namespaced_key(name, options)
33
+ ########patched
34
+ unless options[:force]
35
+ entry = instrument(:read, name, options) do |payload|
36
+ payload[:super_operation] = :fetch if payload
37
+ ent = read_entry(key, options)
38
+ ent = nil if ent && ent.tags && !tags_actual?(ent.tags)
39
+ ent
40
+ end
41
+ end
42
+ ########end of patch
43
+ if entry && entry.expired?
44
+ race_ttl = options[:race_condition_ttl].to_f
45
+ if race_ttl and Time.now.to_f - entry.expires_at <= race_ttl
46
+ entry.expires_at = Time.now + race_ttl
47
+ write_entry(key, entry, :expires_in => race_ttl * 2)
48
+ else
49
+ delete_entry(key, options)
50
+ end
51
+ entry = nil
52
+ end
53
+
54
+ if entry
55
+ instrument(:fetch_hit, name, options) { |payload| }
56
+ entry.value
57
+ else
58
+ result = instrument(:generate, name, options) do |payload|
59
+ yield
60
+ end
61
+ write(name, result, options)
62
+ result
63
+ end
64
+ else
65
+ read(name, options)
66
+ end
67
+ end
68
+
69
+ def write(name, value, options = nil)
70
+ options = merged_options(options)
71
+ instrument(:write, name, options) do |payload|
72
+ ######patch
73
+ entry = ActiveSupport::Cache::Entry.new(value, options)
74
+ write_meta(entry, options[:tags]) if options[:tags]
75
+ write_entry(namespaced_key(name, options), entry, options)
76
+ ######end of patch
77
+ end
78
+ end
79
+
80
+ def exist?(name, options = nil)
81
+ options = merged_options(options)
82
+ instrument(:exist?, name) do |payload|
83
+ #####patched
84
+ entry = read_entry(namespaced_key(name, options), options)
85
+ entry = nil if entry && entry.tags && !tags_actual?(entry.tags)
86
+ #####end of patch
87
+ if entry && !entry.expired?
88
+ true
89
+ else
90
+ false
91
+ end
92
+ end
93
+ end
94
+
95
+ #####patch
96
+
97
+ def write_meta(entry, tags)
98
+ t = if tags.is_a?(Array)
99
+ tags.inject({}) do |res, el|
100
+ res[el] = fetch(el, {:namespace => nil}) { 1 }
101
+ res
102
+ end
103
+ end
104
+ entry.tags = t
105
+ end
106
+
107
+ def tags_actual?(tags)
108
+ if tags.is_a?(Hash)
109
+ # We're doing dup here because of Dalli makes force_encoding
110
+ # and ActiveSupport returns frozen values, so it raises an exception.
111
+ # Ruby uses copy-on-write technique so it's extremely cheap to make a dup
112
+ # of all tags.keys as far as we don't modify them
113
+ actual_versions = read_multi(*tags.keys.map { |k| k.dup } << {:namespace => nil})
114
+ actual_versions == tags
115
+ else
116
+ false
117
+ end
118
+ end
119
+
120
+ def increment_tag(name, options = nil)
121
+ options = merged_options(options)
122
+ entry = read_entry(namespaced_key(name, {:namespace => nil}), options)
123
+ value = entry ? entry.value + 1 : 1
124
+ write_entry(namespaced_key(name, {:namespace => nil}), ActiveSupport::Cache::Entry.new(value), options)
125
+ end
126
+ ######end of patch
127
+ end
128
+ end
129
+
130
+ module EntryMethods
131
+ class ActiveSupport::Cache::Entry
132
+ attr_accessor :tags
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,3 @@
1
+ module CachingWithTags
2
+ VERSION = "0.0.1"
3
+ end
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: caching_with_tags
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Vitaly Tsevan
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-04-08 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rails
16
+ requirement: &12632800 !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: *12632800
25
+ description: Realisation of cache tagging for rails
26
+ email:
27
+ - vzevan@gmail.com
28
+ executables: []
29
+ extensions: []
30
+ extra_rdoc_files: []
31
+ files:
32
+ - .gitignore
33
+ - Gemfile
34
+ - Rakefile
35
+ - caching_with_tags.gemspec
36
+ - lib/caching_with_tags.rb
37
+ - lib/caching_with_tags/railtie.rb
38
+ - lib/caching_with_tags/store.rb
39
+ - lib/caching_with_tags/version.rb
40
+ homepage: ''
41
+ licenses: []
42
+ post_install_message:
43
+ rdoc_options: []
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ none: false
48
+ requirements:
49
+ - - ! '>='
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ! '>='
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ requirements: []
59
+ rubyforge_project:
60
+ rubygems_version: 1.8.10
61
+ signing_key:
62
+ specification_version: 3
63
+ summary: Realisation of cache tagging for rails
64
+ test_files: []