joshbuddy-tokyo_cache_cow 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|