memcached-northscale 0.19.5.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/BENCHMARKS +120 -0
- data/CHANGELOG +79 -0
- data/LICENSE +184 -0
- data/Manifest +29 -0
- data/README +115 -0
- data/Rakefile +31 -0
- data/TODO +4 -0
- data/ext/extconf.rb +95 -0
- data/ext/libmemcached-0.32.tar.gz +0 -0
- data/ext/libmemcached.patch +270 -0
- data/ext/rlibmemcached.i +230 -0
- data/ext/rlibmemcached_wrap.c +13290 -0
- data/ext/sasl.patch +29283 -0
- data/lib/memcached.rb +32 -0
- data/lib/memcached/auth.rb +16 -0
- data/lib/memcached/behaviors.rb +78 -0
- data/lib/memcached/exceptions.rb +84 -0
- data/lib/memcached/integer.rb +6 -0
- data/lib/memcached/memcached.rb +656 -0
- data/lib/memcached/rails.rb +164 -0
- data/memcached-northscale.gemspec +32 -0
- data/test/profile/benchmark.rb +210 -0
- data/test/profile/profile.rb +14 -0
- data/test/profile/valgrind.rb +149 -0
- data/test/setup.rb +29 -0
- data/test/teardown.rb +0 -0
- data/test/test_helper.rb +18 -0
- data/test/unit/binding_test.rb +8 -0
- data/test/unit/memcached_test.rb +1168 -0
- data/test/unit/rails_test.rb +109 -0
- metadata +116 -0
data/Rakefile
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'echoe'
|
2
|
+
|
3
|
+
Echoe.new("memcached-northscale") do |p|
|
4
|
+
p.author = "Sean Lynch"
|
5
|
+
p.project = "northscale"
|
6
|
+
p.summary = "Test gem. Do not use unless you know what you're doing."
|
7
|
+
p.url = "http://blog.evanweaver.com/files/doc/fauna/memcached/"
|
8
|
+
p.docs_host = "blog.evanweaver.com:~/www/bax/public/files/doc/"
|
9
|
+
p.rdoc_pattern = /README|TODO|LICENSE|CHANGELOG|BENCH|COMPAT|exceptions|behaviors|rails.rb|memcached.rb/
|
10
|
+
p.clean_pattern += ["ext/lib", "ext/include", "ext/share", "ext/libmemcached-?.??", "ext/bin", "ext/conftest.dSYM"]
|
11
|
+
end
|
12
|
+
|
13
|
+
task :exceptions do
|
14
|
+
$LOAD_PATH << "lib"
|
15
|
+
require 'memcached'
|
16
|
+
Memcached.constants.sort.each do |const_name|
|
17
|
+
const = Memcached.send(:const_get, const_name)
|
18
|
+
next if const == Memcached::Success or const == Memcached::Stored
|
19
|
+
if const.is_a? Class and const < Memcached::Error
|
20
|
+
puts "* Memcached::#{const_name}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
task :valgrind do
|
26
|
+
exec("valgrind --tool=memcheck --leak-check=full --show-reachable=no --num-callers=15 --track-fds=yes --workaround-gcc296-bugs=yes --max-stackframe=7304328 --dsymutil=yes --track-origins=yes ruby #{File.dirname(__FILE__)}/test/profile/valgrind.rb")
|
27
|
+
end
|
28
|
+
|
29
|
+
task :profile do
|
30
|
+
exec("ruby #{File.dirname(__FILE__)}/test/profile/profile.rb")
|
31
|
+
end
|
data/TODO
ADDED
data/ext/extconf.rb
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'mkmf'
|
2
|
+
require 'rbconfig'
|
3
|
+
|
4
|
+
HERE = File.expand_path(File.dirname(__FILE__))
|
5
|
+
BUNDLE = Dir.glob("libmemcached-*.tar.gz").first
|
6
|
+
BUNDLE_PATH = BUNDLE.sub(".tar.gz", "")
|
7
|
+
|
8
|
+
SOLARIS_32 = RbConfig::CONFIG['target'] == "i386-pc-solaris2.10"
|
9
|
+
|
10
|
+
$CFLAGS = "#{RbConfig::CONFIG['CFLAGS']} #{$CFLAGS}".gsub("$(cflags)", "").gsub("-fno-common", "")
|
11
|
+
$CFLAGS << " -std=gnu99" if SOLARIS_32
|
12
|
+
$EXTRA_CONF = " --disable-64bit" if SOLARIS_32
|
13
|
+
$LDFLAGS = "#{RbConfig::CONFIG['LDFLAGS']} #{$LDFLAGS}".gsub("$(ldflags)", "").gsub("-fno-common", "")
|
14
|
+
$CXXFLAGS = " -std=gnu++98 #{$CFLAGS}"
|
15
|
+
$CPPFLAGS = $ARCH_FLAG = $DLDFLAGS = ""
|
16
|
+
|
17
|
+
if ENV['DEBUG']
|
18
|
+
puts "Setting debug flags."
|
19
|
+
$CFLAGS << " -O0 -ggdb -DHAVE_DEBUG"
|
20
|
+
$EXTRA_CONF = ""
|
21
|
+
end
|
22
|
+
|
23
|
+
def check_libmemcached
|
24
|
+
return if ENV["EXTERNAL_LIB"]
|
25
|
+
|
26
|
+
$includes = " -I#{HERE}/include"
|
27
|
+
$defines = " -DLIBMEMCACHED_WITH_SASL_SUPPORT"
|
28
|
+
$libraries = " -L#{HERE}/lib"
|
29
|
+
$CFLAGS = "#{$includes} #{$libraries} #{$CFLAGS}"
|
30
|
+
$LDFLAGS = "#{$libraries} #{$LDFLAGS}"
|
31
|
+
$LIBPATH = ["#{HERE}/lib"]
|
32
|
+
$DEFLIBPATH = [] unless SOLARIS_32
|
33
|
+
|
34
|
+
Dir.chdir(HERE) do
|
35
|
+
if File.exist?("lib")
|
36
|
+
puts "Libmemcached already built; run 'rake clean' first if you need to rebuild."
|
37
|
+
else
|
38
|
+
tar = SOLARIS_32 ? 'gtar' : 'tar'
|
39
|
+
patch = SOLARIS_32 ? 'gpatch' : 'patch'
|
40
|
+
|
41
|
+
# have_sasl check may fail on OSX, skip it
|
42
|
+
# unless RUBY_PLATFORM =~ /darwin/ or have_library('sasl2')
|
43
|
+
# raise "SASL2 not found. You need the libsasl2-dev library, which should be provided through your system's package manager."
|
44
|
+
# end
|
45
|
+
|
46
|
+
puts "Building libmemcached."
|
47
|
+
puts(cmd = "#{tar} xzf #{BUNDLE} 2>&1")
|
48
|
+
raise "'#{cmd}' failed" unless system(cmd)
|
49
|
+
|
50
|
+
puts "Patching libmemcached source."
|
51
|
+
puts(cmd = "#{patch} -p1 -Z < libmemcached.patch")
|
52
|
+
raise "'#{cmd}' failed" unless system(cmd)
|
53
|
+
|
54
|
+
puts "Patching libmemcached with SASL support."
|
55
|
+
puts(cmd = "#{patch} -p1 -Z < sasl.patch")
|
56
|
+
raise "'#{cmd}' failed" unless system(cmd)
|
57
|
+
|
58
|
+
puts "Touching aclocal.m4 in libmemcached."
|
59
|
+
puts(cmd = "touch -r #{BUNDLE_PATH}/m4/visibility.m4 #{BUNDLE_PATH}/configure.ac #{BUNDLE_PATH}/m4/pandora_have_sasl.m4")
|
60
|
+
raise "'#{cmd}' failed" unless system(cmd)
|
61
|
+
|
62
|
+
Dir.chdir(BUNDLE_PATH) do
|
63
|
+
puts(cmd = "env CFLAGS='-fPIC #{$CFLAGS}' LDFLAGS='-fPIC #{$LDFLAGS}' ./configure --prefix=#{HERE} --without-memcached --disable-shared --disable-utils --disable-dependency-tracking #{$EXTRA_CONF} 2>&1")
|
64
|
+
raise "'#{cmd}' failed" unless system(cmd)
|
65
|
+
|
66
|
+
puts(cmd = "make CXXFLAGS='#{$CXXFLAGS}' || true 2>&1")
|
67
|
+
raise "'#{cmd}' failed" unless system(cmd)
|
68
|
+
|
69
|
+
puts(cmd = "make install || true 2>&1")
|
70
|
+
raise "'#{cmd}' failed" unless system(cmd)
|
71
|
+
end
|
72
|
+
|
73
|
+
system("rm -rf #{BUNDLE_PATH}") unless ENV['DEBUG'] or ENV['DEV']
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Absolutely prevent the linker from picking up any other libmemcached
|
78
|
+
Dir.chdir("#{HERE}/lib") do
|
79
|
+
system("cp -f libmemcached.a libmemcached_gem.a")
|
80
|
+
system("cp -f libmemcached.la libmemcached_gem.la")
|
81
|
+
end
|
82
|
+
$LIBS << " -lmemcached_gem -lsasl2"
|
83
|
+
end
|
84
|
+
|
85
|
+
if ENV['SWIG']
|
86
|
+
puts "Running SWIG."
|
87
|
+
puts(cmd = "swig #{$defines} #{$includes} -ruby -autorename rlibmemcached.i")
|
88
|
+
raise "'#{cmd}' failed" unless system(cmd)
|
89
|
+
puts(cmd = "sed -i 's/STR2CSTR/StringValuePtr/' rlibmemcached_wrap.c")
|
90
|
+
raise "'#{cmd}' failed" unless system(cmd)
|
91
|
+
end
|
92
|
+
|
93
|
+
check_libmemcached
|
94
|
+
|
95
|
+
create_makefile 'rlibmemcached'
|
Binary file
|
@@ -0,0 +1,270 @@
|
|
1
|
+
|
2
|
+
diff --git a/libmemcached-0.32/libmemcached/memcached_response.c b/libmemcached/libmemcached/memcached_response.c
|
3
|
+
--- a/libmemcached-0.32/libmemcached/memcached_response.c
|
4
|
+
+++ b/libmemcached/libmemcached/memcached_response.c
|
5
|
+
@@ -496,6 +496,8 @@
|
6
|
+
case PROTOCOL_BINARY_RESPONSE_E2BIG:
|
7
|
+
case PROTOCOL_BINARY_RESPONSE_EINVAL:
|
8
|
+
case PROTOCOL_BINARY_RESPONSE_NOT_STORED:
|
9
|
+
+ rc= MEMCACHED_NOTSTORED;
|
10
|
+
+ break;
|
11
|
+
case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND:
|
12
|
+
case PROTOCOL_BINARY_RESPONSE_ENOMEM:
|
13
|
+
default:
|
14
|
+
diff --git a/libmemcached-0.32/libmemcached/memcached.c b/libmemcached/libmemcached/memcached.c
|
15
|
+
--- a/libmemcached-0.32/libmemcached/memcached.c
|
16
|
+
+++ b/libmemcached/libmemcached/memcached.c
|
17
|
+
@@ -50,6 +50,9 @@ void memcached_free(memcached_st *ptr)
|
18
|
+
if (ptr->continuum)
|
19
|
+
ptr->call_free(ptr, ptr->continuum);
|
20
|
+
|
21
|
+
+ if (ptr->live_host_indices)
|
22
|
+
+ ptr->call_free(ptr, ptr->live_host_indices);
|
23
|
+
+
|
24
|
+
if (ptr->is_allocated)
|
25
|
+
ptr->call_free(ptr, ptr);
|
26
|
+
else
|
27
|
+
diff --git a/libmemcached-0.32/libmemcached/memcached.h b/libmemcached/libmemcached/memcached.h
|
28
|
+
--- a/libmemcached-0.32/libmemcached/memcached.h
|
29
|
+
+++ b/libmemcached/libmemcached/memcached.h
|
30
|
+
@@ -112,6 +112,9 @@ struct memcached_st {
|
31
|
+
memcached_trigger_delete_key delete_trigger;
|
32
|
+
char prefix_key[MEMCACHED_PREFIX_KEY_MAX_SIZE];
|
33
|
+
uint32_t number_of_replicas;
|
34
|
+
+ uint32_t number_of_live_hosts;
|
35
|
+
+ uint32_t *live_host_indices;
|
36
|
+
+ uint32_t live_host_indices_size;
|
37
|
+
};
|
38
|
+
|
39
|
+
LIBMEMCACHED_API
|
40
|
+
diff --git a/libmemcached-0.32/libmemcached/memcached_connect.c b/libmemcached/libmemcached/memcached_connect.c
|
41
|
+
--- a/libmemcached-0.32/libmemcached/memcached_connect.c
|
42
|
+
+++ b/libmemcached/libmemcached/memcached_connect.c
|
43
|
+
@@ -273,7 +272,6 @@ static memcached_return network_connect(memcached_server_st *ptr)
|
44
|
+
(void)fcntl(ptr->fd, F_SETFL, flags & ~O_NONBLOCK);
|
45
|
+
|
46
|
+
WATCHPOINT_ASSERT(ptr->cursor_active == 0);
|
47
|
+
- ptr->server_failure_counter= 0;
|
48
|
+
return MEMCACHED_SUCCESS;
|
49
|
+
}
|
50
|
+
use = use->ai_next;
|
51
|
+
@@ -282,21 +280,13 @@ static memcached_return network_connect(memcached_server_st *ptr)
|
52
|
+
|
53
|
+
if (ptr->fd == -1)
|
54
|
+
{
|
55
|
+
- /* Failed to connect. schedule next retry */
|
56
|
+
- if (ptr->root->retry_timeout)
|
57
|
+
- {
|
58
|
+
- struct timeval next_time;
|
59
|
+
-
|
60
|
+
- if (gettimeofday(&next_time, NULL) == 0)
|
61
|
+
- ptr->next_retry= next_time.tv_sec + ptr->root->retry_timeout;
|
62
|
+
- }
|
63
|
+
- ptr->server_failure_counter+= 1;
|
64
|
+
+ ptr->server_failure_counter ++;
|
65
|
+
if (ptr->cached_errno == 0)
|
66
|
+
return MEMCACHED_TIMEOUT;
|
67
|
+
+
|
68
|
+
return MEMCACHED_ERRNO; /* The last error should be from connect() */
|
69
|
+
}
|
70
|
+
|
71
|
+
- ptr->server_failure_counter= 0;
|
72
|
+
return MEMCACHED_SUCCESS; /* The last error should be from connect() */
|
73
|
+
}
|
74
|
+
|
75
|
+
@@ -315,7 +305,7 @@ memcached_return memcached_connect(memcached_server_st *ptr)
|
76
|
+
gettimeofday(&next_time, NULL);
|
77
|
+
|
78
|
+
/* if we've had too many consecutive errors on this server, mark it dead. */
|
79
|
+
- if (ptr->server_failure_counter > ptr->root->server_failure_limit)
|
80
|
+
+ if (ptr->server_failure_counter >= ptr->root->server_failure_limit)
|
81
|
+
{
|
82
|
+
ptr->next_retry= next_time.tv_sec + ptr->root->retry_timeout;
|
83
|
+
ptr->server_failure_counter= 0;
|
84
|
+
diff --git a/libmemcached-0.32/libmemcached/memcached_get.h b/libmemcached/libmemcached/memcached_get.h
|
85
|
+
diff --git a/libmemcached-0.32/libmemcached/memcached_hash.c b/libmemcached/libmemcached/memcached_hash.c
|
86
|
+
index 129d761..3a7fa55 100644
|
87
|
+
--- a/libmemcached-0.32/libmemcached/memcached_hash.c
|
88
|
+
+++ b/libmemcached/libmemcached/memcached_hash.c
|
89
|
+
@@ -11,6 +11,7 @@ static uint32_t FNV_32_PRIME= 16777619;
|
90
|
+
/* Prototypes */
|
91
|
+
static uint32_t internal_generate_hash(const char *key, size_t key_length);
|
92
|
+
static uint32_t internal_generate_md5(const char *key, size_t key_length);
|
93
|
+
+uint32_t memcached_live_host_index(memcached_st *ptr, uint32_t num);
|
94
|
+
|
95
|
+
uint32_t memcached_generate_hash_value(const char *key, size_t key_length, memcached_hash hash_algorithm)
|
96
|
+
{
|
97
|
+
@@ -146,10 +144,10 @@ static uint32_t dispatch_host(memcached_st *ptr, uint32_t hash)
|
98
|
+
right= begin;
|
99
|
+
return right->index;
|
100
|
+
}
|
101
|
+
- case MEMCACHED_DISTRIBUTION_MODULA:
|
102
|
+
- return hash % ptr->number_of_hosts;
|
103
|
+
+ case MEMCACHED_DISTRIBUTION_MODULA:
|
104
|
+
+ return memcached_live_host_index(ptr, hash);
|
105
|
+
case MEMCACHED_DISTRIBUTION_RANDOM:
|
106
|
+
- return (uint32_t) random() % ptr->number_of_hosts;
|
107
|
+
+ return memcached_live_host_index(ptr, (uint32_t) random());
|
108
|
+
default:
|
109
|
+
WATCHPOINT_ASSERT(0); /* We have added a distribution without extending the logic */
|
110
|
+
return hash % ptr->number_of_hosts;
|
111
|
+
@@ -201,6 +199,19 @@ uint32_t memcached_generate_hash(memcached_st *ptr, const char *key, size_t key_
|
112
|
+
return dispatch_host(ptr, hash);
|
113
|
+
}
|
114
|
+
|
115
|
+
+uint32_t memcached_live_host_index(memcached_st *ptr, uint32_t num)
|
116
|
+
+{
|
117
|
+
+ if (memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS)) {
|
118
|
+
+ if (ptr->number_of_live_hosts > 0) {
|
119
|
+
+ return ptr->live_host_indices[num % ptr->number_of_live_hosts];
|
120
|
+
+ } else {
|
121
|
+
+ return 0; /* FIXME: we should do something different if every server's dead, but I dunno what. */
|
122
|
+
+ }
|
123
|
+
+ } else {
|
124
|
+
+ return num % ptr->number_of_hosts;
|
125
|
+
+ }
|
126
|
+
+}
|
127
|
+
+
|
128
|
+
static uint32_t internal_generate_hash(const char *key, size_t key_length)
|
129
|
+
{
|
130
|
+
const char *ptr= key;
|
131
|
+
diff --git a/libmemcached-0.32/libmemcached/memcached_hosts.c b/libmemcached/libmemcached/memcached_hosts.c
|
132
|
+
--- a/libmemcached-0.32/libmemcached/memcached_hosts.c
|
133
|
+
+++ b/libmemcached/libmemcached/memcached_hosts.c
|
134
|
+
@@ -7,6 +7,7 @@ static memcached_return server_add(memcached_st *ptr, const char *hostname,
|
135
|
+
uint32_t weight,
|
136
|
+
memcached_connection type);
|
137
|
+
memcached_return update_continuum(memcached_st *ptr);
|
138
|
+
+memcached_return update_live_host_indices(memcached_st *ptr);
|
139
|
+
|
140
|
+
static int compare_servers(const void *p1, const void *p2)
|
141
|
+
{
|
142
|
+
@@ -44,8 +45,12 @@ memcached_return run_distribution(memcached_st *ptr)
|
143
|
+
case MEMCACHED_DISTRIBUTION_MODULA:
|
144
|
+
if (ptr->flags & MEM_USE_SORT_HOSTS)
|
145
|
+
sort_hosts(ptr);
|
146
|
+
+ if (memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS))
|
147
|
+
+ update_live_host_indices(ptr);
|
148
|
+
break;
|
149
|
+
case MEMCACHED_DISTRIBUTION_RANDOM:
|
150
|
+
+ if (memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS))
|
151
|
+
+ update_live_host_indices(ptr);
|
152
|
+
break;
|
153
|
+
default:
|
154
|
+
WATCHPOINT_ASSERT(0); /* We have added a distribution without extending the logic */
|
155
|
+
@@ -85,6 +90,46 @@ static uint32_t ketama_server_hash(const char *key, unsigned int key_length, int
|
156
|
+
| (results[0 + alignment * 4] & 0xFF);
|
157
|
+
}
|
158
|
+
|
159
|
+
+memcached_return update_live_host_indices(memcached_st *ptr)
|
160
|
+
+{
|
161
|
+
+ uint32_t host_index;
|
162
|
+
+ struct timeval now;
|
163
|
+
+ uint32_t i = 0;
|
164
|
+
+ memcached_server_st *list;
|
165
|
+
+
|
166
|
+
+ if (gettimeofday(&now, NULL) != 0)
|
167
|
+
+ {
|
168
|
+
+ ptr->cached_errno = errno;
|
169
|
+
+ return MEMCACHED_ERRNO;
|
170
|
+
+ }
|
171
|
+
+
|
172
|
+
+ if (ptr->live_host_indices == NULL) {
|
173
|
+
+ ptr->live_host_indices = (uint32_t *)ptr->call_malloc(ptr, sizeof(uint32_t) * ptr->number_of_hosts);
|
174
|
+
+ ptr->live_host_indices_size = ptr->number_of_live_hosts;
|
175
|
+
+ }
|
176
|
+
+
|
177
|
+
+ /* somehow we added some hosts. Shouldn't get here much, if at all. */
|
178
|
+
+ if (ptr->live_host_indices_size < ptr->number_of_hosts ) {
|
179
|
+
+ ptr->live_host_indices = (uint32_t *)ptr->call_realloc(ptr, ptr->live_host_indices, sizeof(uint32_t) * ptr->number_of_hosts);
|
180
|
+
+ ptr->live_host_indices_size = ptr->number_of_live_hosts;
|
181
|
+
+ }
|
182
|
+
+
|
183
|
+
+ if (ptr->live_host_indices == NULL)
|
184
|
+
+ return MEMCACHED_FAILURE;
|
185
|
+
+
|
186
|
+
+ list = ptr->hosts;
|
187
|
+
+ for (host_index= 0; host_index < ptr->number_of_hosts; ++host_index)
|
188
|
+
+ {
|
189
|
+
+ if (list[host_index].next_retry <= now.tv_sec) {
|
190
|
+
+ ptr->live_host_indices[i++] = host_index;
|
191
|
+
+ } else if (ptr->next_distribution_rebuild == 0 || list[host_index].next_retry < ptr->next_distribution_rebuild) {
|
192
|
+
+ ptr->next_distribution_rebuild= list[host_index].next_retry;
|
193
|
+
+ }
|
194
|
+
+ }
|
195
|
+
+ ptr->number_of_live_hosts = i;
|
196
|
+
+ return MEMCACHED_SUCCESS;
|
197
|
+
+}
|
198
|
+
+
|
199
|
+
static int continuum_item_cmp(const void *t1, const void *t2)
|
200
|
+
{
|
201
|
+
memcached_continuum_item_st *ct1= (memcached_continuum_item_st *)t1;
|
202
|
+
@@ -111,8 +156,8 @@ memcached_return update_continuum(memcached_st *ptr)
|
203
|
+
uint32_t pointer_per_server= MEMCACHED_POINTS_PER_SERVER;
|
204
|
+
uint32_t pointer_per_hash= 1;
|
205
|
+
uint64_t total_weight= 0;
|
206
|
+
- uint64_t is_ketama_weighted= 0;
|
207
|
+
- uint64_t is_auto_ejecting= 0;
|
208
|
+
+ uint32_t is_ketama_weighted= 0;
|
209
|
+
+ uint32_t is_auto_ejecting= 0;
|
210
|
+
uint32_t points_per_server= 0;
|
211
|
+
uint32_t live_servers= 0;
|
212
|
+
struct timeval now;
|
213
|
+
diff --git a/libmemcached-0.32/libmemcached/memcached_storage.c b/libmemcached/libmemcached/memcached_storage.c
|
214
|
+
index ecefc56..ee79a7e 100644
|
215
|
+
--- a/libmemcached-0.32/libmemcached/memcached_storage.c
|
216
|
+
+++ b/libmemcached/libmemcached/memcached_storage.c
|
217
|
+
@@ -135,22 +135,16 @@ static inline memcached_return memcached_send(memcached_st *ptr,
|
218
|
+
}
|
219
|
+
|
220
|
+
if (write_length >= MEMCACHED_DEFAULT_COMMAND_SIZE)
|
221
|
+
- {
|
222
|
+
- rc= MEMCACHED_WRITE_FAILURE;
|
223
|
+
- goto error;
|
224
|
+
- }
|
225
|
+
+ return MEMCACHED_WRITE_FAILURE;
|
226
|
+
|
227
|
+
/* Send command header */
|
228
|
+
rc= memcached_do(&ptr->hosts[server_key], buffer, write_length, 0);
|
229
|
+
if (rc != MEMCACHED_SUCCESS)
|
230
|
+
- goto error;
|
231
|
+
+ return rc;
|
232
|
+
|
233
|
+
/* Send command body */
|
234
|
+
if ((sent_length= memcached_io_write(&ptr->hosts[server_key], value, value_length, 0)) == -1)
|
235
|
+
- {
|
236
|
+
- rc= MEMCACHED_WRITE_FAILURE;
|
237
|
+
- goto error;
|
238
|
+
- }
|
239
|
+
+ return MEMCACHED_WRITE_FAILURE;
|
240
|
+
|
241
|
+
if ((ptr->flags & MEM_BUFFER_REQUESTS) && verb == SET_OP)
|
242
|
+
to_write= 0;
|
243
|
+
@@ -158,10 +152,7 @@ static inline memcached_return memcached_send(memcached_st *ptr,
|
244
|
+
to_write= 1;
|
245
|
+
|
246
|
+
if ((sent_length= memcached_io_write(&ptr->hosts[server_key], "\r\n", 2, to_write)) == -1)
|
247
|
+
- {
|
248
|
+
- rc= MEMCACHED_WRITE_FAILURE;
|
249
|
+
- goto error;
|
250
|
+
- }
|
251
|
+
+ return MEMCACHED_WRITE_FAILURE;
|
252
|
+
|
253
|
+
if (ptr->flags & MEM_NOREPLY)
|
254
|
+
return (to_write == 0) ? MEMCACHED_BUFFERED : MEMCACHED_SUCCESS;
|
255
|
+
@@ -170,15 +161,8 @@ static inline memcached_return memcached_send(memcached_st *ptr,
|
256
|
+
return MEMCACHED_BUFFERED;
|
257
|
+
|
258
|
+
rc= memcached_response(&ptr->hosts[server_key], buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
|
259
|
+
-
|
260
|
+
if (rc == MEMCACHED_STORED)
|
261
|
+
- return MEMCACHED_SUCCESS;
|
262
|
+
- else
|
263
|
+
- return rc;
|
264
|
+
-
|
265
|
+
-error:
|
266
|
+
- memcached_io_reset(&ptr->hosts[server_key]);
|
267
|
+
-
|
268
|
+
+ return MEMCACHED_SUCCESS;
|
269
|
+
return rc;
|
270
|
+
}
|
data/ext/rlibmemcached.i
ADDED
@@ -0,0 +1,230 @@
|
|
1
|
+
%module rlibmemcached
|
2
|
+
%{
|
3
|
+
#include <libmemcached/visibility.h>
|
4
|
+
#include <libmemcached/memcached.h>
|
5
|
+
%}
|
6
|
+
|
7
|
+
%warnfilter(SWIGWARN_RUBY_WRONG_NAME) memcached_st;
|
8
|
+
%warnfilter(SWIGWARN_RUBY_WRONG_NAME) memcached_server_st;
|
9
|
+
%warnfilter(SWIGWARN_RUBY_WRONG_NAME) memcached_stat_st;
|
10
|
+
%warnfilter(SWIGWARN_RUBY_WRONG_NAME) memcached_string_st;
|
11
|
+
%warnfilter(SWIGWARN_RUBY_WRONG_NAME) memcached_result_st;
|
12
|
+
|
13
|
+
%include "typemaps.i"
|
14
|
+
%include "libmemcached/visibility.h"
|
15
|
+
|
16
|
+
// Register libmemcached's struct free function to prevent memory leaks
|
17
|
+
%freefunc memcached_st "memcached_free";
|
18
|
+
%freefunc memcached_server_st "memcached_server_free";
|
19
|
+
|
20
|
+
// %trackobjects; // Doesn't fix any interesting leaks
|
21
|
+
|
22
|
+
//// Input maps
|
23
|
+
|
24
|
+
%apply unsigned short { uint8_t };
|
25
|
+
%apply unsigned int { uint16_t };
|
26
|
+
%apply unsigned long { uint32_t flags, uint32_t offset, uint32_t weight };
|
27
|
+
%apply unsigned long long { uint64_t data, uint64_t cas };
|
28
|
+
|
29
|
+
// Array of strings map for multiget
|
30
|
+
%typemap(in) (const char **keys, size_t *key_length, size_t number_of_keys) {
|
31
|
+
int i;
|
32
|
+
Check_Type($input, T_ARRAY);
|
33
|
+
$3 = (unsigned int) RARRAY_LEN($input);
|
34
|
+
$2 = (size_t *) malloc(($3+1)*sizeof(size_t));
|
35
|
+
$1 = (char **) malloc(($3+1)*sizeof(char *));
|
36
|
+
for(i = 0; i < $3; i ++) {
|
37
|
+
Check_Type(RARRAY_PTR($input)[i], T_STRING);
|
38
|
+
$2[i] = RSTRING_LEN(RARRAY_PTR($input)[i]);
|
39
|
+
$1[i] = StringValuePtr(RARRAY_PTR($input)[i]);
|
40
|
+
}
|
41
|
+
}
|
42
|
+
%typemap(in) (char **keys, size_t *key_length, unsigned int number_of_keys) {
|
43
|
+
int i;
|
44
|
+
Check_Type($input, T_ARRAY);
|
45
|
+
$3 = (unsigned int) RARRAY_LEN($input);
|
46
|
+
$2 = (size_t *) malloc(($3+1)*sizeof(size_t));
|
47
|
+
$1 = (char **) malloc(($3+1)*sizeof(char *));
|
48
|
+
for(i = 0; i < $3; i ++) {
|
49
|
+
Check_Type(RARRAY_PTR($input)[i], T_STRING);
|
50
|
+
$2[i] = RSTRING_LEN(RARRAY_PTR($input)[i]);
|
51
|
+
$1[i] = StringValuePtr(RARRAY_PTR($input)[i]);
|
52
|
+
}
|
53
|
+
}
|
54
|
+
%typemap(freearg) (char **keys, size_t *key_length, size_t number_of_keys) {
|
55
|
+
free($1);
|
56
|
+
free($2);
|
57
|
+
}
|
58
|
+
|
59
|
+
// Generic strings
|
60
|
+
%typemap(in) (const char *str, size_t len) {
|
61
|
+
$1 = STR2CSTR($input);
|
62
|
+
$2 = (size_t) RSTRING_LEN($input);
|
63
|
+
};
|
64
|
+
|
65
|
+
// Void type strings without lengths for prefix_key callback
|
66
|
+
%typemap(in) (void *data) {
|
67
|
+
if ( (size_t) RSTRING_LEN($input) == 0) {
|
68
|
+
$1 = NULL;
|
69
|
+
} else {
|
70
|
+
$1 = STR2CSTR($input);
|
71
|
+
}
|
72
|
+
};
|
73
|
+
|
74
|
+
%apply (const char *str, size_t len) {
|
75
|
+
(const char *namespace, size_t namespace_length),
|
76
|
+
(const char *key, size_t key_length),
|
77
|
+
(const char *value, size_t value_length)
|
78
|
+
};
|
79
|
+
|
80
|
+
// Key strings with same master key
|
81
|
+
// This will have to go if people actually want to set the master key separately
|
82
|
+
%typemap(in) (const char *master_key, size_t master_key_length, const char *key, size_t key_length) {
|
83
|
+
$3 = $1 = STR2CSTR($input);
|
84
|
+
$4 = $2 = (size_t) RSTRING_LEN($input);
|
85
|
+
};
|
86
|
+
|
87
|
+
|
88
|
+
//// Output maps
|
89
|
+
|
90
|
+
%apply unsigned short *OUTPUT {memcached_return *error}
|
91
|
+
%apply unsigned int *OUTPUT {uint32_t *flags}
|
92
|
+
%apply size_t *OUTPUT {size_t *value_length}
|
93
|
+
%apply unsigned long long *OUTPUT {uint64_t *value}
|
94
|
+
|
95
|
+
// Uint64
|
96
|
+
%typemap(out) (uint64_t) {
|
97
|
+
$result = ULL2NUM($1);
|
98
|
+
};
|
99
|
+
|
100
|
+
// Uint32
|
101
|
+
%typemap(out) (uint32_t) {
|
102
|
+
$result = UINT2NUM($1);
|
103
|
+
};
|
104
|
+
|
105
|
+
// Void type strings without lengths for prefix_key callback
|
106
|
+
// Currently not used by the gem
|
107
|
+
%typemap(out) (void *) {
|
108
|
+
$result = rb_str_new2($1);
|
109
|
+
};
|
110
|
+
|
111
|
+
// String for memcached_fetch
|
112
|
+
%typemap(in, numinputs=0) (char *key, size_t *key_length) {
|
113
|
+
char string[256];
|
114
|
+
size_t length = 0;
|
115
|
+
$1 = string;
|
116
|
+
$2 = &length;
|
117
|
+
};
|
118
|
+
%typemap(argout) (char *key, size_t *key_length) {
|
119
|
+
// Pushes an empty string when *key_length == 0
|
120
|
+
rb_ary_push($result, rb_str_new($1, *$2));
|
121
|
+
}
|
122
|
+
|
123
|
+
// Array of strings
|
124
|
+
|
125
|
+
%typemap(out) (char **) {
|
126
|
+
int i;
|
127
|
+
VALUE ary = rb_ary_new();
|
128
|
+
$result = rb_ary_new();
|
129
|
+
|
130
|
+
for(i=0; $1[i] != NULL; i++) {
|
131
|
+
rb_ary_store(ary, i, rb_str_new2($1[i]));
|
132
|
+
}
|
133
|
+
rb_ary_push($result, ary);
|
134
|
+
free($1);
|
135
|
+
};
|
136
|
+
|
137
|
+
//// SWIG includes, for functions, constants, and structs
|
138
|
+
|
139
|
+
%include "libmemcached/visibility.h"
|
140
|
+
%include "libmemcached/memcached.h"
|
141
|
+
%include "libmemcached/memcached_constants.h"
|
142
|
+
%include "libmemcached/memcached_get.h"
|
143
|
+
%include "libmemcached/memcached_storage.h"
|
144
|
+
%include "libmemcached/memcached_result.h"
|
145
|
+
%include "libmemcached/memcached_server.h"
|
146
|
+
%include "libmemcached/memcached_sasl.h"
|
147
|
+
|
148
|
+
//// Custom C functions
|
149
|
+
|
150
|
+
//// Manual wrappers
|
151
|
+
|
152
|
+
// Single get. SWIG likes to use SWIG_FromCharPtr instead of SWIG_FromCharPtrAndSize because
|
153
|
+
// of the retval/argout split, so it truncates return values with \0 in them.
|
154
|
+
VALUE memcached_get_rvalue(memcached_st *ptr, const char *key, size_t key_length, uint32_t *flags, memcached_return *error);
|
155
|
+
%{
|
156
|
+
VALUE memcached_get_rvalue(memcached_st *ptr, const char *key, size_t key_length, uint32_t *flags, memcached_return *error) {
|
157
|
+
VALUE ret;
|
158
|
+
size_t value_length;
|
159
|
+
char *value = memcached_get(ptr, key, key_length, &value_length, flags, error);
|
160
|
+
ret = rb_str_new(value, value_length);
|
161
|
+
free(value);
|
162
|
+
return ret;
|
163
|
+
};
|
164
|
+
%}
|
165
|
+
|
166
|
+
// Multi get
|
167
|
+
VALUE memcached_fetch_rvalue(memcached_st *ptr, char *key, size_t *key_length, uint32_t *flags, memcached_return *error);
|
168
|
+
%{
|
169
|
+
VALUE memcached_fetch_rvalue(memcached_st *ptr, char *key, size_t *key_length, uint32_t *flags, memcached_return *error) {
|
170
|
+
size_t value_length;
|
171
|
+
VALUE result = rb_ary_new();
|
172
|
+
|
173
|
+
char *value = memcached_fetch(ptr, key, key_length, &value_length, flags, error);
|
174
|
+
if (value == NULL) {
|
175
|
+
rb_ary_push(result, Qnil);
|
176
|
+
} else {
|
177
|
+
VALUE ret = rb_str_new(value, value_length);
|
178
|
+
rb_ary_push(result, ret);
|
179
|
+
free(value);
|
180
|
+
}
|
181
|
+
return result;
|
182
|
+
};
|
183
|
+
%}
|
184
|
+
|
185
|
+
// We need to wrap this so it doesn't leak memory. SWIG doesn't want to automatically free. We could
|
186
|
+
// maybe use a 'ret' %typemap, but this is ok.
|
187
|
+
VALUE memcached_stat_get_rvalue(memcached_st *ptr, memcached_stat_st *stat, char *key, memcached_return *error);
|
188
|
+
%{
|
189
|
+
VALUE memcached_stat_get_rvalue(memcached_st *ptr, memcached_stat_st *stat, char *key, memcached_return *error) {
|
190
|
+
char *str;
|
191
|
+
VALUE ret;
|
192
|
+
str = memcached_stat_get_value(ptr, stat, key, error);
|
193
|
+
ret = rb_str_new2(str);
|
194
|
+
free(str);
|
195
|
+
return ret;
|
196
|
+
};
|
197
|
+
%}
|
198
|
+
|
199
|
+
// Ruby isn't aware that the pointer is an array... there is probably a better way to do this
|
200
|
+
memcached_server_st *memcached_select_server_at(memcached_st *in_ptr, int index);
|
201
|
+
%{
|
202
|
+
memcached_server_st *memcached_select_server_at(memcached_st *in_ptr, int index) {
|
203
|
+
return &(in_ptr->hosts[index]);
|
204
|
+
};
|
205
|
+
%}
|
206
|
+
|
207
|
+
// Same, but for stats
|
208
|
+
memcached_stat_st *memcached_select_stat_at(memcached_st *in_ptr, memcached_stat_st *stat_ptr, int index);
|
209
|
+
%{
|
210
|
+
memcached_stat_st *memcached_select_stat_at(memcached_st *in_ptr, memcached_stat_st *stat_ptr, int index) {
|
211
|
+
return &(stat_ptr[index]);
|
212
|
+
};
|
213
|
+
%}
|
214
|
+
|
215
|
+
// Wrap only hash function
|
216
|
+
// Uint32
|
217
|
+
VALUE memcached_generate_hash_rvalue(const char *key, size_t key_length, memcached_hash hash_algorithm);
|
218
|
+
%{
|
219
|
+
VALUE memcached_generate_hash_rvalue(const char *key, size_t key_length,memcached_hash hash_algorithm) {
|
220
|
+
return UINT2NUM(memcached_generate_hash_value(key, key_length, hash_algorithm));
|
221
|
+
};
|
222
|
+
%}
|
223
|
+
|
224
|
+
// Initialization for SASL
|
225
|
+
%init %{
|
226
|
+
if (sasl_client_init(NULL) != SASL_OK) {
|
227
|
+
fprintf(stderr, "Failed to initialized SASL.\n");
|
228
|
+
}
|
229
|
+
%}
|
230
|
+
|