joshbuddy-tokyo_cache_cow 0.0.1 → 0.0.2
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/README.rdoc +2 -2
- data/VERSION.yml +2 -2
- data/bin/tokyo_cache_cow +5 -46
- data/lib/tokyo_cache_cow.rb +2 -1
- data/lib/tokyo_cache_cow/cache/file_memcache.rb +7 -5
- data/lib/tokyo_cache_cow/cache/hash_memcache.rb +1 -1
- data/lib/tokyo_cache_cow/cache/tokyo_cabinet_memcache.rb +3 -2
- data/lib/tokyo_cache_cow/runner.rb +110 -0
- data/lib/tokyo_cache_cow/server.rb +11 -4
- data/spec/cache_spec.rb +3 -4
- data/spec/server_spec.rb +46 -0
- metadata +3 -2
data/README.rdoc
CHANGED
@@ -66,11 +66,11 @@ But <i>other_key</i> is still peachy.
|
|
66
66
|
=== Server
|
67
67
|
|
68
68
|
|
69
|
-
>>
|
69
|
+
>> tokyo_cache_cow --help
|
70
70
|
|
71
71
|
--------------
|
72
72
|
|
73
|
-
Usage:
|
73
|
+
Usage: tokyo_cache_cow [options]
|
74
74
|
-p, --port[OPTIONAL] Port (default: 11211)
|
75
75
|
-h, --host[OPTIONAL] Host (default: 0.0.0.0)
|
76
76
|
--help Show this help message.
|
data/VERSION.yml
CHANGED
data/bin/tokyo_cache_cow
CHANGED
@@ -1,47 +1,6 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
require 'lib/tokyo_cache_cow'
|
6
|
-
|
7
|
-
options = {:port => '11211', :host => '0.0.0.0', :provider => 'tokyo_cabinet', :file => '/tmp/cache'}
|
8
|
-
OptionParser.new do |opts|
|
9
|
-
opts.banner = "Usage: runner.rb [options]"
|
10
|
-
|
11
|
-
opts.on("-p[OPTIONAL]", "--port", "Port (default: #{options[:port]})") do |v|
|
12
|
-
options[:port] = v
|
13
|
-
end
|
14
|
-
|
15
|
-
opts.on("-h[OPTIONAL]", "--host", "Host (default: #{options[:host]})") do |v|
|
16
|
-
options[:host] = v
|
17
|
-
end
|
18
|
-
|
19
|
-
opts.on("-c[OPTIONAL]", "--cache-provider", "Cache provider (default: #{options[:provider]})") do |v|
|
20
|
-
options[:provider] = v
|
21
|
-
end
|
22
|
-
|
23
|
-
opts.on("-f[OPTIONAL]", "--file", "File (default: #{options[:file]})") do |v|
|
24
|
-
options[:file] = v
|
25
|
-
end
|
26
|
-
|
27
|
-
opts.on_tail("-h", "--help", "Show this help message.") { puts opts; exit }
|
28
|
-
|
29
|
-
end.parse!
|
30
|
-
|
31
|
-
trap("INT") { EM.stop; puts "moooooooo ya later" }
|
32
|
-
|
33
|
-
if File.exists?(File.join(File.dirname(__FILE__), options[:provider]))
|
34
|
-
require File.join(File.dirname(__FILE__), options[:provider])
|
35
|
-
cache = $cache
|
36
|
-
else
|
37
|
-
require 'lib/tokyo_cache_cow/cache'
|
38
|
-
cache = TokyoCacheCow::Cache.const_get("#{options[:provider]}_memcache".split('_').map{|e| e.capitalize}.join.to_sym).new(options[:file])
|
39
|
-
end
|
40
|
-
|
41
|
-
puts "Starting the tokyo cache cow"
|
42
|
-
EM.run do
|
43
|
-
EM.start_server(options[:host], options[:port], TokyoCacheCow::Server) do |c|
|
44
|
-
c.cache = cache
|
45
|
-
end
|
46
|
-
end
|
1
|
+
#!/usr/bin/env ruby -rubygems
|
2
|
+
# Tokyo cache cow command line interface script.
|
3
|
+
# Run <tt>tokyo_cache_cow -h</tt> to get more usage.
|
4
|
+
require File.dirname(__FILE__) + '/../lib/tokyo_cache_cow'
|
47
5
|
|
6
|
+
TokyoCacheCow::Runner.new(ARGV).start!
|
data/lib/tokyo_cache_cow.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'yaml'
|
2
2
|
require 'fileutils'
|
3
3
|
require 'cgi'
|
4
|
+
|
4
5
|
class TokyoCacheCow
|
5
6
|
class Cache
|
6
7
|
class FileMemcache < Base
|
@@ -13,10 +14,9 @@ class TokyoCacheCow
|
|
13
14
|
end
|
14
15
|
end
|
15
16
|
|
16
|
-
def initialize(
|
17
|
-
@path =
|
18
|
-
|
19
|
-
FileUtils.mkdir_p(@path)
|
17
|
+
def initialize(options = {})
|
18
|
+
@path = options[:file] or raise('must supply file')
|
19
|
+
flush_all
|
20
20
|
end
|
21
21
|
|
22
22
|
def time_expired?(time)
|
@@ -70,7 +70,9 @@ class TokyoCacheCow
|
|
70
70
|
end
|
71
71
|
|
72
72
|
def flush_all
|
73
|
-
FileUtils.
|
73
|
+
FileUtils.rm_rf(@path)
|
74
|
+
FileUtils.mkdir_p(@path)
|
75
|
+
true
|
74
76
|
end
|
75
77
|
|
76
78
|
def delete(key, expires = nil)
|
@@ -108,9 +108,10 @@ class TokyoCacheCow
|
|
108
108
|
q.searchout
|
109
109
|
end
|
110
110
|
|
111
|
-
def initialize(
|
111
|
+
def initialize(options = {})
|
112
112
|
@cache = TDB::new # hash database
|
113
|
-
|
113
|
+
options[:file] ?
|
114
|
+
@cache.open(options[:file], TDB::OWRITER | TDB::OCREAT | TDB::OTRUNC) : raise('must supply file')
|
114
115
|
@cache.setxmsiz(500_000_000)
|
115
116
|
end
|
116
117
|
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'eventmachine'
|
2
|
+
require 'optparse'
|
3
|
+
|
4
|
+
class TokyoCacheCow
|
5
|
+
class Runner
|
6
|
+
|
7
|
+
attr_reader :options
|
8
|
+
|
9
|
+
def initialize(argv)
|
10
|
+
@argv = argv
|
11
|
+
# Default options values
|
12
|
+
@options = {
|
13
|
+
:chdir => Dir.pwd,
|
14
|
+
:address => '0.0.0.0',
|
15
|
+
:port => Server::DefaultPort,
|
16
|
+
:class => 'TokyoCacheCow::Cache::TokyoCabinetMemcache',
|
17
|
+
:require => [],
|
18
|
+
:file => '/tmp/tcc-cache',
|
19
|
+
:pid => '/tmp/tcc.pid',
|
20
|
+
:special_delete_prefix => nil,
|
21
|
+
:daemonize => false
|
22
|
+
}
|
23
|
+
|
24
|
+
parse!
|
25
|
+
end
|
26
|
+
|
27
|
+
def parser
|
28
|
+
OptionParser.new do |opts|
|
29
|
+
opts.banner = "Usage: tokyo_cache_cow [options]"
|
30
|
+
|
31
|
+
opts.separator ""
|
32
|
+
opts.separator "Options:"
|
33
|
+
|
34
|
+
opts.on("-p[OPTIONAL]", "--port", "Port (default: #{options[:port]})") do |v|
|
35
|
+
options[:port] = v
|
36
|
+
end
|
37
|
+
|
38
|
+
opts.on("-a[OPTIONAL]", "--address", "Address (default: #{options[:address]})") do |v|
|
39
|
+
options[:address] = v
|
40
|
+
end
|
41
|
+
|
42
|
+
opts.on("-c[OPTIONAL]", "--class", "Cache provider class (default: #{options[:class]})") do |v|
|
43
|
+
options[:provider] = v
|
44
|
+
end
|
45
|
+
|
46
|
+
opts.on("-r[OPTIONAL]", "--require", "require") do |v|
|
47
|
+
options[:require] << v
|
48
|
+
end
|
49
|
+
|
50
|
+
opts.on("-f[OPTIONAL]", "--file", "File (default: #{options[:file]})") do |v|
|
51
|
+
options[:file] = v
|
52
|
+
end
|
53
|
+
|
54
|
+
opts.on("-d[OPTIONAL]", "--daemonize", "Daemonize (default: #{options[:daemonize]})") do |v|
|
55
|
+
options[:daemonize] = true
|
56
|
+
end
|
57
|
+
|
58
|
+
opts.on("-P[OPTIONAL]", "--pid", "Pid file (default: #{options[:pid]})") do |v|
|
59
|
+
options[:pid] = true
|
60
|
+
end
|
61
|
+
|
62
|
+
opts.on("-m[OPTIONAL]", "--matcher", "Special flag for doing matched deletes (not enabled by default)") do |v|
|
63
|
+
options[:special_delete_char] = v
|
64
|
+
end
|
65
|
+
|
66
|
+
opts.on_tail("-h", "--help", "Show this help message.") { puts opts; exit }
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def parse!
|
72
|
+
parser.parse!(@argv)
|
73
|
+
end
|
74
|
+
|
75
|
+
def start!
|
76
|
+
@options[:require].each {|r| require r}
|
77
|
+
|
78
|
+
clazz = @options[:class].to_s.split('::').inject(Kernel) do |parent, mod|
|
79
|
+
parent.const_get(mod)
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
address = @options[:address]
|
84
|
+
port = @options[:port]
|
85
|
+
special_delete_char = @options[:special_delete_char]
|
86
|
+
puts "Starting the tokyo cache cow #{address} #{port}"
|
87
|
+
pid = EM.fork_reactor do
|
88
|
+
cache = clazz.new(:file => @options[:file])
|
89
|
+
trap("INT") { EM.stop; puts "\nmoooooooo ya later"; exit(0)}
|
90
|
+
EM.run do
|
91
|
+
EM.start_server(address, port, TokyoCacheCow::Server) do |c|
|
92
|
+
c.cache = cache
|
93
|
+
c.special_delete_char = special_delete_char if special_delete_char
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
if @options[:daemonize]
|
99
|
+
File.open(options[:pid], 'w') {|f| f << pid}
|
100
|
+
Process.detach(pid)
|
101
|
+
else
|
102
|
+
trap("INT") { }
|
103
|
+
Process.wait(pid)
|
104
|
+
end
|
105
|
+
|
106
|
+
pid
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
end
|
@@ -4,6 +4,8 @@ require 'eventmachine'
|
|
4
4
|
class TokyoCacheCow
|
5
5
|
class Server < EventMachine::Connection
|
6
6
|
|
7
|
+
DefaultPort = 11211
|
8
|
+
|
7
9
|
Terminator = "\r\n"
|
8
10
|
|
9
11
|
#set
|
@@ -42,7 +44,7 @@ class TokyoCacheCow
|
|
42
44
|
|
43
45
|
TerminatorRegex = /\r\n/
|
44
46
|
|
45
|
-
attr_accessor :cache
|
47
|
+
attr_accessor :cache, :special_delete_char
|
46
48
|
|
47
49
|
def send_client_error(message = "invalid arguments")
|
48
50
|
send_data(ClientError % message.to_s)
|
@@ -68,7 +70,6 @@ class TokyoCacheCow
|
|
68
70
|
|
69
71
|
def receive_data(data)
|
70
72
|
ss = StringScanner.new(data)
|
71
|
-
|
72
73
|
while part = ss.scan_until(TerminatorRegex)
|
73
74
|
begin
|
74
75
|
command_argument_separator_index = part.index(/\s/)
|
@@ -133,8 +134,14 @@ class TokyoCacheCow
|
|
133
134
|
when DeleteCommand
|
134
135
|
(key, noreply) = [$1.chomp, !$2.nil?]
|
135
136
|
next unless validate_key(key)
|
136
|
-
|
137
|
-
|
137
|
+
if special_delete_char && key.index(special_delete_char) == 0
|
138
|
+
key.slice!(0,special_delete_char.size)
|
139
|
+
@cache.delete_match(key)
|
140
|
+
send_data(DeletedReply)
|
141
|
+
else
|
142
|
+
send_data @cache.delete(key) ?
|
143
|
+
DeletedReply : NotDeletedReply
|
144
|
+
end
|
138
145
|
end
|
139
146
|
when 'delete_match'
|
140
147
|
DeleteMatchCommand.match(args)
|
data/spec/cache_spec.rb
CHANGED
@@ -2,11 +2,10 @@ require 'benchmark'
|
|
2
2
|
require 'lib/tokyo_cache_cow/cache'
|
3
3
|
|
4
4
|
{
|
5
|
-
'tokyo cabinet memcache' => TokyoCacheCow::Cache::TokyoCabinetMemcache.new('/tmp/tcc1'),
|
6
|
-
'hash memcache' => TokyoCacheCow::Cache::HashMemcache.new
|
7
|
-
'file memcache' => TokyoCacheCow::Cache::FileMemcache.new('/tmp/filecache')
|
5
|
+
'tokyo cabinet memcache' => TokyoCacheCow::Cache::TokyoCabinetMemcache.new(:file => '/tmp/tcc1'),
|
6
|
+
'hash memcache' => TokyoCacheCow::Cache::HashMemcache.new,
|
7
|
+
'file memcache' => TokyoCacheCow::Cache::FileMemcache.new(:file => '/tmp/filecache')
|
8
8
|
}.each do |name, cache|
|
9
|
-
|
10
9
|
describe name do
|
11
10
|
|
12
11
|
before(:each) do
|
data/spec/server_spec.rb
CHANGED
@@ -1,11 +1,18 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'memcached'
|
3
3
|
require 'benchmark'
|
4
|
+
require 'lib/tokyo_cache_cow'
|
4
5
|
|
5
6
|
cache = Memcached.new('127.0.0.1:11211')
|
6
7
|
|
7
8
|
describe 'memcache server' do
|
8
9
|
|
10
|
+
before(:all) do
|
11
|
+
runner = TokyoCacheCow::Runner.new(['--daemonize'])
|
12
|
+
@pid = runner.start!
|
13
|
+
sleep(1)
|
14
|
+
end
|
15
|
+
|
9
16
|
before(:each) do
|
10
17
|
cache.flush
|
11
18
|
end
|
@@ -20,5 +27,44 @@ describe 'memcache server' do
|
|
20
27
|
cache.delete('asd')
|
21
28
|
proc {cache.get('asd')}.should raise_error Memcached::NotFound
|
22
29
|
end
|
30
|
+
|
31
|
+
after(:all) do
|
32
|
+
Process.kill('INT', @pid)
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
describe 'memcache server with special delete support' do
|
39
|
+
|
40
|
+
before(:all) do
|
41
|
+
runner = TokyoCacheCow::Runner.new(['--daemonize', '-m...'])
|
42
|
+
@pid = runner.start!
|
43
|
+
sleep(1)
|
44
|
+
end
|
45
|
+
|
46
|
+
before(:each) do
|
47
|
+
cache.flush
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should delete match through special char " do
|
51
|
+
cache.set('asd123', "qweqweasd")
|
52
|
+
cache.set('asd456', "qweqweasd")
|
53
|
+
cache.set('asd678', "qweqweasd")
|
54
|
+
cache.set('qwe678', "qweqweasd")
|
55
|
+
cache.set('qwe679', "qweqweasd")
|
56
|
+
cache.delete('...asd')
|
57
|
+
proc {cache.get('asd123')}.should raise_error Memcached::NotFound
|
58
|
+
proc {cache.get('asd456')}.should raise_error Memcached::NotFound
|
59
|
+
proc {cache.get('asd678')}.should raise_error Memcached::NotFound
|
60
|
+
cache.delete('...qwe678')
|
61
|
+
proc {cache.get('qwe678')}.should raise_error Memcached::NotFound
|
62
|
+
cache.get('qwe679').should=='qweqweasd'
|
63
|
+
end
|
64
|
+
|
65
|
+
after(:all) do
|
66
|
+
Process.kill('INT', @pid)
|
67
|
+
end
|
68
|
+
|
23
69
|
|
24
70
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: joshbuddy-tokyo_cache_cow
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joshua Hull
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-04-
|
12
|
+
date: 2009-04-30 00:00:00 -07:00
|
13
13
|
default_executable: tokyo_cache_cow
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -33,6 +33,7 @@ files:
|
|
33
33
|
- lib/tokyo_cache_cow/cache/tokyo_cabinet_memcache.rb
|
34
34
|
- lib/tokyo_cache_cow/cache.rb
|
35
35
|
- lib/tokyo_cache_cow/providers.rb
|
36
|
+
- lib/tokyo_cache_cow/runner.rb
|
36
37
|
- lib/tokyo_cache_cow/server.rb
|
37
38
|
- lib/tokyo_cache_cow.rb
|
38
39
|
- spec/cache_spec.rb
|