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.
@@ -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
@@ -0,0 +1,4 @@
1
+
2
+ * Verify that DNS lookups are getting cached
3
+ * Check for memory leaks in Valgrind after free callback change
4
+ * Re-run benchmarks
@@ -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'
@@ -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
+ }
@@ -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
+