зеркало из https://github.com/github/memcached.git
workaround multiget impl
This commit is contained in:
Родитель
bf0db55df8
Коммит
8698a40372
|
@ -2,4 +2,5 @@
|
|||
require 'libmemcached'
|
||||
require 'memcached/integer'
|
||||
require 'memcached/exceptions'
|
||||
require 'memcached/behaviors'
|
||||
require 'memcached/memcached'
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
|
||||
class Memcached
|
||||
|
||||
def self.load_constants(prefix, hash = {})
|
||||
Libmemcached.constants.grep(/^#{prefix}/).each do |const_name|
|
||||
hash[const_name[prefix.length..-1].downcase.to_sym] = Libmemcached.const_get(const_name)
|
||||
end
|
||||
hash
|
||||
end
|
||||
|
||||
BEHAVIORS = load_constants("MEMCACHED_BEHAVIOR_")
|
||||
|
||||
BEHAVIOR_VALUES = {
|
||||
false => 0,
|
||||
true => 1
|
||||
}
|
||||
|
||||
HASH_VALUES = {}
|
||||
BEHAVIOR_VALUES.merge(load_constants("MEMCACHED_HASH_", HASH_VALUES))
|
||||
|
||||
DISTRIBUTION_VALUES = {}
|
||||
BEHAVIOR_VALUES.merge(load_constants("MEMCACHED_DISTRIBUTION_", DISTRIBUTION_VALUES))
|
||||
|
||||
private
|
||||
|
||||
def set_behavior(behavior, value)
|
||||
raise ArgumentError, "No setting #{behavior.inspect}" unless b_id = BEHAVIORS[behavior]
|
||||
raise ArgumentError, "No setting value #{value.inspect}" unless v_id = BEHAVIOR_VALUES[value]
|
||||
|
||||
# Scoped validations
|
||||
msg = "Invalid setting value #{value.inspect} for #{behavior.inspect}"
|
||||
if behavior == :hash
|
||||
raise ArgumentError, msg unless HASH_VALUES[value]
|
||||
elsif behavior == :distribution
|
||||
raise ArgumentError, msg unless DISTRIBUTION_VALUES[value]
|
||||
end
|
||||
|
||||
Libmemcached.memcached_behavior_set(@struct, b_id, v_id)
|
||||
end
|
||||
|
||||
end
|
|
@ -16,12 +16,15 @@ class Memcached
|
|||
|
||||
@@exceptions = []
|
||||
@@empty_struct = Libmemcached::MemcachedSt.new
|
||||
# Libmemcached.memcached_create(@@empty_struct)
|
||||
Libmemcached.memcached_create(@@empty_struct)
|
||||
|
||||
# Generate exception classes
|
||||
Libmemcached::MEMCACHED_MAXIMUM_RETURN.times do |exception_index|
|
||||
description = Libmemcached.memcached_strerror(@@empty_struct, exception_index)
|
||||
exception_class = eval("class #{camelize(description)} < Error; self; end")
|
||||
@@exceptions << exception_class
|
||||
end
|
||||
|
||||
# Verify library version
|
||||
# XXX Impossible with current libmemcached
|
||||
end
|
||||
|
|
|
@ -3,6 +3,15 @@ class Memcached
|
|||
|
||||
FLAGS = 0x0
|
||||
|
||||
DEFAULTS = {
|
||||
:hash => :default,
|
||||
:distribution => :consistent,
|
||||
:buffer_requests => false,
|
||||
:support_cas => false,
|
||||
:tcp_nodelay => false,
|
||||
:no_block => false
|
||||
}
|
||||
|
||||
attr_reader :namespace
|
||||
|
||||
### Configuration
|
||||
|
@ -11,6 +20,7 @@ class Memcached
|
|||
@struct = Libmemcached::MemcachedSt.new
|
||||
Libmemcached.memcached_create(@struct)
|
||||
|
||||
# Servers
|
||||
Array(servers).each do |server|
|
||||
unless server.is_a? String and server =~ /^(\d{1,3}\.){3}\d{1,3}:\d{1,5}$/
|
||||
raise ArgumentError, "Servers must be in the format ip:port (e.g., '127.0.0.1:11211')"
|
||||
|
@ -23,6 +33,12 @@ class Memcached
|
|||
Libmemcached.memcached_select_server_at(@struct, @struct.hosts.count - 1)
|
||||
)
|
||||
end
|
||||
|
||||
# Behaviors
|
||||
(DEFAULTS.merge(opts)).each do |option, value|
|
||||
|
||||
end
|
||||
|
||||
@namespace = opts[:namespace]
|
||||
end
|
||||
|
||||
|
@ -33,14 +49,7 @@ class Memcached
|
|||
end
|
||||
servers
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_behavior(behavior, flag)
|
||||
flag = flag ? 1 : 0
|
||||
Libmemcached.memcached_behavior_set(@struct, behavior, flag)
|
||||
end
|
||||
|
||||
|
||||
### Operations
|
||||
|
||||
public
|
||||
|
@ -48,40 +57,56 @@ class Memcached
|
|||
def set(key, value, timeout=0, marshal=true)
|
||||
value = marshal ? Marshal.dump(value) : value.to_s
|
||||
check_return_code(
|
||||
Libmemcached.memcached_set(@struct, key, value, timeout, FLAGS)
|
||||
Libmemcached.memcached_set(@struct, ns(key), value, timeout, FLAGS)
|
||||
)
|
||||
end
|
||||
|
||||
def get(key, marshal=true)
|
||||
raise ClientError, "Invalid key" if key =~ /\s/ # XXX Server doesn't validate. Possibly a performance problem.
|
||||
value, flags, return_code = Libmemcached.memcached_get_ruby_string(@struct, key)
|
||||
check_return_code(return_code)
|
||||
value = Marshal.load(value) if marshal
|
||||
value
|
||||
end
|
||||
if key.is_a? Array
|
||||
# Multi get
|
||||
# XXX Waiting on the real implementation
|
||||
key.map do |this_key|
|
||||
begin
|
||||
get(this_key, marshal)
|
||||
rescue NotFound
|
||||
# XXX Not sure how this behavior should be defined
|
||||
end
|
||||
end
|
||||
else
|
||||
# Single get
|
||||
# XXX Server doesn't validate. Possibly a performance problem.
|
||||
raise ClientError, "Invalid key" if !key.is_a? String or key =~ /\s/
|
||||
|
||||
value, flags, return_code = Libmemcached.memcached_get_ruby_string(@struct, ns(key))
|
||||
check_return_code(return_code)
|
||||
value = Marshal.load(value) if marshal
|
||||
value
|
||||
end
|
||||
end
|
||||
|
||||
public
|
||||
|
||||
def delete(key, timeout=0)
|
||||
check_return_code(
|
||||
Libmemcached.memcached_delete(@struct, key, timeout)
|
||||
Libmemcached.memcached_delete(@struct, ns(key), timeout)
|
||||
)
|
||||
end
|
||||
|
||||
def add(key, value, timeout=0, marshal=true)
|
||||
value = marshal ? Marshal.dump(value) : value.to_s
|
||||
check_return_code(
|
||||
Libmemcached.memcached_add(@struct, key, value, timeout, FLAGS)
|
||||
Libmemcached.memcached_add(@struct, ns(key), value, timeout, FLAGS)
|
||||
)
|
||||
end
|
||||
|
||||
def increment(key, offset=1)
|
||||
Libmemcached.memcached_increment(@struct, key, offset)
|
||||
return_code, value = Libmemcached.memcached_increment(@struct, key, offset)
|
||||
return_code, value = Libmemcached.memcached_increment(@struct, ns(key), offset)
|
||||
check_return_code(return_code)
|
||||
value
|
||||
end
|
||||
|
||||
def decrement(key, offset=1)
|
||||
return_code, value = Libmemcached.memcached_decrement(@struct, key, offset)
|
||||
return_code, value = Libmemcached.memcached_decrement(@struct, ns(key), offset)
|
||||
check_return_code(return_code)
|
||||
value
|
||||
end
|
||||
|
@ -112,7 +137,11 @@ class Memcached
|
|||
### Operations helpers
|
||||
|
||||
private
|
||||
|
||||
|
||||
def ns(key)
|
||||
"#{@namespace}#{key}"
|
||||
end
|
||||
|
||||
def check_return_code(int)
|
||||
return true if int == 0
|
||||
raise @@exceptions[int]
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
|
||||
$LOAD_PATH << "#{File.dirname(__FILE__)}/../lib"
|
||||
require 'memcached'
|
||||
|
||||
require 'rubygems'
|
||||
if ENV['DEBUG']
|
||||
require 'rubygems'
|
||||
require 'ruby-debug'
|
||||
end
|
||||
|
||||
require 'memcached'
|
||||
require 'test/unit'
|
||||
require 'ostruct'
|
||||
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
|
||||
require "#{File.dirname(__FILE__)}/../test_helper"
|
||||
|
||||
require 'ruby-debug' if ENV['DEBUG']
|
||||
|
||||
class ClassTest < Test::Unit::TestCase
|
||||
|
||||
def setup
|
||||
|
@ -10,7 +8,6 @@ class ClassTest < Test::Unit::TestCase
|
|||
['127.0.0.1:43042', '127.0.0.1:43043'],
|
||||
:namespace => 'test'
|
||||
)
|
||||
# @cache.set_behavior(Libmemcached::MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 1)
|
||||
@value = OpenStruct.new(:a => 1, :b => 2, :c => GenericClass)
|
||||
@marshalled_value = Marshal.dump(@value)
|
||||
end
|
||||
|
@ -36,7 +33,12 @@ class ClassTest < Test::Unit::TestCase
|
|||
assert_equal 2, cache.servers.size
|
||||
end
|
||||
|
||||
def test_intialize_alternative_hashing_scheme
|
||||
def test_initialize_behavior
|
||||
cache = Memcached.new ['127.0.0.1:43042', '127.0.0.1:43043'],
|
||||
:buffer_requests => true
|
||||
assert_raise(Memcached::ActionQueued) do
|
||||
cache.set 'test_initialize_behavior', @value
|
||||
end
|
||||
end
|
||||
|
||||
def test_initialize_single_server
|
||||
|
@ -81,7 +83,7 @@ class ClassTest < Test::Unit::TestCase
|
|||
@cache.set 'test_get_multi_1', 1
|
||||
@cache.set 'test_get_multi_2', 2
|
||||
assert_equal [1, 2],
|
||||
@cache.get(['test_get_multi_1', 'test_get_multi_1'])
|
||||
@cache.get(['test_get_multi_1', 'test_get_multi_2'])
|
||||
end
|
||||
|
||||
def test_set_and_get_unmarshalled
|
||||
|
|
Загрузка…
Ссылка в новой задаче