moneta 0.7.18 → 0.7.19

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 40e5bf4f97796468cef521c2b103f72d7be29811
4
- data.tar.gz: d9ab4368e38146049f4e92a0cf2337b2148fcf10
3
+ metadata.gz: 54ab5446cbb72cf10100e2e72680c4624113aaa0
4
+ data.tar.gz: c3337a129506fdeab6624542b37ada15a9c16c20
5
5
  SHA512:
6
- metadata.gz: 2fadbaee29f91f2259b44cf7140d64e3ab12196ee2e29c6c9ccc5db2518b0a06a4db0d81f654e7625dceaa3ead6a7636aeb2240d9cff0bd17161b2f1865a6f19
7
- data.tar.gz: f1751faff2cef9302fa0b3125e421e6632fa580978ab548fb13afd53f7dc37fe0e586821a657b3c79298a44b9ba66ccf68edacbf6efcc89e3b134176dfa2b7c9
6
+ metadata.gz: dc94d4af7c904ad023cee82ee3ec408e9685273362a94a6cf620ba0d108ea69b660ea8a737bd91491faacd10c09d0e5b1942f429b19fb010df806980e9f1f88b
7
+ data.tar.gz: 50a2df5e71906df99c2954ed1efb8ca2986234db51f21565c53bbbbdf93e2b07f123d041c6c165a0b24e9876852cbc23d2b4877e94261cf0f8b4bda946da53c1
data/.travis.yml CHANGED
@@ -24,31 +24,31 @@ env:
24
24
  global:
25
25
  - secure: "dtM4n7FP8P0UI9Iq+nsvQ7/yfDqsxhfCO9i8zMxm/f9Kxj5Z/4C7jsXsLA+e\n/7FZ9+ld2QjPSPU0LUiDpj/z81bxyZHwqocQ7Nb0DVvO3JRHpr4/iBQQQHd3\n0jvou3mRbu5mBlUjf1/ALaZA+b+vcnsF9fd86UnkY+ChriylGnM="
26
26
  matrix:
27
- - "TASK=test TEST_GROUP=1/10"
28
- - "TASK=test TEST_GROUP=2/10"
29
- - "TASK=test TEST_GROUP=3/10"
30
- - "TASK=test TEST_GROUP=4/10"
31
- - "TASK=test TEST_GROUP=5/10"
32
- - "TASK=test TEST_GROUP=6/10"
33
- - "TASK=test TEST_GROUP=7/10"
34
- - "TASK=test TEST_GROUP=8/10"
35
- - "TASK=test TEST_GROUP=9/10"
36
- - "TASK=test TEST_GROUP=10/10"
37
- - "TASK=test TEST_GROUP=unstable"
38
- - "TASK=benchmarks CONFIG=uniform_small"
39
- - "TASK=benchmarks CONFIG=uniform_medium"
40
- - "TASK=benchmarks CONFIG=uniform_large"
41
- - "TASK=benchmarks CONFIG=normal_small"
42
- - "TASK=benchmarks CONFIG=normal_medium"
43
- - "TASK=benchmarks CONFIG=normal_large"
27
+ - "SCRIPT='parallel-tests 1/10'"
28
+ - "SCRIPT='parallel-tests 2/10'"
29
+ - "SCRIPT='parallel-tests 3/10'"
30
+ - "SCRIPT='parallel-tests 4/10'"
31
+ - "SCRIPT='parallel-tests 5/10'"
32
+ - "SCRIPT='parallel-tests 6/10'"
33
+ - "SCRIPT='parallel-tests 7/10'"
34
+ - "SCRIPT='parallel-tests 8/10'"
35
+ - "SCRIPT='parallel-tests 9/10'"
36
+ - "SCRIPT='parallel-tests 10/10'"
37
+ - "SCRIPT='parallel-tests unstable'"
38
+ - "SCRIPT='benchmarks uniform_small'"
39
+ - "SCRIPT='benchmarks uniform_medium'"
40
+ - "SCRIPT='benchmarks uniform_large'"
41
+ - "SCRIPT='benchmarks normal_small'"
42
+ - "SCRIPT='benchmarks normal_medium'"
43
+ - "SCRIPT='benchmarks normal_large'"
44
44
  matrix:
45
45
  allow_failures:
46
46
  - rvm: jruby-18mode
47
47
  - rvm: jruby-19mode
48
48
  - rvm: rbx-18mode
49
49
  - rvm: rbx-19mode
50
- - env: "TASK=test TEST_GROUP=unstable"
51
- script: "bundle exec rake $TASK"
50
+ - env: "SCRIPT='parallel-tests unstable'"
51
+ script: "eval bundle exec ruby script/$SCRIPT"
52
52
  branches:
53
53
  only:
54
54
  - master
