This commit is contained in:
Evan Weaver 2008-01-20 04:18:31 +00:00
Родитель bf0db55df8
Коммит 8698a40372
6 изменённых файлов: 109 добавлений и 29 удалений

Просмотреть файл

@ -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