csd 0.0.15 → 0.0.16
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 +1 -0
- data/COPYING +367 -0
- data/Rakefile +10 -10
- data/VERSION +1 -1
- data/bin/ai +19 -0
- data/csd.gemspec +257 -35
- data/lib/active_support.rb +75 -0
- data/lib/active_support/all.rb +3 -0
- data/lib/active_support/backtrace_cleaner.rb +94 -0
- data/lib/active_support/base64.rb +42 -0
- data/lib/active_support/basic_object.rb +21 -0
- data/lib/active_support/benchmarkable.rb +60 -0
- data/lib/active_support/buffered_logger.rb +132 -0
- data/lib/active_support/builder.rb +6 -0
- data/lib/active_support/cache.rb +626 -0
- data/lib/active_support/cache/compressed_mem_cache_store.rb +13 -0
- data/lib/active_support/cache/file_store.rb +188 -0
- data/lib/active_support/cache/mem_cache_store.rb +191 -0
- data/lib/active_support/cache/memory_store.rb +159 -0
- data/lib/active_support/cache/strategy/local_cache.rb +164 -0
- data/lib/active_support/cache/synchronized_memory_store.rb +11 -0
- data/lib/active_support/callbacks.rb +600 -0
- data/lib/active_support/concern.rb +29 -0
- data/lib/active_support/configurable.rb +36 -0
- data/lib/active_support/core_ext.rb +3 -0
- data/lib/active_support/core_ext/array.rb +7 -0
- data/lib/active_support/core_ext/array/access.rb +46 -0
- data/lib/active_support/core_ext/array/conversions.rb +164 -0
- data/lib/active_support/core_ext/array/extract_options.rb +29 -0
- data/lib/active_support/core_ext/array/grouping.rb +100 -0
- data/lib/active_support/core_ext/array/random_access.rb +20 -0
- data/lib/active_support/core_ext/array/uniq_by.rb +17 -0
- data/lib/active_support/core_ext/array/wrap.rb +22 -0
- data/lib/active_support/core_ext/benchmark.rb +7 -0
- data/lib/active_support/core_ext/big_decimal.rb +1 -0
- data/lib/active_support/core_ext/big_decimal/conversions.rb +27 -0
- data/lib/active_support/core_ext/cgi.rb +1 -0
- data/lib/active_support/core_ext/cgi/escape_skipping_slashes.rb +19 -0
- data/lib/active_support/core_ext/class.rb +4 -0
- data/lib/active_support/core_ext/class/attribute.rb +67 -0
- data/lib/active_support/core_ext/class/attribute_accessors.rb +63 -0
- data/lib/active_support/core_ext/class/delegating_attributes.rb +44 -0
- data/lib/active_support/core_ext/class/inheritable_attributes.rb +232 -0
- data/lib/active_support/core_ext/class/subclasses.rb +55 -0
- data/lib/active_support/core_ext/date/acts_like.rb +8 -0
- data/lib/active_support/core_ext/date/calculations.rb +240 -0
- data/lib/active_support/core_ext/date/conversions.rb +99 -0
- data/lib/active_support/core_ext/date/freeze.rb +31 -0
- data/lib/active_support/core_ext/date_time/acts_like.rb +13 -0
- data/lib/active_support/core_ext/date_time/calculations.rb +113 -0
- data/lib/active_support/core_ext/date_time/conversions.rb +102 -0
- data/lib/active_support/core_ext/date_time/zones.rb +17 -0
- data/lib/active_support/core_ext/enumerable.rb +119 -0
- data/lib/active_support/core_ext/exception.rb +3 -0
- data/lib/active_support/core_ext/file.rb +2 -0
- data/lib/active_support/core_ext/file/atomic.rb +41 -0
- data/lib/active_support/core_ext/file/path.rb +5 -0
- data/lib/active_support/core_ext/float.rb +1 -0
- data/lib/active_support/core_ext/float/rounding.rb +19 -0
- data/lib/active_support/core_ext/hash.rb +8 -0
- data/lib/active_support/core_ext/hash/conversions.rb +150 -0
- data/lib/active_support/core_ext/hash/deep_merge.rb +16 -0
- data/lib/active_support/core_ext/hash/diff.rb +13 -0
- data/lib/active_support/core_ext/hash/except.rb +24 -0
- data/lib/active_support/core_ext/hash/indifferent_access.rb +14 -0
- data/lib/active_support/core_ext/hash/keys.rb +45 -0
- data/lib/active_support/core_ext/hash/reverse_merge.rb +28 -0
- data/lib/active_support/core_ext/hash/slice.rb +38 -0
- data/lib/active_support/core_ext/integer.rb +3 -0
- data/lib/active_support/core_ext/integer/inflections.rb +14 -0
- data/lib/active_support/core_ext/integer/multiple.rb +6 -0
- data/lib/active_support/core_ext/integer/time.rb +39 -0
- data/lib/active_support/core_ext/kernel.rb +5 -0
- data/lib/active_support/core_ext/kernel/agnostics.rb +11 -0
- data/lib/active_support/core_ext/kernel/debugger.rb +16 -0
- data/lib/active_support/core_ext/kernel/reporting.rb +62 -0
- data/lib/active_support/core_ext/kernel/requires.rb +26 -0
- data/lib/active_support/core_ext/kernel/singleton_class.rb +13 -0
- data/lib/active_support/core_ext/load_error.rb +23 -0
- data/lib/active_support/core_ext/logger.rb +146 -0
- data/lib/active_support/core_ext/module.rb +12 -0
- data/lib/active_support/core_ext/module/aliasing.rb +70 -0
- data/lib/active_support/core_ext/module/anonymous.rb +24 -0
- data/lib/active_support/core_ext/module/attr_accessor_with_default.rb +31 -0
- data/lib/active_support/core_ext/module/attr_internal.rb +32 -0
- data/lib/active_support/core_ext/module/attribute_accessors.rb +66 -0
- data/lib/active_support/core_ext/module/delegation.rb +146 -0
- data/lib/active_support/core_ext/module/deprecation.rb +9 -0
- data/lib/active_support/core_ext/module/introspection.rb +88 -0
- data/lib/active_support/core_ext/module/method_names.rb +14 -0
- data/lib/active_support/core_ext/module/reachable.rb +10 -0
- data/lib/active_support/core_ext/module/remove_method.rb +6 -0
- data/lib/active_support/core_ext/module/synchronization.rb +42 -0
- data/lib/active_support/core_ext/name_error.rb +18 -0
- data/lib/active_support/core_ext/numeric.rb +2 -0
- data/lib/active_support/core_ext/numeric/bytes.rb +44 -0
- data/lib/active_support/core_ext/numeric/time.rb +77 -0
- data/lib/active_support/core_ext/object.rb +14 -0
- data/lib/active_support/core_ext/object/acts_like.rb +10 -0
- data/lib/active_support/core_ext/object/blank.rb +76 -0
- data/lib/active_support/core_ext/object/conversions.rb +4 -0
- data/lib/active_support/core_ext/object/duplicable.rb +65 -0
- data/lib/active_support/core_ext/object/extending.rb +11 -0
- data/lib/active_support/core_ext/object/instance_variables.rb +67 -0
- data/lib/active_support/core_ext/object/misc.rb +2 -0
- data/lib/active_support/core_ext/object/returning.rb +42 -0
- data/lib/active_support/core_ext/object/to_param.rb +49 -0
- data/lib/active_support/core_ext/object/to_query.rb +27 -0
- data/lib/active_support/core_ext/object/try.rb +36 -0
- data/lib/active_support/core_ext/object/with_options.rb +26 -0
- data/lib/active_support/core_ext/proc.rb +14 -0
- data/lib/active_support/core_ext/process.rb +1 -0
- data/lib/active_support/core_ext/process/daemon.rb +23 -0
- data/lib/active_support/core_ext/range.rb +4 -0
- data/lib/active_support/core_ext/range/blockless_step.rb +29 -0
- data/lib/active_support/core_ext/range/conversions.rb +21 -0
- data/lib/active_support/core_ext/range/include_range.rb +21 -0
- data/lib/active_support/core_ext/range/overlaps.rb +8 -0
- data/lib/active_support/core_ext/regexp.rb +5 -0
- data/lib/active_support/core_ext/rexml.rb +46 -0
- data/lib/active_support/core_ext/string.rb +12 -0
- data/lib/active_support/core_ext/string/access.rb +99 -0
- data/lib/active_support/core_ext/string/behavior.rb +7 -0
- data/lib/active_support/core_ext/string/conversions.rb +61 -0
- data/lib/active_support/core_ext/string/encoding.rb +11 -0
- data/lib/active_support/core_ext/string/exclude.rb +6 -0
- data/lib/active_support/core_ext/string/filters.rb +49 -0
- data/lib/active_support/core_ext/string/inflections.rb +149 -0
- data/lib/active_support/core_ext/string/interpolation.rb +2 -0
- data/lib/active_support/core_ext/string/multibyte.rb +72 -0
- data/lib/active_support/core_ext/string/output_safety.rb +109 -0
- data/lib/active_support/core_ext/string/starts_ends_with.rb +4 -0
- data/lib/active_support/core_ext/string/xchar.rb +18 -0
- data/lib/active_support/core_ext/time/acts_like.rb +8 -0
- data/lib/active_support/core_ext/time/calculations.rb +282 -0
- data/lib/active_support/core_ext/time/conversions.rb +85 -0
- data/lib/active_support/core_ext/time/marshal.rb +56 -0
- data/lib/active_support/core_ext/time/publicize_conversion_methods.rb +10 -0
- data/lib/active_support/core_ext/time/zones.rb +78 -0
- data/lib/active_support/core_ext/uri.rb +22 -0
- data/lib/active_support/dependencies.rb +628 -0
- data/lib/active_support/dependencies/autoload.rb +50 -0
- data/lib/active_support/deprecation.rb +18 -0
- data/lib/active_support/deprecation/behaviors.rb +38 -0
- data/lib/active_support/deprecation/method_wrappers.rb +29 -0
- data/lib/active_support/deprecation/proxy_wrappers.rb +74 -0
- data/lib/active_support/deprecation/reporting.rb +56 -0
- data/lib/active_support/duration.rb +105 -0
- data/lib/active_support/gzip.rb +25 -0
- data/lib/active_support/hash_with_indifferent_access.rb +145 -0
- data/lib/active_support/i18n.rb +8 -0
- data/lib/active_support/inflections.rb +56 -0
- data/lib/active_support/inflector.rb +7 -0
- data/lib/active_support/inflector/inflections.rb +211 -0
- data/lib/active_support/inflector/methods.rb +141 -0
- data/lib/active_support/inflector/transliterate.rb +97 -0
- data/lib/active_support/json.rb +2 -0
- data/lib/active_support/json/backends/jsongem.rb +43 -0
- data/lib/active_support/json/backends/yajl.rb +40 -0
- data/lib/active_support/json/backends/yaml.rb +90 -0
- data/lib/active_support/json/decoding.rb +51 -0
- data/lib/active_support/json/encoding.rb +254 -0
- data/lib/active_support/json/variable.rb +11 -0
- data/lib/active_support/lazy_load_hooks.rb +27 -0
- data/lib/active_support/locale/en.yml +36 -0
- data/lib/active_support/memoizable.rb +103 -0
- data/lib/active_support/message_encryptor.rb +71 -0
- data/lib/active_support/message_verifier.rb +62 -0
- data/lib/active_support/multibyte.rb +44 -0
- data/lib/active_support/multibyte/chars.rb +480 -0
- data/lib/active_support/multibyte/exceptions.rb +8 -0
- data/lib/active_support/multibyte/unicode.rb +393 -0
- data/lib/active_support/multibyte/utils.rb +60 -0
- data/lib/active_support/notifications.rb +81 -0
- data/lib/active_support/notifications/fanout.rb +93 -0
- data/lib/active_support/notifications/instrumenter.rb +56 -0
- data/lib/active_support/option_merger.rb +25 -0
- data/lib/active_support/ordered_hash.rb +158 -0
- data/lib/active_support/ordered_options.rb +27 -0
- data/lib/active_support/railtie.rb +100 -0
- data/lib/active_support/rescuable.rb +114 -0
- data/lib/active_support/ruby/shim.rb +22 -0
- data/lib/active_support/secure_random.rb +199 -0
- data/lib/active_support/string_inquirer.rb +21 -0
- data/lib/active_support/test_case.rb +42 -0
- data/lib/active_support/testing/assertions.rb +82 -0
- data/lib/active_support/testing/declarative.rb +40 -0
- data/lib/active_support/testing/default.rb +9 -0
- data/lib/active_support/testing/deprecation.rb +55 -0
- data/lib/active_support/testing/isolation.rb +154 -0
- data/lib/active_support/testing/pending.rb +48 -0
- data/lib/active_support/testing/performance.rb +455 -0
- data/lib/active_support/testing/setup_and_teardown.rb +111 -0
- data/lib/active_support/time.rb +34 -0
- data/lib/active_support/time/autoload.rb +5 -0
- data/lib/active_support/time_with_zone.rb +341 -0
- data/lib/active_support/values/time_zone.rb +377 -0
- data/lib/active_support/values/unicode_tables.dat +0 -0
- data/lib/active_support/version.rb +10 -0
- data/lib/active_support/whiny_nil.rb +60 -0
- data/lib/active_support/xml_mini.rb +158 -0
- data/lib/active_support/xml_mini/jdom.rb +168 -0
- data/lib/active_support/xml_mini/libxml.rb +80 -0
- data/lib/active_support/xml_mini/libxmlsax.rb +85 -0
- data/lib/active_support/xml_mini/nokogiri.rb +78 -0
- data/lib/active_support/xml_mini/nokogirisax.rb +83 -0
- data/lib/active_support/xml_mini/rexml.rb +129 -0
- data/lib/csd.rb +82 -2
- data/lib/csd/application.rb +2 -0
- data/lib/csd/application/default.rb +51 -0
- data/lib/csd/application/default/base.rb +15 -0
- data/lib/csd/application/minisip.rb +25 -0
- data/lib/csd/application/minisip/about.yml +14 -0
- data/lib/csd/application/minisip/base.rb +161 -0
- data/lib/csd/application/minisip/error.rb +11 -0
- data/lib/csd/application/minisip/options/common.rb +0 -0
- data/lib/csd/application/minisip/options/compile.rb +59 -0
- data/lib/csd/{applications → application}/minisip/unix/base.rb +10 -11
- data/lib/csd/application/opensips/about.yml +2 -0
- data/lib/csd/applications.rb +55 -0
- data/lib/csd/commands.rb +88 -65
- data/lib/csd/error.rb +31 -0
- data/lib/csd/extensions.rb +1 -0
- data/lib/{extensions → csd/extensions}/core/array.rb +2 -2
- data/lib/csd/extensions/core/dir.rb +46 -0
- data/lib/{extensions → csd/extensions}/core/file.rb +2 -2
- data/lib/{extensions → csd/extensions}/core/object.rb +2 -2
- data/lib/csd/extensions/core/option_parser.rb +33 -0
- data/lib/{extensions → csd/extensions}/core/pathname.rb +12 -3
- data/lib/{extensions → csd/extensions}/core/string.rb +2 -2
- data/lib/{extensions → csd/extensions}/gem/platform.rb +6 -2
- data/lib/csd/global_open_struct.rb +18 -0
- data/lib/csd/options.rb +124 -95
- data/lib/csd/path.rb +31 -0
- data/lib/csd/ui.rb +1 -0
- data/lib/csd/ui/cli.rb +7 -0
- data/lib/csd/ui/ui.rb +46 -0
- data/lib/csd/version.rb +9 -0
- data/lib/term/ansicolor.rb +102 -0
- data/lib/term/ansicolor/.keep +0 -0
- data/lib/term/ansicolor/version.rb +10 -0
- data/test/functional/test_applications.rb +86 -0
- data/test/functional/test_commands.rb +42 -29
- data/test/functional/test_options.rb +98 -0
- data/test/helper.rb +14 -0
- data/test/unit/test_dir.rb +38 -0
- data/test/unit/test_pathname.rb +32 -0
- metadata +253 -40
- data/LICENSE +0 -20
- data/bin/csd +0 -8
- data/lib/csd/applications/base.rb +0 -33
- data/lib/csd/applications/minisip/base.rb +0 -125
- data/lib/csd/applications/minisip/init.rb +0 -20
- data/lib/csd/init.rb +0 -69
- data/lib/csd/path_container.rb +0 -15
- data/publish +0 -29
@@ -0,0 +1,13 @@
|
|
1
|
+
module ActiveSupport
|
2
|
+
module Cache
|
3
|
+
class CompressedMemCacheStore < MemCacheStore
|
4
|
+
def initialize(*args)
|
5
|
+
ActiveSupport::Deprecation.warn('ActiveSupport::Cache::CompressedMemCacheStore has been deprecated in favor of ActiveSupport::Cache::MemCacheStore(:compress => true).', caller)
|
6
|
+
addresses = args.dup
|
7
|
+
options = addresses.extract_options!
|
8
|
+
args = addresses + [options.merge(:compress => true)]
|
9
|
+
super(*args)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,188 @@
|
|
1
|
+
require 'active_support/core_ext/file/atomic'
|
2
|
+
|
3
|
+
module ActiveSupport
|
4
|
+
module Cache
|
5
|
+
# A cache store implementation which stores everything on the filesystem.
|
6
|
+
#
|
7
|
+
# FileStore implements the Strategy::LocalCache strategy which implements
|
8
|
+
# an in memory cache inside of a block.
|
9
|
+
class FileStore < Store
|
10
|
+
attr_reader :cache_path
|
11
|
+
|
12
|
+
DIR_FORMATTER = "%03X"
|
13
|
+
ESCAPE_FILENAME_CHARS = /[^a-z0-9_.-]/i
|
14
|
+
UNESCAPE_FILENAME_CHARS = /%[0-9A-F]{2}/
|
15
|
+
|
16
|
+
def initialize(cache_path, options = nil)
|
17
|
+
super(options)
|
18
|
+
@cache_path = cache_path
|
19
|
+
extend Strategy::LocalCache
|
20
|
+
end
|
21
|
+
|
22
|
+
def clear(options = nil)
|
23
|
+
root_dirs = Dir.entries(cache_path).reject{|f| ['.', '..'].include?(f)}
|
24
|
+
FileUtils.rm_r(root_dirs.collect{|f| File.join(cache_path, f)})
|
25
|
+
end
|
26
|
+
|
27
|
+
def cleanup(options = nil)
|
28
|
+
options = merged_options(options)
|
29
|
+
each_key(options) do |key|
|
30
|
+
entry = read_entry(key, options)
|
31
|
+
delete_entry(key, options) if entry && entry.expired?
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def increment(name, amount = 1, options = nil)
|
36
|
+
file_name = key_file_path(namespaced_key(name, options))
|
37
|
+
lock_file(file_name) do
|
38
|
+
options = merged_options(options)
|
39
|
+
if num = read(name, options)
|
40
|
+
num = num.to_i + amount
|
41
|
+
write(name, num, options)
|
42
|
+
num
|
43
|
+
else
|
44
|
+
nil
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def decrement(name, amount = 1, options = nil)
|
50
|
+
file_name = key_file_path(namespaced_key(name, options))
|
51
|
+
lock_file(file_name) do
|
52
|
+
options = merged_options(options)
|
53
|
+
if num = read(name, options)
|
54
|
+
num = num.to_i - amount
|
55
|
+
write(name, num, options)
|
56
|
+
num
|
57
|
+
else
|
58
|
+
nil
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def delete_matched(matcher, options = nil)
|
64
|
+
options = merged_options(options)
|
65
|
+
instrument(:delete_matched, matcher.inspect) do
|
66
|
+
matcher = key_matcher(matcher, options)
|
67
|
+
search_dir(cache_path) do |path|
|
68
|
+
key = file_path_key(path)
|
69
|
+
delete_entry(key, options) if key.match(matcher)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
protected
|
75
|
+
|
76
|
+
def read_entry(key, options)
|
77
|
+
file_name = key_file_path(key)
|
78
|
+
if File.exist?(file_name)
|
79
|
+
entry = File.open(file_name) { |f| Marshal.load(f) }
|
80
|
+
if entry && !entry.expired? && !entry.expires_in && !self.options[:expires_in]
|
81
|
+
# Check for deprecated use of +:expires_in+ option from versions < 3.0
|
82
|
+
deprecated_expires_in = options[:expires_in]
|
83
|
+
if deprecated_expires_in
|
84
|
+
ActiveSupport::Deprecation.warn('Setting :expires_in on read has been deprecated in favor of setting it on write.', caller)
|
85
|
+
if entry.created_at + deprecated_expires_in.to_f <= Time.now.to_f
|
86
|
+
delete_entry(key, options)
|
87
|
+
entry = nil
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
entry
|
92
|
+
end
|
93
|
+
rescue
|
94
|
+
nil
|
95
|
+
end
|
96
|
+
|
97
|
+
def write_entry(key, entry, options)
|
98
|
+
file_name = key_file_path(key)
|
99
|
+
ensure_cache_path(File.dirname(file_name))
|
100
|
+
File.atomic_write(file_name, cache_path) {|f| Marshal.dump(entry, f)}
|
101
|
+
true
|
102
|
+
end
|
103
|
+
|
104
|
+
def delete_entry(key, options)
|
105
|
+
file_name = key_file_path(key)
|
106
|
+
if File.exist?(file_name)
|
107
|
+
begin
|
108
|
+
File.delete(file_name)
|
109
|
+
delete_empty_directories(File.dirname(file_name))
|
110
|
+
true
|
111
|
+
rescue => e
|
112
|
+
# Just in case the error was caused by another process deleting the file first.
|
113
|
+
raise e if File.exist?(file_name)
|
114
|
+
false
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
private
|
120
|
+
# Lock a file for a block so only one process can modify it at a time.
|
121
|
+
def lock_file(file_name, &block) # :nodoc:
|
122
|
+
if File.exist?(file_name)
|
123
|
+
File.open(file_name, 'r') do |f|
|
124
|
+
begin
|
125
|
+
f.flock File::LOCK_EX
|
126
|
+
yield
|
127
|
+
ensure
|
128
|
+
f.flock File::LOCK_UN
|
129
|
+
end
|
130
|
+
end
|
131
|
+
else
|
132
|
+
yield
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# Translate a key into a file path.
|
137
|
+
def key_file_path(key)
|
138
|
+
fname = key.to_s.gsub(ESCAPE_FILENAME_CHARS){|match| "%#{match.ord.to_s(16).upcase}"}
|
139
|
+
hash = Zlib.adler32(fname)
|
140
|
+
hash, dir_1 = hash.divmod(0x1000)
|
141
|
+
dir_2 = hash.modulo(0x1000)
|
142
|
+
fname_paths = []
|
143
|
+
# Make sure file name is < 255 characters so it doesn't exceed file system limits.
|
144
|
+
if fname.size <= 255
|
145
|
+
fname_paths << fname
|
146
|
+
else
|
147
|
+
while fname.size <= 255
|
148
|
+
fname_path << fname[0, 255]
|
149
|
+
fname = fname[255, -1]
|
150
|
+
end
|
151
|
+
end
|
152
|
+
File.join(cache_path, DIR_FORMATTER % dir_1, DIR_FORMATTER % dir_2, *fname_paths)
|
153
|
+
end
|
154
|
+
|
155
|
+
# Translate a file path into a key.
|
156
|
+
def file_path_key(path)
|
157
|
+
fname = path[cache_path.size, path.size].split(File::SEPARATOR, 4).last
|
158
|
+
fname.gsub(UNESCAPE_FILENAME_CHARS){|match| $1.ord.to_s(16)}
|
159
|
+
end
|
160
|
+
|
161
|
+
# Delete empty directories in the cache.
|
162
|
+
def delete_empty_directories(dir)
|
163
|
+
return if dir == cache_path
|
164
|
+
if Dir.entries(dir).reject{|f| ['.', '..'].include?(f)}.empty?
|
165
|
+
File.delete(dir) rescue nil
|
166
|
+
delete_empty_directories(File.dirname(dir))
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
# Make sure a file path's directories exist.
|
171
|
+
def ensure_cache_path(path)
|
172
|
+
FileUtils.makedirs(path) unless File.exist?(path)
|
173
|
+
end
|
174
|
+
|
175
|
+
def search_dir(dir, &callback)
|
176
|
+
Dir.foreach(dir) do |d|
|
177
|
+
next if d == "." || d == ".."
|
178
|
+
name = File.join(dir, d)
|
179
|
+
if File.directory?(name)
|
180
|
+
search_dir(name, &callback)
|
181
|
+
else
|
182
|
+
callback.call name
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
@@ -0,0 +1,191 @@
|
|
1
|
+
begin
|
2
|
+
require 'memcache'
|
3
|
+
rescue LoadError => e
|
4
|
+
$stderr.puts "You don't have memcache installed in your application. Please add it to your Gemfile and run bundle install"
|
5
|
+
raise e
|
6
|
+
end
|
7
|
+
require 'digest/md5'
|
8
|
+
|
9
|
+
module ActiveSupport
|
10
|
+
module Cache
|
11
|
+
# A cache store implementation which stores data in Memcached:
|
12
|
+
# http://www.danga.com/memcached/
|
13
|
+
#
|
14
|
+
# This is currently the most popular cache store for production websites.
|
15
|
+
#
|
16
|
+
# Special features:
|
17
|
+
# - Clustering and load balancing. One can specify multiple memcached servers,
|
18
|
+
# and MemCacheStore will load balance between all available servers. If a
|
19
|
+
# server goes down, then MemCacheStore will ignore it until it goes back
|
20
|
+
# online.
|
21
|
+
#
|
22
|
+
# MemCacheStore implements the Strategy::LocalCache strategy which implements
|
23
|
+
# an in memory cache inside of a block.
|
24
|
+
class MemCacheStore < Store
|
25
|
+
module Response # :nodoc:
|
26
|
+
STORED = "STORED\r\n"
|
27
|
+
NOT_STORED = "NOT_STORED\r\n"
|
28
|
+
EXISTS = "EXISTS\r\n"
|
29
|
+
NOT_FOUND = "NOT_FOUND\r\n"
|
30
|
+
DELETED = "DELETED\r\n"
|
31
|
+
end
|
32
|
+
|
33
|
+
ESCAPE_KEY_CHARS = /[\x00-\x20%\x7F-\xFF]/
|
34
|
+
|
35
|
+
def self.build_mem_cache(*addresses)
|
36
|
+
addresses = addresses.flatten
|
37
|
+
options = addresses.extract_options!
|
38
|
+
addresses = ["localhost"] if addresses.empty?
|
39
|
+
MemCache.new(addresses, options)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Creates a new MemCacheStore object, with the given memcached server
|
43
|
+
# addresses. Each address is either a host name, or a host-with-port string
|
44
|
+
# in the form of "host_name:port". For example:
|
45
|
+
#
|
46
|
+
# ActiveSupport::Cache::MemCacheStore.new("localhost", "server-downstairs.localnetwork:8229")
|
47
|
+
#
|
48
|
+
# If no addresses are specified, then MemCacheStore will connect to
|
49
|
+
# localhost port 11211 (the default memcached port).
|
50
|
+
#
|
51
|
+
# Instead of addresses one can pass in a MemCache-like object. For example:
|
52
|
+
#
|
53
|
+
# require 'memcached' # gem install memcached; uses C bindings to libmemcached
|
54
|
+
# ActiveSupport::Cache::MemCacheStore.new(Memcached::Rails.new("localhost:11211"))
|
55
|
+
def initialize(*addresses)
|
56
|
+
addresses = addresses.flatten
|
57
|
+
options = addresses.extract_options!
|
58
|
+
super(options)
|
59
|
+
|
60
|
+
if addresses.first.respond_to?(:get)
|
61
|
+
@data = addresses.first
|
62
|
+
else
|
63
|
+
mem_cache_options = options.dup
|
64
|
+
UNIVERSAL_OPTIONS.each{|name| mem_cache_options.delete(name)}
|
65
|
+
@data = self.class.build_mem_cache(*(addresses + [mem_cache_options]))
|
66
|
+
end
|
67
|
+
|
68
|
+
extend Strategy::LocalCache
|
69
|
+
extend LocalCacheWithRaw
|
70
|
+
end
|
71
|
+
|
72
|
+
# Reads multiple keys from the cache using a single call to the
|
73
|
+
# servers for all keys. Options can be passed in the last argument.
|
74
|
+
def read_multi(*names)
|
75
|
+
options = names.extract_options!
|
76
|
+
options = merged_options(options)
|
77
|
+
keys_to_names = names.inject({}){|map, name| map[escape_key(namespaced_key(name, options))] = name; map}
|
78
|
+
raw_values = @data.get_multi(keys_to_names.keys, :raw => true)
|
79
|
+
values = {}
|
80
|
+
raw_values.each do |key, value|
|
81
|
+
entry = deserialize_entry(value)
|
82
|
+
values[keys_to_names[key]] = entry.value unless entry.expired?
|
83
|
+
end
|
84
|
+
values
|
85
|
+
end
|
86
|
+
|
87
|
+
# Increment a cached value. This method uses the memcached incr atomic
|
88
|
+
# operator and can only be used on values written with the :raw option.
|
89
|
+
# Calling it on a value not stored with :raw will initialize that value
|
90
|
+
# to zero.
|
91
|
+
def increment(name, amount = 1, options = nil) # :nodoc:
|
92
|
+
options = merged_options(options)
|
93
|
+
response = instrument(:increment, name, :amount => amount) do
|
94
|
+
@data.incr(escape_key(namespaced_key(name, options)), amount)
|
95
|
+
end
|
96
|
+
response == Response::NOT_FOUND ? nil : response.to_i
|
97
|
+
rescue MemCache::MemCacheError
|
98
|
+
nil
|
99
|
+
end
|
100
|
+
|
101
|
+
# Decrement a cached value. This method uses the memcached decr atomic
|
102
|
+
# operator and can only be used on values written with the :raw option.
|
103
|
+
# Calling it on a value not stored with :raw will initialize that value
|
104
|
+
# to zero.
|
105
|
+
def decrement(name, amount = 1, options = nil) # :nodoc:
|
106
|
+
options = merged_options(options)
|
107
|
+
response = instrument(:decrement, name, :amount => amount) do
|
108
|
+
@data.decr(escape_key(namespaced_key(name, options)), amount)
|
109
|
+
end
|
110
|
+
response == Response::NOT_FOUND ? nil : response.to_i
|
111
|
+
rescue MemCache::MemCacheError
|
112
|
+
nil
|
113
|
+
end
|
114
|
+
|
115
|
+
# Clear the entire cache on all memcached servers. This method should
|
116
|
+
# be used with care when using a shared cache.
|
117
|
+
def clear(options = nil)
|
118
|
+
@data.flush_all
|
119
|
+
end
|
120
|
+
|
121
|
+
# Get the statistics from the memcached servers.
|
122
|
+
def stats
|
123
|
+
@data.stats
|
124
|
+
end
|
125
|
+
|
126
|
+
protected
|
127
|
+
# Read an entry from the cache.
|
128
|
+
def read_entry(key, options) # :nodoc:
|
129
|
+
deserialize_entry(@data.get(escape_key(key), true))
|
130
|
+
rescue MemCache::MemCacheError => e
|
131
|
+
logger.error("MemCacheError (#{e}): #{e.message}") if logger
|
132
|
+
nil
|
133
|
+
end
|
134
|
+
|
135
|
+
# Write an entry to the cache.
|
136
|
+
def write_entry(key, entry, options) # :nodoc:
|
137
|
+
method = options && options[:unless_exist] ? :add : :set
|
138
|
+
value = options[:raw] ? entry.value.to_s : entry
|
139
|
+
expires_in = options[:expires_in].to_i
|
140
|
+
if expires_in > 0 && !options[:raw]
|
141
|
+
# Set the memcache expire a few minutes in the future to support race condition ttls on read
|
142
|
+
expires_in += 5.minutes
|
143
|
+
end
|
144
|
+
response = @data.send(method, escape_key(key), value, expires_in, options[:raw])
|
145
|
+
response == Response::STORED
|
146
|
+
rescue MemCache::MemCacheError => e
|
147
|
+
logger.error("MemCacheError (#{e}): #{e.message}") if logger
|
148
|
+
false
|
149
|
+
end
|
150
|
+
|
151
|
+
# Delete an entry from the cache.
|
152
|
+
def delete_entry(key, options) # :nodoc:
|
153
|
+
response = @data.delete(escape_key(key))
|
154
|
+
response == Response::DELETED
|
155
|
+
rescue MemCache::MemCacheError => e
|
156
|
+
logger.error("MemCacheError (#{e}): #{e.message}") if logger
|
157
|
+
false
|
158
|
+
end
|
159
|
+
|
160
|
+
private
|
161
|
+
def escape_key(key)
|
162
|
+
key = key.to_s.gsub(ESCAPE_KEY_CHARS){|match| "%#{match[0].to_s(16).upcase}"}
|
163
|
+
key = "#{key[0, 213]}:md5:#{Digest::MD5.hexdigest(key)}" if key.size > 250
|
164
|
+
key
|
165
|
+
end
|
166
|
+
|
167
|
+
def deserialize_entry(raw_value)
|
168
|
+
if raw_value
|
169
|
+
entry = Marshal.load(raw_value) rescue raw_value
|
170
|
+
entry.is_a?(Entry) ? entry : Entry.new(entry)
|
171
|
+
else
|
172
|
+
nil
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
# Provide support for raw values in the local cache strategy.
|
177
|
+
module LocalCacheWithRaw # :nodoc:
|
178
|
+
protected
|
179
|
+
def write_entry(key, entry, options) # :nodoc:
|
180
|
+
retval = super
|
181
|
+
if options[:raw] && local_cache && retval
|
182
|
+
raw_entry = Entry.new(entry.value.to_s)
|
183
|
+
raw_entry.expires_at = entry.expires_at
|
184
|
+
local_cache.write_entry(key, raw_entry, options)
|
185
|
+
end
|
186
|
+
retval
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
@@ -0,0 +1,159 @@
|
|
1
|
+
require 'monitor'
|
2
|
+
|
3
|
+
module ActiveSupport
|
4
|
+
module Cache
|
5
|
+
# A cache store implementation which stores everything into memory in the
|
6
|
+
# same process. If you're running multiple Ruby on Rails server processes
|
7
|
+
# (which is the case if you're using mongrel_cluster or Phusion Passenger),
|
8
|
+
# then this means that your Rails server process instances won't be able
|
9
|
+
# to share cache data with each other and this may not be the most
|
10
|
+
# appropriate cache for you.
|
11
|
+
#
|
12
|
+
# This cache has a bounded size specified by the :size options to the
|
13
|
+
# initializer (default is 32Mb). When the cache exceeds the alotted size,
|
14
|
+
# a cleanup will occur which tries to prune the cache down to three quarters
|
15
|
+
# of the maximum size by removing the least recently used entries.
|
16
|
+
#
|
17
|
+
# MemoryStore is thread-safe.
|
18
|
+
class MemoryStore < Store
|
19
|
+
def initialize(options = nil)
|
20
|
+
options ||= {}
|
21
|
+
super(options)
|
22
|
+
@data = {}
|
23
|
+
@key_access = {}
|
24
|
+
@max_size = options[:size] || 32.megabytes
|
25
|
+
@max_prune_time = options[:max_prune_time] || 2
|
26
|
+
@cache_size = 0
|
27
|
+
@monitor = Monitor.new
|
28
|
+
@pruning = false
|
29
|
+
end
|
30
|
+
|
31
|
+
def clear(options = nil)
|
32
|
+
synchronize do
|
33
|
+
@data.clear
|
34
|
+
@key_access.clear
|
35
|
+
@cache_size = 0
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def cleanup(options = nil)
|
40
|
+
options = merged_options(options)
|
41
|
+
instrument(:cleanup, :size => @data.size) do
|
42
|
+
keys = synchronize{ @data.keys }
|
43
|
+
keys.each do |key|
|
44
|
+
entry = @data[key]
|
45
|
+
delete_entry(key, options) if entry && entry.expired?
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Prune the cache down so the entries fit within the specified memory size by removing
|
51
|
+
# the least recently accessed entries.
|
52
|
+
def prune(target_size, max_time = nil)
|
53
|
+
return if pruning?
|
54
|
+
@pruning = true
|
55
|
+
begin
|
56
|
+
start_time = Time.now
|
57
|
+
cleanup
|
58
|
+
instrument(:prune, target_size, :from => @cache_size) do
|
59
|
+
keys = synchronize{ @key_access.keys.sort{|a,b| @key_access[a].to_f <=> @key_access[b].to_f} }
|
60
|
+
keys.each do |key|
|
61
|
+
delete_entry(key, options)
|
62
|
+
return if @cache_size <= target_size || (max_time && Time.now - start_time > max_time)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
ensure
|
66
|
+
@pruning = false
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Return true if the cache is currently be pruned to remove older entries.
|
71
|
+
def pruning?
|
72
|
+
@pruning
|
73
|
+
end
|
74
|
+
|
75
|
+
# Increment an integer value in the cache.
|
76
|
+
def increment(name, amount = 1, options = nil)
|
77
|
+
synchronize do
|
78
|
+
options = merged_options(options)
|
79
|
+
if num = read(name, options)
|
80
|
+
num = num.to_i + amount
|
81
|
+
write(name, num, options)
|
82
|
+
num
|
83
|
+
else
|
84
|
+
nil
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Decrement an integer value in the cache.
|
90
|
+
def decrement(name, amount = 1, options = nil)
|
91
|
+
synchronize do
|
92
|
+
options = merged_options(options)
|
93
|
+
if num = read(name, options)
|
94
|
+
num = num.to_i - amount
|
95
|
+
write(name, num, options)
|
96
|
+
num
|
97
|
+
else
|
98
|
+
nil
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def delete_matched(matcher, options = nil)
|
104
|
+
options = merged_options(options)
|
105
|
+
instrument(:delete_matched, matcher.inspect) do
|
106
|
+
matcher = key_matcher(matcher, options)
|
107
|
+
keys = synchronize { @data.keys }
|
108
|
+
keys.each do |key|
|
109
|
+
delete_entry(key, options) if key.match(matcher)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def inspect # :nodoc:
|
115
|
+
"<##{self.class.name} entries=#{@data.size}, size=#{@cache_size}, options=#{@options.inspect}>"
|
116
|
+
end
|
117
|
+
|
118
|
+
# Synchronize calls to the cache. This should be called wherever the underlying cache implementation
|
119
|
+
# is not thread safe.
|
120
|
+
def synchronize(&block) # :nodoc:
|
121
|
+
@monitor.synchronize(&block)
|
122
|
+
end
|
123
|
+
|
124
|
+
protected
|
125
|
+
def read_entry(key, options) # :nodoc:
|
126
|
+
entry = @data[key]
|
127
|
+
synchronize do
|
128
|
+
if entry
|
129
|
+
@key_access[key] = Time.now.to_f
|
130
|
+
else
|
131
|
+
@key_access.delete(key)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
entry
|
135
|
+
end
|
136
|
+
|
137
|
+
def write_entry(key, entry, options) # :nodoc:
|
138
|
+
synchronize do
|
139
|
+
old_entry = @data[key]
|
140
|
+
@cache_size -= old_entry.size if old_entry
|
141
|
+
@cache_size += entry.size
|
142
|
+
@key_access[key] = Time.now.to_f
|
143
|
+
@data[key] = entry
|
144
|
+
prune(@max_size * 0.75, @max_prune_time) if @cache_size > @max_size
|
145
|
+
true
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def delete_entry(key, options) # :nodoc:
|
150
|
+
synchronize do
|
151
|
+
@key_access.delete(key)
|
152
|
+
entry = @data.delete(key)
|
153
|
+
@cache_size -= entry.size if entry
|
154
|
+
!!entry
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|