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 CHANGED
@@ -66,11 +66,11 @@ But <i>other_key</i> is still peachy.
66
66
  === Server
67
67
 
68
68
 
69
- >> ruby -rubygems runner.rb --help
69
+ >> tokyo_cache_cow --help
70
70
 
71
71
  --------------
72
72
 
73
- Usage: runner.rb [options]
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
@@ -1,4 +1,4 @@
1
1
  ---
2
- :patch: 1
3
- :major: 0
4
2
  :minor: 0
3
+ :patch: 2
4
+ :major: 0
data/bin/tokyo_cache_cow CHANGED
@@ -1,47 +1,6 @@
1
- require 'eventmachine'
2
- require 'optparse'
3
-
4
- $:.unshift File.join(File.dirname(__FILE__), '..')
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!
@@ -1,4 +1,5 @@
1
1
  $:.unshift File.dirname(__FILE__)
2
2
 
3
+ require 'tokyo_cache_cow/runner'
3
4
  require 'tokyo_cache_cow/server'
4
- require 'tokyo_cache_cow/providers'
5
+ require 'tokyo_cache_cow/cache'
@@ -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(path)
17
- @path = path
18
- FileUtils.rm_rf(@path)
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.rm(Dir.glob(File.join(@path, '*'))) and true
73
+ FileUtils.rm_rf(@path)
74
+ FileUtils.mkdir_p(@path)
75
+ true
74
76
  end
75
77
 
76
78
  def delete(key, expires = nil)
@@ -10,7 +10,7 @@ class TokyoCacheCow
10
10
  end
11
11
  end
12
12
 
13
- def initialize(file)
13
+ def initialize(options = {})
14
14
  @cache = {}
15
15
  end
16
16
 
@@ -108,9 +108,10 @@ class TokyoCacheCow
108
108
  q.searchout
109
109
  end
110
110
 
111
- def initialize(file)
111
+ def initialize(options = {})
112
112
  @cache = TDB::new # hash database
113
- @cache.open(file, TDB::OWRITER | TDB::OCREAT | TDB::OTRUNC)
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
- send_data @cache.delete(key) ?
137
- DeletedReply : NotDeletedReply
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(nil),
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.1
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-21 00:00:00 -07:00
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