ruby-memcached 0.1.0
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.
- checksums.yaml +7 -0
- data/bin/memcached-client.rb +29 -0
- data/bin/memcached-server.rb +22 -0
- data/lib/ruby-memcached.rb +3 -0
- data/lib/ruby-memcached/Client.rb +161 -0
- data/lib/ruby-memcached/Constants.rb +5 -0
- data/lib/ruby-memcached/Item.rb +38 -0
- data/lib/ruby-memcached/Memcached.rb +121 -0
- data/lib/ruby-memcached/Server.rb +194 -0
- data/lib/ruby-memcached/constants/Commands.rb +26 -0
- data/lib/ruby-memcached/constants/CommandsRegex.rb +26 -0
- data/lib/ruby-memcached/constants/Errors.rb +11 -0
- data/lib/ruby-memcached/constants/Responses.rb +18 -0
- data/lib/ruby-memcached/constants/ResponsesRegex.rb +12 -0
- metadata +120 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 11f93dfef10cbbbc92972e071a7662c78ada89bbc098fc59905ad386c5a62c25
|
4
|
+
data.tar.gz: e94b21ce9b83b03bd204114b2344ae398971428e1154f1508daeebbfb17ca7cc
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 10d7e9ca7df90a8f07f66d5627cc4b9012b2e66762014800d796650424403a49ae2855bd20052982051094bd2f862e515ae84ef9e87c0ff43210a53075d3064f
|
7
|
+
data.tar.gz: 0a25744a8187a5d3f1d48a23e10ebe89d4ab6e830ff5f6ddb42ea7f881c0488ffd0aed2a5f025ac754832bdf618aa427ad0551ffe03f8d1cb62c6ace741a16f4
|
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'socket'
|
4
|
+
require_relative '../lib/ruby-memcached.rb'
|
5
|
+
|
6
|
+
|
7
|
+
host = ARGV[0]
|
8
|
+
port = ARGV[1]
|
9
|
+
server = TCPSocket.new(host, port)
|
10
|
+
|
11
|
+
listener = Thread.new {
|
12
|
+
while response = server.gets()
|
13
|
+
puts("Server: " + response)
|
14
|
+
end
|
15
|
+
}
|
16
|
+
|
17
|
+
speaker = Thread.new {
|
18
|
+
while true
|
19
|
+
print("> ")
|
20
|
+
server.puts(STDIN.gets())
|
21
|
+
break if $_ =~ RubyMemcached::CommandsRegex.end
|
22
|
+
sleep(0.1)
|
23
|
+
end
|
24
|
+
}
|
25
|
+
|
26
|
+
listener.join()
|
27
|
+
speaker.join()
|
28
|
+
|
29
|
+
server.close()
|
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require_relative '../lib/ruby-memcached.rb'
|
4
|
+
|
5
|
+
puts('Creating server...')
|
6
|
+
host = ARGV[0]
|
7
|
+
port = ARGV[1]
|
8
|
+
gc_interval = ARGV[2].to_i()
|
9
|
+
|
10
|
+
server = RubyMemcached::Server.new(host, port)
|
11
|
+
|
12
|
+
main = Thread.new {
|
13
|
+
puts('Starting server...')
|
14
|
+
server.start()
|
15
|
+
}
|
16
|
+
|
17
|
+
gc = Thread.new {
|
18
|
+
server.start_gc(gc_interval) if gc_interval > 0
|
19
|
+
}
|
20
|
+
|
21
|
+
main.join()
|
22
|
+
puts('Server closed')
|
@@ -0,0 +1,161 @@
|
|
1
|
+
require 'socket'
|
2
|
+
|
3
|
+
require_relative './Memcached.rb'
|
4
|
+
require_relative './Constants.rb'
|
5
|
+
|
6
|
+
module RubyMemcached
|
7
|
+
class Client
|
8
|
+
|
9
|
+
attr_reader :host
|
10
|
+
attr_reader :port
|
11
|
+
|
12
|
+
def initialize(host, port)
|
13
|
+
@host = host
|
14
|
+
@port = port
|
15
|
+
@server = TCPSocket.new(host, port)
|
16
|
+
end
|
17
|
+
|
18
|
+
def get(keys)
|
19
|
+
keys_string = keys.reduce { |ss, s| ss + ' ' + s }
|
20
|
+
@server.puts(Commands.get % keys_string)
|
21
|
+
|
22
|
+
items = []
|
23
|
+
|
24
|
+
loop do
|
25
|
+
case @server.gets()
|
26
|
+
when ResponsesRegex.get
|
27
|
+
key = $~['key']
|
28
|
+
flags = $~['flags'].to_i()
|
29
|
+
bytes = $~['bytes'].to_i()
|
30
|
+
data = @server.read(bytes + 1).chomp()
|
31
|
+
|
32
|
+
items << Memcached::Item.new(key, data, flags, 0, bytes, nil)
|
33
|
+
|
34
|
+
when ResponsesRegex.end
|
35
|
+
break
|
36
|
+
|
37
|
+
when /.*ERROR.*/
|
38
|
+
break
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
return items
|
43
|
+
end
|
44
|
+
|
45
|
+
def gets(keys)
|
46
|
+
keys_string = keys.reduce { |ss, s| ss + ' ' + s }
|
47
|
+
@server.puts(Commands.gets % keys_string)
|
48
|
+
|
49
|
+
items = []
|
50
|
+
|
51
|
+
loop do
|
52
|
+
case @server.gets()
|
53
|
+
when ResponsesRegex.gets
|
54
|
+
key = $~['key']
|
55
|
+
flags = $~['flags'].to_i()
|
56
|
+
bytes = $~['bytes'].to_i()
|
57
|
+
cas_id = $~['cas_id'].to_i()
|
58
|
+
data = @server.read(bytes + 1).chomp()
|
59
|
+
|
60
|
+
items << Memcached::Item.new(key, data, flags, 0, bytes, cas_id)
|
61
|
+
|
62
|
+
when ResponsesRegex.end
|
63
|
+
break
|
64
|
+
|
65
|
+
when /.*ERROR.*/
|
66
|
+
break
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
return items
|
71
|
+
end
|
72
|
+
|
73
|
+
def set(key, flags, exptime, bytes, data)
|
74
|
+
@server.puts(Commands.set % [
|
75
|
+
key,
|
76
|
+
flags,
|
77
|
+
exptime,
|
78
|
+
bytes,
|
79
|
+
'',
|
80
|
+
data
|
81
|
+
])
|
82
|
+
|
83
|
+
return Responses.to_h[Responses.key @server.gets()]
|
84
|
+
end
|
85
|
+
|
86
|
+
def add(key, flags, exptime, bytes, data)
|
87
|
+
@server.puts(Commands.add % [
|
88
|
+
key,
|
89
|
+
flags,
|
90
|
+
exptime,
|
91
|
+
bytes,
|
92
|
+
'',
|
93
|
+
data
|
94
|
+
])
|
95
|
+
|
96
|
+
return Responses.to_h[Responses.key @server.gets()]
|
97
|
+
end
|
98
|
+
|
99
|
+
def replace(key, flags, exptime, bytes, data)
|
100
|
+
@server.puts(Commands.replace % [
|
101
|
+
key,
|
102
|
+
flags,
|
103
|
+
exptime,
|
104
|
+
bytes,
|
105
|
+
'',
|
106
|
+
data
|
107
|
+
])
|
108
|
+
|
109
|
+
return Responses.to_h[Responses.key @server.gets()]
|
110
|
+
end
|
111
|
+
|
112
|
+
def append(key, bytes, data)
|
113
|
+
@server.puts(Commands.append % [
|
114
|
+
key,
|
115
|
+
bytes,
|
116
|
+
'',
|
117
|
+
data
|
118
|
+
])
|
119
|
+
|
120
|
+
return Responses.to_h[Responses.key @server.gets()]
|
121
|
+
end
|
122
|
+
|
123
|
+
def prepend(key, bytes, data)
|
124
|
+
@server.puts(Commands._prepend % [
|
125
|
+
key,
|
126
|
+
bytes,
|
127
|
+
'',
|
128
|
+
data
|
129
|
+
])
|
130
|
+
|
131
|
+
return Responses.to_h[Responses.key @server.gets()]
|
132
|
+
end
|
133
|
+
|
134
|
+
def cas(key, flags, exptime, bytes, cas_id, data)
|
135
|
+
@server.puts(Commands.cas % [
|
136
|
+
key,
|
137
|
+
flags,
|
138
|
+
exptime,
|
139
|
+
bytes,
|
140
|
+
cas_id,
|
141
|
+
'',
|
142
|
+
data
|
143
|
+
])
|
144
|
+
|
145
|
+
return Responses.to_h[Responses.key @server.gets()]
|
146
|
+
end
|
147
|
+
|
148
|
+
def delete(key)
|
149
|
+
@server.puts(Commands.delete % key)
|
150
|
+
return Responses.to_h[Responses.key @server.gets()]
|
151
|
+
end
|
152
|
+
|
153
|
+
def end()
|
154
|
+
@server.puts(Commands.end)
|
155
|
+
end
|
156
|
+
|
157
|
+
def reconnect()
|
158
|
+
@server = TCPSocket.new(@host, @port)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module RubyMemcached
|
2
|
+
class Memcached::Item
|
3
|
+
|
4
|
+
attr_accessor :key
|
5
|
+
attr_accessor :data
|
6
|
+
attr_accessor :flags
|
7
|
+
attr_accessor :exptime
|
8
|
+
attr_accessor :bytes
|
9
|
+
attr_accessor :cas_id
|
10
|
+
|
11
|
+
attr_accessor :lock
|
12
|
+
|
13
|
+
def initialize(key, data, flags, exptime, bytes, cas_id)
|
14
|
+
@key = key
|
15
|
+
@data = data
|
16
|
+
@flags = flags
|
17
|
+
@bytes = bytes
|
18
|
+
@exptime = get_exptime(exptime.to_i)
|
19
|
+
@cas_id = cas_id
|
20
|
+
|
21
|
+
@lock = Mutex.new()
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_s()
|
25
|
+
return @key
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def get_exptime(exptime)
|
31
|
+
if (exptime == 0)
|
32
|
+
return nil
|
33
|
+
elsif (exptime < 1592000)
|
34
|
+
return Time.now().getutc() + exptime
|
35
|
+
else
|
36
|
+
return Time.at(exptime)
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require 'concurrent'
|
2
|
+
|
3
|
+
module RubyMemcached
|
4
|
+
class Memcached
|
5
|
+
|
6
|
+
attr_reader :storage
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@storage = Concurrent::Hash.new()
|
10
|
+
end
|
11
|
+
|
12
|
+
def get(key)
|
13
|
+
self.check_exptime(key)
|
14
|
+
return @storage[key]
|
15
|
+
end
|
16
|
+
|
17
|
+
def get_multi(keys)
|
18
|
+
result = []
|
19
|
+
for key in keys do
|
20
|
+
item = self.get(key)
|
21
|
+
result.append(item) unless item.nil?
|
22
|
+
end
|
23
|
+
return result
|
24
|
+
end
|
25
|
+
|
26
|
+
def set(key, flags, exptime, bytes, data)
|
27
|
+
if(@storage.key?(key))
|
28
|
+
cas_id = @storage[key].cas_id + 1
|
29
|
+
else
|
30
|
+
cas_id = 0
|
31
|
+
end
|
32
|
+
new_item = Item.new(key, data, flags, exptime, bytes, cas_id)
|
33
|
+
@storage.store(key, new_item)
|
34
|
+
return Responses.stored
|
35
|
+
end
|
36
|
+
|
37
|
+
def add(key, flags, exptime, bytes, data)
|
38
|
+
self.check_exptime(key)
|
39
|
+
|
40
|
+
return Responses.not_stored if @storage.key?(key)
|
41
|
+
new_item = Item.new(key, data, flags, exptime, bytes, 0)
|
42
|
+
@storage.store(key, new_item)
|
43
|
+
return Responses.stored
|
44
|
+
end
|
45
|
+
|
46
|
+
def replace(key, flags, exptime, bytes, data)
|
47
|
+
self.check_exptime(key)
|
48
|
+
|
49
|
+
return Responses.not_stored unless @storage.key?(key)
|
50
|
+
cas_id = @storage[key].cas_id + 1
|
51
|
+
new_item = Item.new(key, data, flags, exptime, bytes, cas_id)
|
52
|
+
@storage.store(key, new_item)
|
53
|
+
return Responses.stored
|
54
|
+
end
|
55
|
+
|
56
|
+
def append(key, bytes, data)
|
57
|
+
self.check_exptime(key)
|
58
|
+
|
59
|
+
return Responses.not_stored unless @storage.key?(key)
|
60
|
+
@storage[key].data.concat(data)
|
61
|
+
@storage[key].bytes += bytes
|
62
|
+
@storage[key].cas_id += 1
|
63
|
+
return Responses.stored
|
64
|
+
end
|
65
|
+
|
66
|
+
def prepend(key, bytes, data)
|
67
|
+
self.check_exptime(key)
|
68
|
+
|
69
|
+
return Responses.not_stored unless @storage.key?(key)
|
70
|
+
@storage[key].data.prepend(data)
|
71
|
+
@storage[key].bytes += bytes
|
72
|
+
@storage[key].cas_id += 1
|
73
|
+
return Responses.stored
|
74
|
+
end
|
75
|
+
|
76
|
+
def cas(key, flags, exptime, bytes, cas_id, data)
|
77
|
+
self.check_exptime(key)
|
78
|
+
|
79
|
+
return Responses.not_found unless @storage.key?(key)
|
80
|
+
|
81
|
+
old_item = @storage[key]
|
82
|
+
old_item.lock.synchronize do
|
83
|
+
return Responses.exists if old_item.cas_id != cas_id
|
84
|
+
|
85
|
+
new_item = Item.new(key, data, flags, exptime, bytes, old_item.cas_id + 1)
|
86
|
+
@storage.store(key, new_item)
|
87
|
+
return Responses.stored
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def delete(key)
|
92
|
+
return Responses.not_found unless @storage.key?(key)
|
93
|
+
@storage.delete(key)
|
94
|
+
return Responses.deleted
|
95
|
+
end
|
96
|
+
|
97
|
+
def check_exptime(key)
|
98
|
+
value = @storage[key]
|
99
|
+
return true if value.nil?() || value.exptime.nil?()
|
100
|
+
|
101
|
+
current_time = Time.now().getutc()
|
102
|
+
|
103
|
+
if (current_time > value.exptime)
|
104
|
+
@storage.delete(key)
|
105
|
+
return false
|
106
|
+
end
|
107
|
+
|
108
|
+
return true
|
109
|
+
end
|
110
|
+
|
111
|
+
def check_exptimes()
|
112
|
+
deleted = 0
|
113
|
+
@storage.each_key do | key |
|
114
|
+
delete += 1 unless self.check_exptime(key)
|
115
|
+
end
|
116
|
+
return deleted
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
require_relative './Item.rb'
|
@@ -0,0 +1,194 @@
|
|
1
|
+
require 'socket'
|
2
|
+
|
3
|
+
require_relative './/Memcached.rb'
|
4
|
+
require_relative './Constants.rb'
|
5
|
+
|
6
|
+
module RubyMemcached
|
7
|
+
class Server
|
8
|
+
|
9
|
+
attr_reader :host
|
10
|
+
attr_reader :port
|
11
|
+
attr_accessor :storage
|
12
|
+
|
13
|
+
def initialize(host, port)
|
14
|
+
@host = host
|
15
|
+
@port = port
|
16
|
+
@connection = TCPServer.new(host, port)
|
17
|
+
@memc = Memcached.new()
|
18
|
+
end
|
19
|
+
|
20
|
+
def start
|
21
|
+
loop do
|
22
|
+
Thread.start(@connection.accept()) do | client |
|
23
|
+
|
24
|
+
puts('Opening connection to %s' % client.to_s)
|
25
|
+
|
26
|
+
continue_condition = true
|
27
|
+
|
28
|
+
while command = client.gets()
|
29
|
+
printf('%s: %s' % [client.to_s(), command])
|
30
|
+
begin
|
31
|
+
continue_condition = parse(command, client) unless command.nil?
|
32
|
+
rescue => e
|
33
|
+
client.puts(Errors.server_error % e.message)
|
34
|
+
puts(Errors.server_error % e.message)
|
35
|
+
end
|
36
|
+
break unless continue_condition
|
37
|
+
end
|
38
|
+
|
39
|
+
client.close()
|
40
|
+
puts('Closing connection to %s' % [client.to_s()])
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def parse(command, client)
|
46
|
+
case command
|
47
|
+
when CommandsRegex.get
|
48
|
+
self.get(client, $~)
|
49
|
+
|
50
|
+
when CommandsRegex.gets
|
51
|
+
self.gets(client, $~)
|
52
|
+
|
53
|
+
when CommandsRegex.set
|
54
|
+
self.set(client, $~)
|
55
|
+
|
56
|
+
when CommandsRegex.add
|
57
|
+
self.add(client, $~)
|
58
|
+
|
59
|
+
when CommandsRegex.replace
|
60
|
+
self.replace(client, $~)
|
61
|
+
|
62
|
+
when CommandsRegex.append
|
63
|
+
self.append(client, $~)
|
64
|
+
|
65
|
+
when CommandsRegex.prepend
|
66
|
+
self.prepend(client, $~)
|
67
|
+
|
68
|
+
when CommandsRegex.cas
|
69
|
+
self.cas(client, $~)
|
70
|
+
|
71
|
+
when CommandsRegex.delete
|
72
|
+
self.delete(client, $~)
|
73
|
+
|
74
|
+
when CommandsRegex.end
|
75
|
+
return false;
|
76
|
+
else
|
77
|
+
client.puts(Errors.client_error % [": Invalid command"])
|
78
|
+
end
|
79
|
+
|
80
|
+
return true
|
81
|
+
end
|
82
|
+
|
83
|
+
def get_data(client, bytes)
|
84
|
+
return client.read(bytes + 1).chomp()
|
85
|
+
end
|
86
|
+
|
87
|
+
def get(client, command)
|
88
|
+
keys = command['keys'].split(' ')
|
89
|
+
items = @memc.get_multi(keys)
|
90
|
+
|
91
|
+
for item in items
|
92
|
+
client.puts(Responses.get % [item.key, item.flags, item.bytes, item.data]) unless item.nil?()
|
93
|
+
end
|
94
|
+
client.puts(Responses.end)
|
95
|
+
end
|
96
|
+
|
97
|
+
def gets(client, command)
|
98
|
+
keys = command['keys'].split(' ')
|
99
|
+
items = @memc.get_multi(keys)
|
100
|
+
|
101
|
+
for item in items
|
102
|
+
client.puts(Responses.gets % [item.key, item.flags, item.bytes, item.cas_id, item.data]) unless item.nil?()
|
103
|
+
end
|
104
|
+
client.puts(Responses.end)
|
105
|
+
end
|
106
|
+
|
107
|
+
def set(client, command)
|
108
|
+
key = command['key']
|
109
|
+
flags = command['flags']
|
110
|
+
exptime = command['exptime']
|
111
|
+
bytes = command['bytes'].to_i()
|
112
|
+
data = self.get_data(client, bytes)
|
113
|
+
noreply = !command['noreply'].nil?
|
114
|
+
|
115
|
+
response = @memc.set(key, flags, exptime, bytes, data)
|
116
|
+
client.puts(response) unless noreply
|
117
|
+
end
|
118
|
+
|
119
|
+
def add(client, command)
|
120
|
+
key = command['key']
|
121
|
+
flags = command['flags']
|
122
|
+
exptime = command['exptime']
|
123
|
+
bytes = command['bytes'].to_i()
|
124
|
+
data = self.get_data(client, bytes)
|
125
|
+
noreply = !command['noreply'].nil?
|
126
|
+
|
127
|
+
response = @memc.add(key, flags, exptime, bytes, data)
|
128
|
+
client.puts(response) unless noreply
|
129
|
+
end
|
130
|
+
|
131
|
+
def replace(client, command)
|
132
|
+
key = command['key']
|
133
|
+
flags = command['flags']
|
134
|
+
exptime = command['exptime']
|
135
|
+
bytes = command['bytes'].to_i()
|
136
|
+
data = self.get_data(client, bytes)
|
137
|
+
noreply = !command['noreply'].nil?
|
138
|
+
|
139
|
+
response = @memc.replace(key, flags, exptime, bytes, data)
|
140
|
+
client.puts(response) unless noreply
|
141
|
+
end
|
142
|
+
|
143
|
+
def append(client, command)
|
144
|
+
key = command['key']
|
145
|
+
bytes = command['bytes'].to_i()
|
146
|
+
data = self.get_data(client, bytes)
|
147
|
+
noreply = !command['noreply'].nil?
|
148
|
+
|
149
|
+
response = @memc.append(key, bytes, data)
|
150
|
+
client.puts(response) unless noreply
|
151
|
+
end
|
152
|
+
|
153
|
+
def prepend(client, command)
|
154
|
+
key = command['key']
|
155
|
+
bytes = command['bytes'].to_i()
|
156
|
+
data = self.get_data(client, bytes)
|
157
|
+
noreply = !command['noreply'].nil?
|
158
|
+
|
159
|
+
response = @memc.prepend(key, bytes, data)
|
160
|
+
client.puts(response) unless noreply
|
161
|
+
|
162
|
+
end
|
163
|
+
|
164
|
+
def cas(client, command)
|
165
|
+
key = command['key']
|
166
|
+
flags = command['flags']
|
167
|
+
exptime = command['exptime']
|
168
|
+
bytes = command['bytes'].to_i()
|
169
|
+
data = self.get_data(client, bytes)
|
170
|
+
cas_id = command['cas_id'].to_i()
|
171
|
+
noreply = !command['noreply'].nil?
|
172
|
+
|
173
|
+
response = @memc.cas(key, flags, exptime, bytes, cas_id, data)
|
174
|
+
client.puts(response) unless noreply
|
175
|
+
end
|
176
|
+
|
177
|
+
def delete(client, command)
|
178
|
+
key = command['key']
|
179
|
+
noreply = !command['noreply'].nil?
|
180
|
+
|
181
|
+
response = @memc.delete(key)
|
182
|
+
client.puts(response) unless noreply
|
183
|
+
end
|
184
|
+
|
185
|
+
def start_gc(interval, loops = nil)
|
186
|
+
|
187
|
+
while loops.nil?() || loops > 0
|
188
|
+
sleep(interval)
|
189
|
+
puts('Garbage collector deleted: %d' % @memc.check_exptimes())
|
190
|
+
loops -= 1 unless loops.nil?()
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'ruby-enum'
|
2
|
+
|
3
|
+
module RubyMemcached
|
4
|
+
class Commands
|
5
|
+
include Ruby::Enum
|
6
|
+
|
7
|
+
define :get, "get %s\n"
|
8
|
+
define :gets, "gets %s\n"
|
9
|
+
|
10
|
+
define :set, "set %s %d %d %d%s\n%s\n"
|
11
|
+
define :add, "add %s %d %d %d%s\n%s\n"
|
12
|
+
define :replace, "replace %s %d %d %d%s\n%s\n"
|
13
|
+
|
14
|
+
define :append, "append %s %d%s\n%s\n"
|
15
|
+
define :_prepend, "prepend %s %d%s\n%s\n"
|
16
|
+
|
17
|
+
define :cas, "cas %s %d %d %d %d%s\n%s\n"
|
18
|
+
|
19
|
+
define :delete, "delete %s%s\n"
|
20
|
+
|
21
|
+
define :incr, "incr %s %d%s\n%d\n"
|
22
|
+
define :decr, "decr %s %d%s\n%d\n"
|
23
|
+
|
24
|
+
define :end, "END\n"
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'ruby-enum'
|
2
|
+
|
3
|
+
module RubyMemcached
|
4
|
+
class CommandsRegex
|
5
|
+
include Ruby::Enum
|
6
|
+
|
7
|
+
define :get, /^get (?<keys>(\w|[ ])+)\n/
|
8
|
+
define :gets, /^gets (?<keys>(\w|[ ])+)\n/
|
9
|
+
|
10
|
+
define :set, /^set (?<key>(\w)+) (?<flags>[0-9]+) (?<exptime>[0-9]+) (?<bytes>[0-9]+)(?<noreply> noreply)?\n/
|
11
|
+
define :add, /^add (?<key>(\w)+) (?<flags>[0-9]+) (?<exptime>[0-9]+) (?<bytes>[0-9]+)(?<noreply> noreply)?\n/
|
12
|
+
define :replace, /^replace (?<key>(\w)+) (?<flags>[0-9]+) (?<exptime>[0-9]+) (?<bytes>[0-9]+)(?<noreply> noreply)?\n/
|
13
|
+
|
14
|
+
define :append, /^append (?<key>(\w)+) (?<bytes>[0-9]+)(?<noreply> noreply)?\n/
|
15
|
+
define :prepend, /^prepend (?<key>(\w)+) (?<bytes>[0-9]+)(?<noreply> noreply)?\n/
|
16
|
+
|
17
|
+
define :cas, /^cas (?<key>(\w)+) (?<flags>[0-9]+) (?<exptime>[0-9]+) (?<bytes>[0-9]+) (?<cas_id>[0-9]+)(?<noreply> noreply)?\n/
|
18
|
+
|
19
|
+
define :delete, /^delete (?<key>(\w)+)(?<noreply> noreply)?\n/
|
20
|
+
|
21
|
+
define :incr, /^incr (?<key>(\w)+) (?<value>[0-9]+)(?<noreply> noreply)?\n/
|
22
|
+
define :decr, /^decr (?<key>(\w)+) (?<value>[0-9]+)(?<noreply> noreply)?\n/
|
23
|
+
|
24
|
+
define :end, /END\n/
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'ruby-enum'
|
2
|
+
|
3
|
+
module RubyMemcached
|
4
|
+
class Responses
|
5
|
+
include Ruby::Enum
|
6
|
+
|
7
|
+
define :stored, "STORED\n"
|
8
|
+
define :not_stored, "NOT_STORED\n"
|
9
|
+
define :exists, "EXISTS\n"
|
10
|
+
define :not_found, "NOT_FOUND\n"
|
11
|
+
define :deleted, "DELETED\n"
|
12
|
+
|
13
|
+
define :get, "VALUE %s %d %d\n%s\n"
|
14
|
+
define :gets, "VALUE %s %d %d %d\n%s\n"
|
15
|
+
|
16
|
+
define :end, "END\n"
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'ruby-enum'
|
2
|
+
|
3
|
+
module RubyMemcached
|
4
|
+
class ResponsesRegex
|
5
|
+
include Ruby::Enum
|
6
|
+
|
7
|
+
define :get, /VALUE (?<key>(\w)+) (?<flags>[0-9]+) (?<bytes>[0-9]+)/
|
8
|
+
define :gets, /VALUE (?<key>(\w)+) (?<flags>[0-9]+) (?<bytes>[0-9]+) (?<cas_id>[0-9]+)/
|
9
|
+
|
10
|
+
define :end, /END/
|
11
|
+
end
|
12
|
+
end
|
metadata
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ruby-memcached
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Francisco Bongiovanni
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-12-05 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: ruby-enum
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.7.2
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.7.2
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: concurrent-ruby
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.1'
|
34
|
+
- - ">="
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: 1.1.5
|
37
|
+
type: :runtime
|
38
|
+
prerelease: false
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - "~>"
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '1.1'
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 1.1.5
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rake
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '12.3'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '12.3'
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: minitest
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '5.11'
|
68
|
+
type: :development
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - "~>"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '5.11'
|
75
|
+
description: A simple memcached implementation for Moove-It code challenge
|
76
|
+
email: Frantss.Bongiovanni@gmail.com
|
77
|
+
executables:
|
78
|
+
- memcached-client.rb
|
79
|
+
- memcached-server.rb
|
80
|
+
extensions: []
|
81
|
+
extra_rdoc_files: []
|
82
|
+
files:
|
83
|
+
- bin/memcached-client.rb
|
84
|
+
- bin/memcached-server.rb
|
85
|
+
- lib/ruby-memcached.rb
|
86
|
+
- lib/ruby-memcached/Client.rb
|
87
|
+
- lib/ruby-memcached/Constants.rb
|
88
|
+
- lib/ruby-memcached/Item.rb
|
89
|
+
- lib/ruby-memcached/Memcached.rb
|
90
|
+
- lib/ruby-memcached/Server.rb
|
91
|
+
- lib/ruby-memcached/constants/Commands.rb
|
92
|
+
- lib/ruby-memcached/constants/CommandsRegex.rb
|
93
|
+
- lib/ruby-memcached/constants/Errors.rb
|
94
|
+
- lib/ruby-memcached/constants/Responses.rb
|
95
|
+
- lib/ruby-memcached/constants/ResponsesRegex.rb
|
96
|
+
homepage: https://rubygems.org/gems/ruby-memcached
|
97
|
+
licenses:
|
98
|
+
- MIT
|
99
|
+
metadata:
|
100
|
+
github_uri: https://github.com/Frantss/memcached-ruby
|
101
|
+
post_install_message:
|
102
|
+
rdoc_options: []
|
103
|
+
require_paths:
|
104
|
+
- lib
|
105
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
111
|
+
requirements:
|
112
|
+
- - ">="
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: '0'
|
115
|
+
requirements: []
|
116
|
+
rubygems_version: 3.0.3
|
117
|
+
signing_key:
|
118
|
+
specification_version: 4
|
119
|
+
summary: Simple ruby memcached implementation
|
120
|
+
test_files: []
|