data/CHANGES CHANGED
@@ -1,3 +1,9 @@
1
+ 0.7.19
2
+
3
+ * ActionDispatch::Session::MonetaStore fixed for Rails 4
4
+ * Moneta::Server: Tries now to remove stale unix socket
5
+ * Moneta::Server: More robust and better performance
6
+
1
7
  0.7.18
2
8
 
3
9
  * Adapters::File#increment and #create fixed on JRuby
data/CONTRIBUTORS CHANGED
@@ -16,6 +16,7 @@ lakshan <lakshan@web2media.net>
16
16
  Piotr Murach <pmurach@gmail.com>
17
17
  Potapov Sergey <blake131313@gmail.com>
18
18
  Quin Hoxie <quin@aboutus.org>
19
+ Ryan T. Hosford <tad.hosford@gmail.com>
19
20
  Scott Wadden <scott.wadden@gmail.com>
20
21
  Tom Meier <ozmeier@yahoo.co.uk>
21
22
  Xavier Shay <xavier@rhnh.net>
data/Gemfile CHANGED
@@ -1,8 +1,14 @@
1
+ # Rails 4 requires Ruby >= 1.9
2
+ def rails_version
3
+ v = ['>= 3.2.11']
4
+ v << '< 4.0.0' unless RUBY_VERSION >= '1.9'
5
+ v
6
+ end
7
+
1
8
  source 'https://rubygems.org'
2
9
  gemspec
3
10
 
4
11
  # Testing
5
- gem 'rake'
6
12
  gem 'rspec'
7
13
  gem 'rspec-retry'
8
14
 
@@ -38,7 +44,7 @@ gem 'dm-migrations'
38
44
  gem 'dm-mysql-adapter'
39
45
  # FIXME: Use fog master because of failing tests, fixed after 1.11.1
40
46
  gem 'fog', :github => 'fog/fog'
41
- gem 'activerecord', '>= 3.2.11'
47
+ gem 'activerecord', *rails_version
42
48
  gem 'redis'
43
49
  gem 'mongo'
44
50
  gem 'sequel'
@@ -74,5 +80,5 @@ gem 'rack'
74
80
  gem 'rack-cache'
75
81
 
76
82
  # Rails integration testing
77
- gem 'actionpack', '>= 3.2.11'
83
+ gem 'actionpack', *rails_version
78
84
  gem 'minitest', '~> 4.7.4'
data/SPEC.md CHANGED
@@ -65,7 +65,7 @@ Closes the store
65
65
 
66
66
  ### <code>features => Array&lt;Symbol&gt;</code> and <code>supports?(Symbol) => [TrueClass, FalseClass]</code>
67
67
 
68
- Feature detection. Adapters MUST return <code>:create</code> and <code>:increment</code> if these methods are supported.
68
+ Feature detection. Adapters MUST return <code>:create</code> and <code>:increment</code> if these methods are supported.
69
69
 
70
70
  ## Additional Options Hashes
71
71
 
@@ -6,6 +6,7 @@ module ActionDispatch
6
6
  class MonetaStore < Rack::Session::Moneta
7
7
  include Compatibility
8
8
  include StaleSessionCheck
9
+ include SessionObject if defined?(SessionObject)
9
10
  end
10
11
  end
11
12
  end
data/lib/moneta.rb CHANGED
@@ -10,7 +10,6 @@ module Moneta
10
10
  autoload :Lock, 'moneta/lock'
11
11
  autoload :Logger, 'moneta/logger'
12
12
  autoload :Mutex, 'moneta/synchronize'
13
- autoload :Net, 'moneta/mixins'
14
13
  autoload :OptionMerger, 'moneta/optionmerger'
15
14
  autoload :OptionSupport, 'moneta/mixins'
16
15
  autoload :Pool, 'moneta/pool'
@@ -5,7 +5,6 @@ module Moneta
5
5
  # Moneta client backend
6
6
  # @api public
7
7
  class Client
8
- include Net
9
8
  include Defaults
10
9
 
11
10
  # @param [Hash] options
@@ -14,50 +13,50 @@ module Moneta
14
13
  # @option options [String] :socket Unix socket file name as alternative to `:port` and `:host`
15
14
  def initialize(options = {})
16
15
  @socket = options[:socket] ? UNIXSocket.open(options[:socket]) :
17
- TCPSocket.open(options[:host] || '127.0.0.1', options[:port] || DEFAULT_PORT)
16
+ TCPSocket.open(options[:host] || '127.0.0.1', options[:port] || 9000)
18
17
  end
19
18
 
20
19
  # (see Proxy#key?)
21
20
  def key?(key, options = {})
22
- write(@socket, [:key?, key, options])
23
- read_result
21
+ write(:key?, key, options)
22
+ read
24
23
  end
