binary42-fastcache 0.1 → 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/benchmark/basic.rb +31 -0
- data/lib/fastcache.rb +5 -4
- data/lib/fastcache/bucket/modulus.rb +5 -7
- data/lib/fastcache/interface/connection.rb +9 -14
- data/lib/fastcache/memcache.rb +2 -3
- data/lib/fastcache/memcache/errors.rb +3 -0
- data/lib/fastcache/memcache/node.rb +2 -2
- data/lib/fastcache/memcache/protocol.rb +42 -23
- data/lib/fastcache/routing/basic_router.rb +20 -0
- data/lib/fastcache/util/maybe.rb +1 -1
- data/spec/routing/basic_router_spec.rb +37 -0
- metadata +5 -3
- data/benchmark/connection.rb +0 -15
- data/lib/fastcache/router/basic.rb +0 -0
data/benchmark/basic.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
$LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
|
3
|
+
require 'fastcache'
|
4
|
+
require 'memcache'
|
5
|
+
require 'benchmark'
|
6
|
+
|
7
|
+
NODE = ['localhost:11211']
|
8
|
+
|
9
|
+
n = 1000
|
10
|
+
Benchmark.bm(30) do |x|
|
11
|
+
x.report 'basic operations - memcache-client' do
|
12
|
+
conn = MemCache.new(*NODE)
|
13
|
+
n.times do
|
14
|
+
conn.get('f')
|
15
|
+
conn.set('f', '42')
|
16
|
+
conn.get('f')
|
17
|
+
conn.delete('f')
|
18
|
+
end
|
19
|
+
conn.reset
|
20
|
+
end
|
21
|
+
x.report 'basic operations - fastcache' do
|
22
|
+
conn = FastCache.connect(NODE)
|
23
|
+
n.times do
|
24
|
+
conn.get('f')
|
25
|
+
conn.set('f', '42')
|
26
|
+
conn.get('f')
|
27
|
+
conn.delete('f')
|
28
|
+
end
|
29
|
+
conn.close_all_connections
|
30
|
+
end
|
31
|
+
end
|
data/lib/fastcache.rb
CHANGED
@@ -14,7 +14,7 @@ require 'fastcache/hash/sha1'
|
|
14
14
|
|
15
15
|
# Key routers
|
16
16
|
# TODO: Check for ruby-ketama
|
17
|
-
require 'fastcache/
|
17
|
+
require 'fastcache/routing/basic_router'
|
18
18
|
|
19
19
|
# Networking and protocol support code
|
20
20
|
require 'fastcache/memcache'
|
@@ -32,9 +32,10 @@ class << FastCache
|
|
32
32
|
:type => 'raw'
|
33
33
|
}.merge(opts)
|
34
34
|
|
35
|
-
connections[opts[:name]].
|
35
|
+
connections[opts[:name]].close_all_connections if connections[opts[:name]]
|
36
36
|
|
37
|
-
|
37
|
+
node_list = node_list.split(',') if String === node_list
|
38
|
+
nodes = node_list.map {|node|
|
38
39
|
host, port = *node.split(':')
|
39
40
|
port ||= 80
|
40
41
|
[host, port.to_i]
|
@@ -65,4 +66,4 @@ private
|
|
65
66
|
@connections ||= {}
|
66
67
|
end
|
67
68
|
|
68
|
-
end
|
69
|
+
end
|
@@ -1,16 +1,14 @@
|
|
1
1
|
class FastCache::ModulusBucket
|
2
2
|
|
3
|
-
def initialize(
|
4
|
-
@
|
5
|
-
@key = key
|
3
|
+
def initialize(nodes)
|
4
|
+
@nodes = nodes
|
6
5
|
end
|
7
6
|
|
8
|
-
def select(
|
9
|
-
count = nodes.size
|
10
|
-
# Note: An upper bound on tries ought to be given at some point
|
7
|
+
def select(hash)
|
8
|
+
count = @nodes.size
|
11
9
|
count.times do |i|
|
12
10
|
begin
|
13
|
-
break yield(@
|
11
|
+
break yield(@nodes[(hash + i) % count])
|
14
12
|
rescue FastCache::Memcache::ProtocolError
|
15
13
|
next
|
16
14
|
end
|
@@ -1,24 +1,19 @@
|
|
1
1
|
class FastCache::Connection
|
2
2
|
include FastCache::Memcache::Protocol
|
3
3
|
|
4
|
-
attr_accessor :
|
5
|
-
attr_reader :nodes
|
4
|
+
attr_accessor :router
|
6
5
|
|
7
|
-
|
6
|
+
CONNECTION_OPTIONS = {
|
7
|
+
:router => FastCache::BasicRouter}
|
8
|
+
|
9
|
+
def initialize(nodes, opts = nil)
|
10
|
+
opts = CONNECTION_OPTIONS.merge(opts || {})
|
8
11
|
@nodes = nodes.map {|(host, port)| FastCache::Memcache::Node.new(host, port)}
|
9
|
-
@
|
10
|
-
@hash_class = FastCache::CRC32
|
11
|
-
@marshal_module = Marshal # Ruby's built in marshal
|
12
|
+
@router = opts[:router].new(@nodes)
|
12
13
|
end
|
13
14
|
|
14
|
-
def
|
15
|
+
def close_all_connections
|
15
16
|
@nodes.each do |node| node.close end
|
16
17
|
end
|
17
18
|
|
18
|
-
|
19
|
-
|
20
|
-
def bucket(key)
|
21
|
-
@bucket_class.new(key, @hash_class)
|
22
|
-
end
|
23
|
-
|
24
|
-
end
|
19
|
+
end
|
data/lib/fastcache/memcache.rb
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
module FastCache; end
|
2
|
-
module FastCache::Memcache
|
3
|
-
class ProtocolError < RuntimeError; end
|
4
|
-
end
|
2
|
+
module FastCache::Memcache; end
|
5
3
|
|
6
4
|
# Memcache components
|
7
5
|
require 'fastcache/memcache/node'
|
8
6
|
require 'fastcache/memcache/protocol'
|
7
|
+
require 'fastcache/memcache/errors'
|
@@ -30,7 +30,7 @@ class FastCache::Memcache::Node
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def close
|
33
|
-
socket.close
|
33
|
+
socket.close if @socket
|
34
34
|
@socket = nil
|
35
35
|
end
|
36
36
|
|
@@ -41,7 +41,7 @@ class FastCache::Memcache::Node
|
|
41
41
|
private
|
42
42
|
|
43
43
|
def socket
|
44
|
-
return @socket if @socket
|
44
|
+
return @socket if @socket && !@socket.closed?
|
45
45
|
|
46
46
|
@socket = nil
|
47
47
|
|
@@ -1,11 +1,8 @@
|
|
1
|
-
# Informal protocol for mixin:
|
2
|
-
# bucket will ask for a key and return a bucket
|
3
|
-
# nodes will return connection nodes
|
4
1
|
module FastCache::Memcache::Protocol
|
5
2
|
|
6
3
|
def get(key)
|
7
|
-
|
8
|
-
node.write "get #{
|
4
|
+
router.route(key) {|node|
|
5
|
+
node.write "get #{key}\r\n"
|
9
6
|
resp = node.gets
|
10
7
|
break FastCache::Maybe.nothing if resp == "END\r\n"
|
11
8
|
resp =~ /(\d+)\r/
|
@@ -21,8 +18,8 @@ module FastCache::Memcache::Protocol
|
|
21
18
|
|
22
19
|
def set(key, value, expiry = 0)
|
23
20
|
value = value.to_s
|
24
|
-
|
25
|
-
node.write "set #{
|
21
|
+
router.route(key) {|node|
|
22
|
+
node.write "set #{key} 0 #{expiry} #{value.size}\r\n#{value}\r\n"
|
26
23
|
result = node.gets
|
27
24
|
if result == "STORED\r\n"
|
28
25
|
FastCache::Maybe.just(value)
|
@@ -36,8 +33,8 @@ module FastCache::Memcache::Protocol
|
|
36
33
|
|
37
34
|
def add(key, value, expiry = 0)
|
38
35
|
data = value.to_s
|
39
|
-
|
40
|
-
node.write "add #{
|
36
|
+
router.route(key) {|node|
|
37
|
+
node.write "add #{key} 0 #{expiry} #{data.size}\r\n#{data}\r\n"
|
41
38
|
resp = node.gets
|
42
39
|
if resp == "STORED\r\n"
|
43
40
|
FastCache::Maybe.just(data)
|
@@ -51,8 +48,8 @@ module FastCache::Memcache::Protocol
|
|
51
48
|
|
52
49
|
def replace(key, value, expiry = 0)
|
53
50
|
data = value.to_s
|
54
|
-
|
55
|
-
node.write "replace #{
|
51
|
+
router.route(key) {|node|
|
52
|
+
node.write "replace #{key} 0 #{expiry} #{data.size}\r\n#{data}\r\n"
|
56
53
|
resp = node.gets
|
57
54
|
if resp == "STORED\r\n"
|
58
55
|
FastCache::Maybe.just(data)
|
@@ -65,12 +62,12 @@ module FastCache::Memcache::Protocol
|
|
65
62
|
end
|
66
63
|
|
67
64
|
def delete(key, expiry = 0)
|
68
|
-
|
69
|
-
node.write "delete #{
|
65
|
+
router.route(key) {|node|
|
66
|
+
node.write "delete #{key} #{expiry}\r\n"
|
70
67
|
resp = node.gets
|
71
68
|
resp == "DELETED\r\n"
|
72
69
|
}
|
73
|
-
rescue FastCache::Memcache::
|
70
|
+
rescue FastCache::Memcache::ProtocolError
|
74
71
|
FastCache::Maybe.nothing
|
75
72
|
end
|
76
73
|
|
@@ -78,20 +75,42 @@ module FastCache::Memcache::Protocol
|
|
78
75
|
fail 'Not implemented'
|
79
76
|
end
|
80
77
|
|
81
|
-
def incr(
|
82
|
-
|
78
|
+
def incr(key, count)
|
79
|
+
router.route(key) {|node|
|
80
|
+
node.write "incr #{key} #{count}\r\n"
|
81
|
+
resp = node.gets
|
82
|
+
resp == "NOT_FOUND\r\n" ?
|
83
|
+
nil :
|
84
|
+
resp.to_i
|
85
|
+
}
|
86
|
+
rescue FastCache::Memcache::ProtocolError
|
87
|
+
FastCache::Maybe.nothing
|
83
88
|
end
|
84
89
|
|
85
|
-
def decr(
|
86
|
-
|
90
|
+
def decr(key, count)
|
91
|
+
router.route(key) {|node|
|
92
|
+
node.write "decr #{key} #{count}\r\n"
|
93
|
+
resp = node.gets
|
94
|
+
resp == "NOT_FOUND\r\n" ?
|
95
|
+
nil :
|
96
|
+
resp.to_i
|
97
|
+
}
|
98
|
+
rescue FastCache::Memcache::ProtocolError
|
99
|
+
FastCache::Maybe.nothing
|
87
100
|
end
|
88
101
|
|
89
|
-
def flush_all_caches
|
90
|
-
|
102
|
+
def flush_all_caches(delay = nil)
|
103
|
+
router.each {|node|
|
104
|
+
node.write "flush_all #{delay} noreply\r\n"
|
105
|
+
}
|
106
|
+
self
|
91
107
|
end
|
92
108
|
|
93
|
-
def flush_cache(key)
|
94
|
-
|
109
|
+
def flush_cache(key, delay = nil)
|
110
|
+
router.route(key) {|node|
|
111
|
+
node.write "flush_all #{delay} noreply\r\n"
|
112
|
+
}
|
113
|
+
self
|
95
114
|
end
|
96
115
|
|
97
116
|
def stats(*)
|
@@ -99,7 +118,7 @@ module FastCache::Memcache::Protocol
|
|
99
118
|
end
|
100
119
|
|
101
120
|
def reset_connections
|
102
|
-
|
121
|
+
router.each {|node| node.close}
|
103
122
|
end
|
104
123
|
|
105
124
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class FastCache::BasicRouter
|
2
|
+
|
3
|
+
attr_reader :bucket_delegate, :hash_delegate
|
4
|
+
|
5
|
+
def initialize(nodes, bucket_class = FastCache::ModulusBucket, hash_class = FastCache::CRC32)
|
6
|
+
@nodes = nodes
|
7
|
+
@bucket_delegate = bucket_class.new(nodes)
|
8
|
+
@hash_delegate = hash_class
|
9
|
+
end
|
10
|
+
|
11
|
+
def each(&b)
|
12
|
+
@nodes.each(&b)
|
13
|
+
end
|
14
|
+
|
15
|
+
def route(key, &b)
|
16
|
+
digest = @hash_delegate.new(key.to_s).digest
|
17
|
+
@bucket_delegate.select(digest.unpack('N').first, &b)
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
data/lib/fastcache/util/maybe.rb
CHANGED
@@ -0,0 +1,37 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
include FastCache
|
3
|
+
|
4
|
+
describe BasicRouter, '.new' do
|
5
|
+
|
6
|
+
it 'should take a nodes list, bucket delegate, and hashing delegate' do
|
7
|
+
router = BasicRouter.new([], ModulusBucket, CRC32)
|
8
|
+
router.bucket_delegate.should be_kind_of(ModulusBucket)
|
9
|
+
router.hash_delegate.should == CRC32
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should default to modulus and crc32 based delegates' do
|
13
|
+
router = BasicRouter.new([])
|
14
|
+
router.bucket_delegate.should be_kind_of(ModulusBucket)
|
15
|
+
router.hash_delegate.should == CRC32
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
describe BasicRouter, '#route' do
|
21
|
+
|
22
|
+
before :each do
|
23
|
+
@nodes = [:one, :two, :three, :four]
|
24
|
+
@router = BasicRouter.new(@nodes)
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should route to the same buck if the string representation is the same' do
|
28
|
+
@router.route(:key) {|n| @n1 = n}
|
29
|
+
@router.route('key') {|n| @n2 = n}
|
30
|
+
@n1.should == @n2
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should return a node' do
|
34
|
+
@nodes.should include(@router.route('x') {|n| n})
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: binary42-fastcache
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: "0.
|
4
|
+
version: "0.2"
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brian Mitchell
|
@@ -26,18 +26,19 @@ files:
|
|
26
26
|
- lib/fastcache/hash/md5.rb
|
27
27
|
- lib/fastcache/hash/crc32.rb
|
28
28
|
- lib/fastcache/util/maybe.rb
|
29
|
+
- lib/fastcache/routing/basic_router.rb
|
29
30
|
- lib/fastcache/marshal/yaml.rb
|
30
31
|
- lib/fastcache/marshal/duck.rb
|
31
32
|
- lib/fastcache/marshal/ruby.rb
|
32
33
|
- lib/fastcache/bucket/modulus.rb
|
33
34
|
- lib/fastcache/bucket/consistent.rb
|
34
|
-
- lib/fastcache/router/basic.rb
|
35
35
|
- lib/fastcache/interface/dictionary.rb
|
36
36
|
- lib/fastcache/interface/evaluator.rb
|
37
37
|
- lib/fastcache/interface/connection.rb
|
38
38
|
- lib/fastcache/memcache.rb
|
39
39
|
- lib/fastcache/memcache/node.rb
|
40
40
|
- lib/fastcache/memcache/protocol.rb
|
41
|
+
- lib/fastcache/memcache/errors.rb
|
41
42
|
- lib/fastcache.rb
|
42
43
|
- LICENSE
|
43
44
|
- Rakefile
|
@@ -73,9 +74,10 @@ specification_version: 2
|
|
73
74
|
summary: FastCache - a client side implementation of the memcached protocol
|
74
75
|
test_files:
|
75
76
|
- spec/util/maybe_spec.rb
|
77
|
+
- spec/routing/basic_router_spec.rb
|
76
78
|
- spec/spec_helper.rb
|
77
79
|
- spec/memcache/node_spec.rb
|
78
80
|
- spec/memcache/protocol_spec.rb
|
79
|
-
- benchmark/connection.rb
|
80
81
|
- benchmark/benchmark_helper.rb
|
82
|
+
- benchmark/basic.rb
|
81
83
|
- Rakefile
|
data/benchmark/connection.rb
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
n = 1000
|
2
|
-
Benchmark.bm(30) do |x|
|
3
|
-
x.report 'manual connection open/close' do
|
4
|
-
n.times do
|
5
|
-
conn = FastCache.connect NODE
|
6
|
-
conn.close
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
|
-
x.report 'block connection open/close' do
|
11
|
-
n.times do
|
12
|
-
FastCache.connect(NODE) {}
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
File without changes
|