25
24
 
26
25
  # (see Proxy#load)
27
26
  def load(key, options = {})
28
- write(@socket, [:load, key, options])
29
- read_result
27
+ write(:load, key, options)
28
+ read
30
29
  end
31
30
 
32
31
  # (see Proxy#store)
33
32
  def store(key, value, options = {})
34
- write(@socket, [:store, key, value, options])
35
- read_result
33
+ write(:store, key, value, options)
34
+ read
36
35
  value
37
36
  end
38
37
 
39
38
  # (see Proxy#delete)
40
39
  def delete(key, options = {})
41
- write(@socket, [:delete, key, options])
42
- read_result
40
+ write(:delete, key, options)
41
+ read
43
42
  end
44
43
 
45
44
  # (see Proxy#increment)
46
45
  def increment(key, amount = 1, options = {})
47
- write(@socket, [:increment, key, amount, options])
48
- read_result
46
+ write(:increment, key, amount, options)
47
+ read
49
48
  end
50
49
 
51
50
  # (see Proxy#create)
52
51
  def create(key, value, options = {})
53
- write(@socket, [:create, key, value, options])
54
- read_result
52
+ write(:create, key, value, options)
53
+ read
55
54
  end
56
55
 
57
56
  # (see Proxy#clear)
58
57
  def clear(options = {})
59
- write(@socket, [:clear, options])
60
- read_result
58
+ write(:clear, options)
59
+ read
61
60
  self
62
61
  end
63
62
 
@@ -71,16 +70,22 @@ module Moneta
71
70
  def features
72
71
  @features ||=
73
72
  begin
74
- write(@socket, [:features])
75
- read_result.freeze
73
+ write(:features)
74
+ read.freeze
76
75
  end
77
76
  end
78
77
 
79
78
  private
80
79
 
81
- def read_result
82
- result = read(@socket)
83
- raise result if Error === result
80
+ def write(*args)
81
+ s = Marshal.dump(args)
82
+ @socket.write([s.bytesize].pack('N') << s)
83
+ end
84
+
85
+ def read
86
+ size = @socket.read(4).unpack('N').first
87
+ result = Marshal.load(@socket.read(size))
88
+ raise result if Exception === result
84
89
  result
85
90
  end
86
91
  end
@@ -52,7 +52,7 @@ module Moneta
52
52
  def increment(key, amount = 1, options = {})
53
53
  # FIXME: There is a Dalli bug, load(key) returns a wrong value after increment
54
54
  # therefore we set default = nil and create the counter manually
55
- # See https://github.com/mperham/dalli/issues/309
55
+ # See https://github.com/mperham/dalli/issues/309
56
56
  result =
57
57
  if amount >= 0
58
58
  @backend.incr(key, amount, expires_value(options) || nil, nil)
@@ -64,7 +64,7 @@ module Moneta
64
64
  @backend.decrement(key, -amount)
65
65
  end
66
66
  # HACK: Throw error if applied to invalid value
67
- # see https://github.com/evan/memcached/issues/110
67
+ # see https://github.com/evan/memcached/issues/110
68
68
  Utils.to_int((@backend.get(key, false) rescue nil)) if result == 0
69
69
  result
70
70
  rescue ::Memcached::NotFound => ex
data/lib/moneta/mixins.rb CHANGED
@@ -284,27 +284,6 @@ module Moneta
284
284
  end
285
285
  end
286
286
 
287
- # @api private
288
- module Net
289
- DEFAULT_PORT = 9000
290
-
291
- class Error < RuntimeError; end
292
-
293
- def pack(o)
294
- s = Marshal.dump(o)
295
- [s.bytesize].pack('N') << s
296
- end
297
-
298
- def read(io)
299
- size = io.read(4).unpack('N').first
300
- Marshal.load(io.read(size))
301
- end
302
-
303
- def write(io, o)
304
- io.write(pack(o))
305
- end
306
- end
307
-
308
287
  # This mixin handles the calculation of expiration times.
309
288
  #
310
289
  #
data/lib/moneta/pool.rb CHANGED
@@ -27,7 +27,7 @@ module Moneta
27
27
 
28
28
  def close
29
29
  @mutex.synchronize do
30
- raise '#close can only when no thread is using the pool' if @all.size != @pool.size
30
+ raise '#close can only be called when no thread is using the pool' if @all.size != @pool.size
31
31
  @all.each(&:close)
32
32
  @all = @pool = nil
33
33
  end
data/lib/moneta/server.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  require 'socket'
2
2
 
3
3
  module Moneta
4
- # Moneta server
4
+ # Moneta server to be used together with Moneta::Adapters::Client
5
5
  # @api public
6
6
  class Server
7
7
  # @param [Hash] options
@@ -9,13 +9,9 @@ module Moneta
9
9
  # @option options [String] :socket Alternative Unix socket file name
10
10
  def initialize(store, options = {})
11
11
  @store = store
12
- @server =
13
- if @socket = options[:socket]
14
- UNIXServer.open(@socket)
15
- else
16
- TCPServer.open(options[:port] || DEFAULT_PORT)
17
- end
18
- @clients = [@server]
12
+ @server = start(options)
13
+ @ios = [@server]
14
+ @clients = {}
19
15
  @running = false
20
16
  end
21
17
 
@@ -52,54 +48,89 @@ module Moneta
52
48
 
53
49
  private
54
50
 
55
- include Net
56
51
  TIMEOUT = 1
52
+ MAXSIZE = 0x100000
57
53
 
58
54
  def mainloop
59
- client = accept
60
- handle(client) if client
55
+ if ios = IO.select(@ios, nil, @ios, TIMEOUT)
56
+ ios[2].each do |io|
57
+ io.close
58
+ delete_client(io)
59
+ end
60
+ ios[0].each do |io|
61
+ if io == @server
62
+ if client = @server.accept
63
+ @ios << client
64
+ @clients[client] = ''
65
+ end
66
+ elsif io.closed? || io.eof?
67
+ delete_client(io)
68
+ else
69
+ handle(io, @clients[io] << io.readpartial(0xFFFF))
70
+ end
71
+ end
72
+ end
61
73
  rescue SignalException => ex
62
74
  warn "Moneta::Server - #{ex.message}"
63
- raise if ex.signo == 15 # SIGTERM
64
- rescue IOError => ex
65
- warn "Moneta::Server - #{ex.message}" unless ex.message =~ /closed/
66
- @clients.delete(client) if client
67
- @clients.reject!(&:closed?)
75
+ raise if ex.signo == 15 || ex.signo == 2 # SIGTERM or SIGINT
68
76
  rescue Exception => ex
69
77
  warn "Moneta::Server - #{ex.message}"
70
- write(client, Error.new(ex.message)) if client
71
78
  end
72
79
 
73
- def accept
74
- ios = IO.select(@clients, nil, @clients, TIMEOUT)
75
- return nil unless ios
76
- ios[2].each do |io|
77
- io.close
78
- @clients.delete(io)
79
- end
80
- ios[0].each do |io|
81
- if io == @server
82
- client = @server.accept
83
- @clients << client if client
84
- else
85
- return io unless io.eof?
86
- @clients.delete(io)
87
- end
88
- end
89
- nil
80
+ def delete_client(io)
81
+ @ios.delete(io)
82
+ @clients.delete(io)
83
+ end
84
+
85
+ def pack(o)
86
+ s = Marshal.dump(o)
87
+ [s.bytesize].pack('N') << s
90
88
  end
91
89
 
92
- def handle(client)
93
- method, *args = read(client)
90
+ def handle(io, buffer)
91
+ buffer = @clients[io]
92
+ return if buffer.bytesize < 8 # At least 4 bytes for the marshalled array
93
+ size = buffer[0,4].unpack('N').first
94
+ if size > MAXSIZE
95
+ delete_client(io)
96
+ return
97
+ end
98
+ return if buffer.bytesize < 4 + size
99
+ buffer.slice!(0, 4)
100
+ method, *args = Marshal.load(buffer.slice!(0, size))
94
101
  case method
95
102
  when :key?, :load, :delete, :increment, :create, :features
96
- write(client, @store.send(method, *args))
103
+ io.write(pack @store.send(method, *args))
97
104
  when :store, :clear
98
105
  @store.send(method, *args)
99
- client.write(@nil ||= pack(nil))
106
+ io.write(@nil ||= pack(nil))
100
107
  else
101
108
  raise 'Invalid method call'
102
109
  end
110
+ rescue IOError => ex
111
+ warn "Moneta::Server - #{ex.message}" unless ex.message =~ /closed/
112
+ delete_client(io)
113
+ rescue Exception => ex
114
+ warn "Moneta::Server - #{ex.message}"
115
+ io.write(pack Exception.new(ex.message))
116
+ end
117
+
118
+ def start(options)
119
+ if @socket = options[:socket]
120
+ begin
121
+ UNIXServer.open(@socket)
122
+ rescue Errno::EADDRINUSE
123
+ if client = (UNIXSocket.open(@socket) rescue nil)
124
+ client.close
125
+ raise
126
+ end
127
+ File.unlink(@socket)
128
+ tries ||= 0
129
+ (tries += 1) < 3 ? retry : raise
130
+ end
131
+ else
132
+ TCPServer.open(options[:host] || '127.0.0.1', options[:port] || 9000)
133
+ end
103
134
  end
104
135
  end
105
136
  end