memcached 0.19.10 → 0.20.0

Sign up to get free protection for your applications and to get access to all the features.
data.tar.gz.sig CHANGED
Binary file
data/CHANGELOG CHANGED
@@ -1,4 +1,6 @@
1
1
 
2
+ v0.20.0. Add experimental module, with get_len() operator.
3
+
2
4
  v0.19.10. Add no-op hash (MEMCACHED_HASH_NONE) to skip hashing when there is one server (bierbaum). Updated benchmark.
3
5
 
4
6
  v0.19.8. Support :noreply behavior.
data/Manifest CHANGED
@@ -10,6 +10,7 @@ ext/libmemcached-0.32.tar.gz
10
10
  ext/libmemcached-2.patch
11
11
  ext/libmemcached-3.patch
12
12
  ext/libmemcached-4.patch
13
+ ext/libmemcached-5.patch
13
14
  ext/libmemcached.patch
14
15
  ext/rlibmemcached.i
15
16
  ext/rlibmemcached_wrap.c
@@ -18,6 +19,7 @@ lib/memcached.rb
18
19
  lib/memcached/auth.rb
19
20
  lib/memcached/behaviors.rb
20
21
  lib/memcached/exceptions.rb
22
+ lib/memcached/experimental_memcached.rb
21
23
  lib/memcached/integer.rb
22
24
  lib/memcached/memcached.rb
23
25
  lib/memcached/rails.rb
@@ -28,5 +30,6 @@ test/setup.rb
28
30
  test/teardown.rb
29
31
  test/test_helper.rb
30
32
  test/unit/binding_test.rb
33
+ test/unit/memcached_experimental_test.rb
31
34
  test/unit/memcached_test.rb
32
35
  test/unit/rails_test.rb
@@ -67,6 +67,10 @@ def check_libmemcached
67
67
  puts(cmd = "#{patch} -p1 -Z < libmemcached-4.patch")
68
68
  raise "'#{cmd}' failed" unless system(cmd) or ENV['DEV']
69
69
 
70
+ puts "Patching libmemcached for get_len command."
71
+ puts(cmd = "#{patch} -p1 -Z < libmemcached-5.patch")
72
+ raise "'#{cmd}' failed" unless system(cmd) or ENV['DEV']
73
+
70
74
  puts "Touching aclocal.m4 in libmemcached."
71
75
  puts(cmd = "touch -r #{BUNDLE_PATH}/m4/visibility.m4 #{BUNDLE_PATH}/configure.ac #{BUNDLE_PATH}/m4/pandora_have_sasl.m4")
72
76
  raise "'#{cmd}' failed" unless system(cmd)
@@ -0,0 +1,832 @@
1
+ diff --git a/docs/memcached_get.pod b/docs/memcached_get.pod
2
+ --- a/libmemcached-0.32/docs/memcached_get.pod
3
+ +++ b/docs/memcached_get.pod
4
+ @@ -1,6 +1,6 @@
5
+ =head1 NAME
6
+
7
+ -memcached_get, memcached_mget, memcached_fetch - Get a value
8
+ +memcached_get, memcached_get_len, memcached_mget, memcached_mget_len, memcached_fetch - Get a value
9
+
10
+ =head1 LIBRARY
11
+
12
+ @@ -15,20 +15,21 @@ C Client Library for memcached (libmemcached, -lmemcached)
13
+ memcached_result_st *result,
14
+ memcached_return *error);
15
+
16
+ - char *memcached_get (memcached_st *ptr,
17
+ - const char *key, size_t key_length,
18
+ - size_t *value_length,
19
+ - uint32_t *flags,
20
+ - memcached_return *error);
21
+ + char *memcached_get(memcached_st *ptr,
22
+ + const char *key, size_t key_length,
23
+ + size_t *value_length,
24
+ + uint32_t *flags,
25
+ + memcached_return *error);
26
+
27
+ memcached_return
28
+ - memcached_mget (memcached_st *ptr,
29
+ - char **keys, size_t *key_length,
30
+ - size_t number_of_keys);
31
+ + memcached_mget(memcached_st *ptr,
32
+ + char **keys, size_t *key_length,
33
+ + size_t number_of_keys);
34
+ char *
35
+ memcached_get_by_key(memcached_st *ptr,
36
+ const char *master_key, size_t master_key_length,
37
+ const char *key, size_t key_length,
38
+ + uint32_t user_spec_len,
39
+ size_t *value_length,
40
+ uint32_t *flags,
41
+ memcached_return *error);
42
+ @@ -37,19 +38,33 @@ C Client Library for memcached (libmemcached, -lmemcached)
43
+ memcached_mget_by_key(memcached_st *ptr,
44
+ const char *master_key, size_t master_key_length,
45
+ char **keys, size_t *key_length,
46
+ - size_t number_of_keys);
47
+ -
48
+ - char *memcached_fetch (memcached_st *ptr,
49
+ - char *key, size_t *key_length,
50
+ - size_t *value_length,
51
+ - uint32_t *flags,
52
+ - memcached_return *error);
53
+ + size_t number_of_keys,
54
+ + uint32_t user_spec_len);
55
+ +
56
+ + char *memcached_fetch(memcached_st *ptr,
57
+ + char *key, size_t *key_length,
58
+ + size_t *value_length,
59
+ + uint32_t *flags,
60
+ + memcached_return *error);
61
+ memcached_return
62
+ memcached_fetch_execute(memcached_st *ptr,
63
+ memcached_return (*callback[])(memcached_st *ptr, memcached_result_st *result, void *context),
64
+ void *context,
65
+ unsigned int number_of_callbacks);
66
+
67
+ + char *
68
+ + memcached_get_len(memcached_st *ptr,
69
+ + const char *key, size_t key_length,
70
+ + uint32_t user_spec_len,
71
+ + size_t *value_length,
72
+ + uint32_t *flags,
73
+ + memcached_return *error);
74
+ +
75
+ + memcached_return
76
+ + memcached_mget_len(memcached_st *ptr,
77
+ + const char **keys, size_t *key_length,
78
+ + size_t number_of_keys, uint32_t user_spec_len);
79
+ +
80
+ =head1 DESCRIPTION
81
+
82
+ memcached_get() is used to fetch an individual value from the server. You
83
+ @@ -61,6 +76,12 @@ memcached_return pointer to hold any error. The object will be returned
84
+ upon success and NULL will be returned on failure. Any object returned by
85
+ memcached_get() must be released by the caller application.
86
+
87
+ +memcached_get_len() is also used to fetch an individual value from the
88
+ +server. The only difference when compared to memcached_get() is that
89
+ +the server will only send back the first n bytes of the value where n is
90
+ +specified by the user. Note that this command is only available when
91
+ +using the ascii protocol.
92
+ +
93
+ memcached_mget() is used to select multiple keys at once. For multiple key
94
+ operations it is always faster to use this function. This function always
95
+ works asynchronously. memcached_fetch() is then used to retrieve any keys
96
+ @@ -71,17 +92,23 @@ return NULL (aka no more values). If you need to quit in the middle of a
97
+ memcached_get() call, execute a memcached_quit(). After you do this, you can
98
+ issue new queries against the server.
99
+
100
+ +memcached_mget_len() is also used to select multiple keys at once. The
101
+ +only difference when compared to memcached_mget() is that the server
102
+ +will only send back the first n bytes of each value where n is
103
+ +specified by the user. Note that this command is only available when
104
+ +using the ascii protocol.
105
+ +
106
+ memcached_fetch() is used to fetch an individual value from the server.
107
+ -memcached_mget() must always be called before using this method. You
108
+ -must pass in a key and its length to fetch the object. You must supply
109
+ -three pointer variables which will give you the state of the returned
110
+ -object. A uint32_t pointer to contain whatever flags you stored with the value,
111
+ -a size_t pointer which will be filled with size of of the object, and a
112
+ -memcached_return pointer to hold any error. The object will be returned
113
+ -upon success and NULL will be returned on failure. MEMCACHD_END is returned
114
+ -by the *error value when all objects that have been found are returned.
115
+ -The final value upon MEMCACHED_END is null. Values returned by
116
+ -memcached_fetch() musted be free'ed by the caller.
117
+ +memcached_mget() or memcached_mget_len() must always be called before
118
+ +using this method. You must pass in a key and its length to fetch the
119
+ +object. You must supply three pointer variables which will give you the
120
+ +state of the returned object. A uint32_t pointer to contain whatever
121
+ +flags you stored with the value, a size_t pointer which will be filled
122
+ +with size of of the object, and a memcached_return pointer to hold any
123
+ +error. The object will be returned upon success and NULL will be returned
124
+ +on failure. MEMCACHD_END is returned by the *error value when all objects
125
+ +that have been found are returned. The final value upon MEMCACHED_END is
126
+ +null. Values returned by memcached_fetch() musted be free'ed by the caller.
127
+
128
+ memcached_fetch_result() is used to return a memcached_result_st(3) structure
129
+ from a memcached server. The result object is forward compatible with changes
130
+ @@ -113,8 +140,9 @@ C<MEMCACHED_NOT_SUPPORTED>.
131
+ =head1 RETURN
132
+
133
+ All objects returned must be freed by the calling application.
134
+ -memcached_get() and memcached_fetch() will return NULL on error. You must
135
+ -look at the value of error to determine what the actual error was.
136
+ +memcached_get(), memcached_get_len(), and memcached_fetch() will return
137
+ +NULL on error. You must look at the value of error to determine what
138
+ +the actual error was.
139
+
140
+ =head1 HOME
141
+
142
+ diff --git a/libmemcached/common.h b/libmemcached/common.h
143
+ --- a/libmemcached-0.32/libmemcached/common.h
144
+ +++ b/libmemcached/libmemcached/common.h
145
+ @@ -34,6 +34,15 @@
146
+ # endif
147
+ #endif
148
+
149
+ +/* Note we need the 2 concats below because arguments to ##
150
+ + * are not expanded, so we need to expand __LINE__ with one indirection
151
+ + * before doing the actual concatenation.
152
+ + * From: http://www.pixelbeat.org/programming/gcc/static_assert.html
153
+ + */
154
+ +#define ASSERT_CONCAT_(a, b) a##b
155
+ +#define ASSERT_CONCAT(a, b) ASSERT_CONCAT_(a, b)
156
+ +#define assert_on_compile(e) enum { ASSERT_CONCAT(assert_line_, __LINE__) = 1/(!!(e)) }
157
+ +
158
+ /* Define this here, which will turn on the visibilty controls while we're
159
+ * building libmemcached.
160
+ */
161
+ diff --git a/libmemcached/memcached.hpp b/libmemcached/memcached.hpp
162
+ --- a/libmemcached-0.32/libmemcached/memcached.hpp
163
+ +++ b/libmemcached/libmemcached/memcached.hpp
164
+ @@ -175,6 +175,7 @@ public:
165
+ char *value= memcached_get_by_key(&memc,
166
+ master_key.c_str(), master_key.length(),
167
+ key.c_str(), key.length(),
168
+ + GET_LEN_ARG_UNSPECIFIED,
169
+ &value_length, &flags, &rc);
170
+ if (value)
171
+ {
172
+ diff --git a/libmemcached/memcached_get.c b/libmemcached/memcached_get.c
173
+ --- a/libmemcached-0.32/libmemcached/memcached_get.c
174
+ +++ b/libmemcached/libmemcached/memcached_get.c
175
+ @@ -10,14 +10,29 @@ char *memcached_get(memcached_st *ptr, const char *key,
176
+ uint32_t *flags,
177
+ memcached_return *error)
178
+ {
179
+ - return memcached_get_by_key(ptr, NULL, 0, key, key_length, value_length,
180
+ + return memcached_get_by_key(ptr, NULL, 0, key, key_length,
181
+ + GET_LEN_ARG_UNSPECIFIED, value_length,
182
+ flags, error);
183
+ }
184
+
185
+ +char *memcached_get_len(memcached_st *ptr,
186
+ + const char *key, size_t key_length,
187
+ + uint32_t user_spec_len,
188
+ + size_t *value_length,
189
+ + uint32_t *flags,
190
+ + memcached_return *error)
191
+ +{
192
+ + return memcached_get_by_key(ptr, NULL, 0, key, key_length,
193
+ + user_spec_len, value_length,
194
+ + flags, error);
195
+ +
196
+ +}
197
+ +
198
+ char *memcached_get_by_key(memcached_st *ptr,
199
+ const char *master_key,
200
+ size_t master_key_length,
201
+ const char *key, size_t key_length,
202
+ + uint32_t user_spec_len,
203
+ size_t *value_length,
204
+ uint32_t *flags,
205
+ memcached_return *error)
206
+ @@ -37,7 +52,8 @@ char *memcached_get_by_key(memcached_st *ptr,
207
+ *error= memcached_mget_by_key(ptr,
208
+ master_key,
209
+ master_key_length,
210
+ - (const char **)&key, &key_length, 1);
211
+ + (const char **)&key, &key_length, 1,
212
+ + user_spec_len);
213
+
214
+ value= memcached_fetch(ptr, NULL, NULL,
215
+ value_length, flags, error);
216
+ @@ -105,7 +121,16 @@ memcached_return memcached_mget(memcached_st *ptr,
217
+ const char **keys, size_t *key_length,
218
+ size_t number_of_keys)
219
+ {
220
+ - return memcached_mget_by_key(ptr, NULL, 0, keys, key_length, number_of_keys);
221
+ + return memcached_mget_by_key(ptr, NULL, 0, keys, key_length, number_of_keys,
222
+ + GET_LEN_ARG_UNSPECIFIED);
223
+ +}
224
+ +
225
+ +memcached_return memcached_mget_len(memcached_st *ptr,
226
+ + const char **keys, size_t *key_length,
227
+ + size_t number_of_keys, uint32_t user_spec_len)
228
+ +{
229
+ + return memcached_mget_by_key(ptr, NULL, 0, keys, key_length, number_of_keys,
230
+ + user_spec_len);
231
+ }
232
+
233
+ static memcached_return binary_mget_by_key(memcached_st *ptr,
234
+ @@ -114,19 +139,28 @@ static memcached_return binary_mget_by_key(memcached_st *ptr,
235
+ const char **keys, size_t *key_length,
236
+ size_t number_of_keys);
237
+
238
+ +static bool user_specified_length_is_valid(uint32_t user_spec_len)
239
+ +{
240
+ + assert_on_compile(GET_LEN_ARG_UNSPECIFIED == -1U);
241
+ + return (user_spec_len > 0 && user_spec_len < GET_LEN_ARG_UNSPECIFIED);
242
+ +}
243
+ +
244
+ memcached_return memcached_mget_by_key(memcached_st *ptr,
245
+ const char *master_key,
246
+ size_t master_key_length,
247
+ const char **keys,
248
+ size_t *key_length,
249
+ - size_t number_of_keys)
250
+ + size_t number_of_keys,
251
+ + uint32_t user_spec_len)
252
+ {
253
+ unsigned int x;
254
+ + const char *get_command;
255
+ + uint8_t get_command_length;
256
+ memcached_return rc= MEMCACHED_NOTFOUND;
257
+ - const char *get_command= "get ";
258
+ - uint8_t get_command_length= 4;
259
+ unsigned int master_server_key= (unsigned int)-1; /* 0 is a valid server id! */
260
+ bool is_master_key_set= false;
261
+ + bool use_cas = (ptr->flags & MEM_SUPPORT_CAS);
262
+ + bool length_specified = (user_spec_len != GET_LEN_ARG_UNSPECIFIED);
263
+
264
+ unlikely (ptr->flags & MEM_USE_UDP)
265
+ return MEMCACHED_NOT_SUPPORTED;
266
+ @@ -151,6 +185,14 @@ memcached_return memcached_mget_by_key(memcached_st *ptr,
267
+ is_master_key_set= true;
268
+ }
269
+
270
+ + if (length_specified) {
271
+ + if (ptr->flags & MEM_BINARY_PROTOCOL)
272
+ + return MEMCACHED_NOT_SUPPORTED;
273
+ +
274
+ + if (!user_specified_length_is_valid(user_spec_len))
275
+ + return MEMCACHED_FAILURE;
276
+ + }
277
+ +
278
+ /*
279
+ Here is where we pay for the non-block API. We need to remove any data sitting
280
+ in the queue before we start our get.
281
+ @@ -175,10 +217,24 @@ memcached_return memcached_mget_by_key(memcached_st *ptr,
282
+ return binary_mget_by_key(ptr, master_server_key, is_master_key_set, keys,
283
+ key_length, number_of_keys);
284
+
285
+ - if (ptr->flags & MEM_SUPPORT_CAS)
286
+ - {
287
+ - get_command= "gets ";
288
+ - get_command_length= 5;
289
+ + if (length_specified) {
290
+ + if (use_cas)
291
+ + {
292
+ + get_command= "gets_len ";
293
+ + get_command_length= 9;
294
+ + } else {
295
+ + get_command= "get_len ";
296
+ + get_command_length= 8;
297
+ + }
298
+ + } else {
299
+ + if (use_cas)
300
+ + {
301
+ + get_command= "gets ";
302
+ + get_command_length= 5;
303
+ + } else {
304
+ + get_command= "get ";
305
+ + get_command_length= 4;
306
+ + }
307
+ }
308
+
309
+ /*
310
+ @@ -206,6 +262,17 @@ memcached_return memcached_mget_by_key(memcached_st *ptr,
311
+ rc= MEMCACHED_SOME_ERRORS;
312
+ continue;
313
+ }
314
+ +
315
+ + if (length_specified) {
316
+ + char len[GET_LEN_BUFSZ];
317
+ + if (snprintf(len, GET_LEN_BUFSZ, "%d ", user_spec_len) < 0 ||
318
+ + (memcached_io_write(&ptr->hosts[server_key], len, strlen(len), 0) == -1))
319
+ + {
320
+ + rc= MEMCACHED_SOME_ERRORS;
321
+ + continue;
322
+ + }
323
+ + }
324
+ +
325
+ WATCHPOINT_ASSERT(ptr->hosts[server_key].cursor_active == 0);
326
+ memcached_server_response_increment(&ptr->hosts[server_key]);
327
+ WATCHPOINT_ASSERT(ptr->hosts[server_key].cursor_active == 1);
328
+ diff --git a/libmemcached/memcached_get.h b/libmemcached/memcached_get.h
329
+ --- a/libmemcached-0.32/libmemcached/memcached_get.h
330
+ +++ b/libmemcached/libmemcached/memcached_get.h
331
+ @@ -13,6 +13,9 @@
332
+ extern "C" {
333
+ #endif
334
+
335
+ +#define GET_LEN_ARG_UNSPECIFIED -1U
336
+ +#define GET_LEN_BUFSZ 32
337
+ +
338
+ /* Public defines */
339
+ LIBMEMCACHED_API
340
+ char *memcached_get(memcached_st *ptr,
341
+ @@ -22,14 +25,29 @@ char *memcached_get(memcached_st *ptr,
342
+ memcached_return *error);
343
+
344
+ LIBMEMCACHED_API
345
+ +char *memcached_get_len(memcached_st *ptr,
346
+ + const char *key, size_t key_length,
347
+ + uint32_t user_spec_len,
348
+ + size_t *value_length,
349
+ + uint32_t *flags,
350
+ + memcached_return *error);
351
+ +
352
+ +LIBMEMCACHED_API
353
+ memcached_return memcached_mget(memcached_st *ptr,
354
+ const char **keys, size_t *key_length,
355
+ size_t number_of_keys);
356
+
357
+ LIBMEMCACHED_API
358
+ +memcached_return memcached_mget_len(memcached_st *ptr,
359
+ + const char **keys, size_t *key_length,
360
+ + size_t number_of_keys, uint32_t user_spec_len);
361
+ +
362
+ +LIBMEMCACHED_API
363
+ char *memcached_get_by_key(memcached_st *ptr,
364
+ - const char *master_key, size_t master_key_length,
365
+ - const char *key, size_t key_length,
366
+ + const char *master_key,
367
+ + size_t master_key_length,
368
+ + const char *key, size_t key_length,
369
+ + uint32_t user_spec_len,
370
+ size_t *value_length,
371
+ uint32_t *flags,
372
+ memcached_return *error);
373
+ @@ -40,7 +58,8 @@ memcached_return memcached_mget_by_key(memcached_st *ptr,
374
+ master_key_length,
375
+ const char **keys,
376
+ size_t *key_length,
377
+ - size_t number_of_keys);
378
+ + size_t number_of_keys,
379
+ + uint32_t user_spec_len);
380
+
381
+ LIBMEMCACHED_API
382
+ char *memcached_fetch(memcached_st *ptr,
383
+ diff --git a/tests/function.c b/tests/function.c
384
+ --- a/libmemcached-0.32/tests/function.c
385
+ +++ b/tests/function.c
386
+ @@ -291,9 +291,10 @@ static test_return error_test(memcached_st *memc)
387
+ 334139633U, 2257084983U, 3088286104U, 13199785U, 2542027183U, 1097051614U, 199566778U, 2748246961U, 2465192557U,
388
+ 1664094137U, 2405439045U, 1842224848U, 692413798U, 3479807801U, 919913813U, 4269430871U, 610793021U, 527273862U,
389
+ 1437122909U, 2300930706U, 2943759320U, 674306647U, 2400528935U, 54481931U, 4186304426U, 1741088401U, 2979625118U,
390
+ - 4159057246U, 1769812374U, 2302537950U, 1110330676U };
391
+ + 4159057246U, 1769812374U, 2302537950U, 1110330676U};
392
+
393
+ - assert(MEMCACHED_MAXIMUM_RETURN == 40); // You have updated the memcache_error messages but not updated docs/tests.
394
+ + // You have updated the memcache_error messages but not updated docs/tests.
395
+ + assert(MEMCACHED_SUCCESS == 0 && MEMCACHED_MAXIMUM_RETURN == 40);
396
+ for (rc= MEMCACHED_SUCCESS; rc < MEMCACHED_MAXIMUM_RETURN; rc++)
397
+ {
398
+ uint32_t hash_val;
399
+ @@ -505,6 +506,170 @@ static test_return cas_test(memcached_st *memc)
400
+ return 0;
401
+ }
402
+
403
+ +static test_return mget_len_no_cas_test(memcached_st *memc)
404
+ +{
405
+ + unsigned int x;
406
+ + memcached_return rc;
407
+ + uint32_t number_of_keys = 3;
408
+ + const char *keys[]= {"fudge_for_me", "son_of_bonnie", "food_a_la_carte"};
409
+ + size_t keys_length[]= {12, 13, 15};
410
+ + const unsigned int specified_length = 4;
411
+ +
412
+ + memcached_result_st results_obj;
413
+ + memcached_result_st *results;
414
+ +
415
+ + results= memcached_result_create(memc, &results_obj);
416
+ + assert(results);
417
+ + assert(&results_obj == results);
418
+ +
419
+ + /* We need to empty the server before continuing test */
420
+ + rc= memcached_flush(memc, 0);
421
+ + assert(rc == MEMCACHED_SUCCESS);
422
+ +
423
+ + rc= memcached_mget(memc, keys, keys_length, number_of_keys);
424
+ + assert(rc == MEMCACHED_SUCCESS);
425
+ +
426
+ + while ((results= memcached_fetch_result(memc, &results_obj, &rc)) != NULL)
427
+ + {
428
+ + assert(results);
429
+ + }
430
+ +
431
+ + while ((results= memcached_fetch_result(memc, &results_obj, &rc)) != NULL)
432
+ + assert(!results);
433
+ + assert(rc == MEMCACHED_END);
434
+ +
435
+ + memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, 0);
436
+ +
437
+ + for (x= 0; x < number_of_keys; x++)
438
+ + {
439
+ + rc= memcached_set(memc, keys[x], keys_length[x],
440
+ + keys[x], keys_length[x],
441
+ + (time_t)50, (uint32_t)9);
442
+ + assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
443
+ + }
444
+ +
445
+ + rc= memcached_mget_len(memc, keys, keys_length, number_of_keys, specified_length);
446
+ +
447
+ + if (memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) == 1) {
448
+ + assert(rc == MEMCACHED_NOT_SUPPORTED);
449
+ + return 0;
450
+ + }
451
+ +
452
+ + assert(rc == MEMCACHED_SUCCESS);
453
+ +
454
+ + x = 0;
455
+ + while ((results= memcached_fetch_result(memc, &results_obj, &rc)))
456
+ + {
457
+ + assert(results);
458
+ + assert(&results_obj == results);
459
+ + assert(rc == MEMCACHED_SUCCESS);
460
+ + assert(!memcached_result_cas(results));
461
+ +
462
+ + char *result_str = memcached_result_value(results);
463
+ + assert(strlen(result_str) == specified_length);
464
+ +
465
+ + x++;
466
+ + }
467
+ + assert(x == number_of_keys);
468
+ +
469
+ + memcached_result_free(&results_obj);
470
+ +
471
+ + return 0;
472
+ +}
473
+ +
474
+ +static test_return mget_len_cas_test(memcached_st *memc)
475
+ +{
476
+ + unsigned int x;
477
+ + memcached_return rc;
478
+ + uint32_t number_of_keys = 3;
479
+ + const char *keys[]= {"fudge_for_me", "son_of_bonnie", "food_a_la_carte"};
480
+ + size_t keys_length[]= {12, 13, 15};
481
+ + const unsigned int specified_length = 4;
482
+ + const char *value2= "change the value";
483
+ + size_t value2_length= strlen(value2);
484
+ +
485
+ + memcached_result_st results_obj;
486
+ + memcached_result_st *results;
487
+ +
488
+ + results= memcached_result_create(memc, &results_obj);
489
+ + assert(results);
490
+ + assert(&results_obj == results);
491
+ +
492
+ + /* We need to empty the server before continuing test */
493
+ + rc= memcached_flush(memc, 0);
494
+ + assert(rc == MEMCACHED_SUCCESS);
495
+ +
496
+ + rc= memcached_mget(memc, keys, keys_length, number_of_keys);
497
+ + assert(rc == MEMCACHED_SUCCESS);
498
+ +
499
+ + while ((results= memcached_fetch_result(memc, &results_obj, &rc)) != NULL)
500
+ + {
501
+ + assert(results);
502
+ + }
503
+ +
504
+ + while ((results= memcached_fetch_result(memc, &results_obj, &rc)) != NULL)
505
+ + assert(!results);
506
+ + assert(rc == MEMCACHED_END);
507
+ +
508
+ + memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, 1);
509
+ +
510
+ + for (x= 0; x < number_of_keys; x++)
511
+ + {
512
+ + rc= memcached_set(memc, keys[x], keys_length[x],
513
+ + keys[x], keys_length[x],
514
+ + (time_t)50, (uint32_t)9);
515
+ + assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
516
+ + }
517
+ +
518
+ + rc= memcached_mget_len(memc, keys, keys_length, number_of_keys, specified_length);
519
+ +
520
+ + if (memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) == 1) {
521
+ + assert(rc == MEMCACHED_NOT_SUPPORTED);
522
+ + return 0;
523
+ + }
524
+ +
525
+ + assert(rc == MEMCACHED_SUCCESS);
526
+ +
527
+ + /*
528
+ + * memcached_cas() calls below truncate memcached_fetch_result()'s
529
+ + * results so clone the memcached_st state and move on with life.
530
+ + * This happens when using memcached_mget() and memcached_mget_len().
531
+ + */
532
+ + memcached_st *mclone= memcached_clone(NULL, memc);
533
+ +
534
+ + x = 0;
535
+ + while ((results= memcached_fetch_result(memc, &results_obj, &rc)))
536
+ + {
537
+ + assert(results);
538
+ + assert(&results_obj == results);
539
+ + assert(rc == MEMCACHED_SUCCESS);
540
+ +
541
+ + char *result_str = memcached_result_value(results);
542
+ + assert(strlen(result_str) == specified_length);
543
+ +
544
+ + assert(memcached_result_cas(results));
545
+ +
546
+ + uint64_t cas = memcached_result_cas(results);
547
+ + char *key = memcached_result_key_value(results);
548
+ + uint32_t key_length = memcached_result_key_length(results);
549
+ + rc= memcached_cas(mclone, key, key_length, value2, value2_length, 0, 0, cas);
550
+ +
551
+ + /*
552
+ + * The item will have a new cas value, so try to set it again with the old
553
+ + * value. This should fail!
554
+ + */
555
+ + rc= memcached_cas(mclone, key, key_length, value2, value2_length, 0, 0, cas);
556
+ + assert(rc == MEMCACHED_DATA_EXISTS);
557
+ +
558
+ + x++;
559
+ + }
560
+ + assert(x == number_of_keys);
561
+ +
562
+ + memcached_result_free(&results_obj);
563
+ +
564
+ + return 0;
565
+ +}
566
+ +
567
+ static test_return prepend_test(memcached_st *memc)
568
+ {
569
+ memcached_return rc;
570
+ @@ -706,7 +871,8 @@ static test_return bad_key_test(memcached_st *memc)
571
+ rc= memcached_mget(memc_clone, keys, key_lengths, 3);
572
+ assert(rc == MEMCACHED_BAD_KEY_PROVIDED);
573
+
574
+ - rc= memcached_mget_by_key(memc_clone, "foo daddy", 9, keys, key_lengths, 1);
575
+ + rc= memcached_mget_by_key(memc_clone, "foo daddy", 9, keys, key_lengths,
576
+ + 1, GET_LEN_ARG_UNSPECIFIED);
577
+ assert(rc == MEMCACHED_BAD_KEY_PROVIDED);
578
+
579
+ max_keylen= 250;
580
+ @@ -872,6 +1038,100 @@ static test_return get_test2(memcached_st *memc)
581
+ return 0;
582
+ }
583
+
584
+ +static test_return get_len_test(memcached_st *memc)
585
+ +{
586
+ + memcached_return rc;
587
+ + const char *key= "foo_never_found_thank_you";
588
+ + const uint32_t user_spec_len = 4;
589
+ + char *string;
590
+ + size_t string_length;
591
+ + uint32_t flags;
592
+ +
593
+ + rc= memcached_delete(memc, key, strlen(key), (time_t)0);
594
+ + assert(rc == MEMCACHED_BUFFERED || rc == MEMCACHED_NOTFOUND);
595
+ +
596
+ + string= memcached_get_len(memc, key, strlen(key), user_spec_len,
597
+ + &string_length, &flags, &rc);
598
+ +
599
+ + if (memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) == 1) {
600
+ + assert(rc == MEMCACHED_NOT_SUPPORTED);
601
+ + } else {
602
+ + assert(rc == MEMCACHED_NOTFOUND);
603
+ + assert(string_length == 0);
604
+ + assert(!string);
605
+ + }
606
+ +
607
+ + return 0;
608
+ +}
609
+ +
610
+ +static test_return get_len_test2(memcached_st *memc)
611
+ +{
612
+ + memcached_return rc;
613
+ + const char *key= "foo";
614
+ + const char *value= "when we sanitize";
615
+ + const uint32_t user_spec_len = 6;
616
+ + const char *ret_value= "when w";
617
+ + char *string;
618
+ + size_t string_length;
619
+ + uint32_t flags;
620
+ +
621
+ + rc= memcached_set(memc, key, strlen(key),
622
+ + value, strlen(value),
623
+ + (time_t)0, (uint32_t)0);
624
+ + assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
625
+ +
626
+ + string= memcached_get_len(memc, key, strlen(key), user_spec_len,
627
+ + &string_length, &flags, &rc);
628
+ +
629
+ + if (memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) == 1) {
630
+ + assert(rc == MEMCACHED_NOT_SUPPORTED);
631
+ + } else {
632
+ + assert(string);
633
+ + assert(rc == MEMCACHED_SUCCESS);
634
+ + assert(string_length == strlen(ret_value));
635
+ + assert(!memcmp(string, ret_value, string_length));
636
+ +
637
+ + free(string);
638
+ + }
639
+ +
640
+ + return 0;
641
+ +}
642
+ +
643
+ +static test_return get_len_test3(memcached_st *memc)
644
+ +{
645
+ + memcached_return rc;
646
+ + const char *key= "test";
647
+ + const char *value= "bar";
648
+ + const uint32_t user_spec_len = 2;
649
+ + const char *ret_value= "ba";
650
+ + char *string;
651
+ + size_t string_length;
652
+ + uint32_t flags;
653
+ +
654
+ + rc= memcached_set(memc, key, strlen(key),
655
+ + value, strlen(value),
656
+ + (time_t)0, (uint32_t)0);
657
+ + assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
658
+ +
659
+ + string= memcached_get_len(memc, key, strlen(key), user_spec_len,
660
+ + &string_length, &flags, &rc);
661
+ +
662
+ + if (memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) == 1) {
663
+ + assert(rc == MEMCACHED_NOT_SUPPORTED);
664
+ + } else {
665
+ + assert(string);
666
+ + assert(rc == MEMCACHED_SUCCESS);
667
+ + assert(string_length == strlen(ret_value));
668
+ + assert(!memcmp(string, ret_value, string_length));
669
+ +
670
+ + free(string);
671
+ + }
672
+ +
673
+ + return 0;
674
+ +}
675
+ +
676
+ +
677
+ +
678
+ static test_return set_test2(memcached_st *memc)
679
+ {
680
+ memcached_return rc;
681
+ @@ -1031,6 +1291,7 @@ static test_return get_test5(memcached_st *memc)
682
+ assert(rc == MEMCACHED_SUCCESS);
683
+
684
+ char *val= memcached_get_by_key(memc, keys[0], lengths[0], "yek", 3,
685
+ + GET_LEN_ARG_UNSPECIFIED,
686
+ &rlen, &flags, &rc);
687
+ assert(val == NULL);
688
+ assert(rc == MEMCACHED_NOTFOUND);
689
+ @@ -1225,6 +1486,80 @@ static test_return mget_result_test(memcached_st *memc)
690
+ return 0;
691
+ }
692
+
693
+ +static test_return mget_len_result_test(memcached_st *memc)
694
+ +{
695
+ + memcached_return rc;
696
+ + uint32_t number_of_keys = 3;
697
+ + const char *keys[]= {"fudge_for_me", "son_of_bonnie", "food_a_la_carte"};
698
+ + size_t key_length[]= {12, 13, 15};
699
+ + const unsigned int specified_length = 4;
700
+ + const char *expected_results[]= {"fudg", "son_", "food"};
701
+ + unsigned int x;
702
+ +
703
+ + memcached_result_st results_obj;
704
+ + memcached_result_st *results;
705
+ +
706
+ + results= memcached_result_create(memc, &results_obj);
707
+ + assert(results);
708
+ + assert(&results_obj == results);
709
+ +
710
+ + /* We need to empty the server before continueing test */
711
+ + rc= memcached_flush(memc, 0);
712
+ + assert(rc == MEMCACHED_SUCCESS);
713
+ +
714
+ + rc= memcached_mget(memc, keys, key_length, number_of_keys);
715
+ + assert(rc == MEMCACHED_SUCCESS);
716
+ +
717
+ + while ((results= memcached_fetch_result(memc, &results_obj, &rc)) != NULL)
718
+ + {
719
+ + assert(results);
720
+ + }
721
+ +
722
+ + while ((results= memcached_fetch_result(memc, &results_obj, &rc)) != NULL)
723
+ + assert(!results);
724
+ + assert(rc == MEMCACHED_END);
725
+ +
726
+ + for (x= 0; x < number_of_keys; x++)
727
+ + {
728
+ + rc= memcached_set(memc, keys[x], key_length[x],
729
+ + keys[x], key_length[x],
730
+ + (time_t)50, (uint32_t)9);
731
+ + assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
732
+ + }
733
+ +
734
+ + rc= memcached_mget_len(memc, keys, key_length, number_of_keys, specified_length);
735
+ +
736
+ + if (memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) == 1) {
737
+ + assert(rc == MEMCACHED_NOT_SUPPORTED);
738
+ + return 0;
739
+ + }
740
+ +
741
+ + assert(rc == MEMCACHED_SUCCESS);
742
+ +
743
+ + x = 0;
744
+ + while ((results= memcached_fetch_result(memc, &results_obj, &rc)))
745
+ + {
746
+ + char *result_str = memcached_result_value(results);
747
+ + size_t str_len = strlen(result_str);
748
+ + assert(results);
749
+ + assert(&results_obj == results);
750
+ + assert(rc == MEMCACHED_SUCCESS);
751
+ + assert(str_len == specified_length);
752
+ + assert(strlen(expected_results[0]) == specified_length);
753
+ + assert(strlen(expected_results[1]) == specified_length);
754
+ + assert(strlen(expected_results[2]) == specified_length);
755
+ + assert((memcmp(result_str, expected_results[0], specified_length) == 0) ||
756
+ + (memcmp(result_str, expected_results[1], specified_length) == 0) ||
757
+ + (memcmp(result_str, expected_results[2], specified_length) == 0));
758
+ + x++;
759
+ + }
760
+ + assert(x == number_of_keys);
761
+ +
762
+ + memcached_result_free(&results_obj);
763
+ +
764
+ + return 0;
765
+ +}
766
+ +
767
+ static test_return mget_result_alloc_test(memcached_st *memc)
768
+ {
769
+ memcached_return rc;
770
+ @@ -3633,6 +3968,7 @@ static test_return replication_set_test(memcached_st *memc)
771
+ size_t len;
772
+ uint32_t flags;
773
+ char *val= memcached_get_by_key(memc_clone, key, 1, "bubba", 5,
774
+ + GET_LEN_ARG_UNSPECIFIED,
775
+ &len, &flags, &rc);
776
+ assert(rc == MEMCACHED_SUCCESS);
777
+ assert(val != NULL);
778
+ @@ -3664,6 +4000,7 @@ static test_return replication_get_test(memcached_st *memc)
779
+ size_t len;
780
+ uint32_t flags;
781
+ char *val= memcached_get_by_key(memc_clone, key, 1, "bubba", 5,
782
+ + GET_LEN_ARG_UNSPECIFIED,
783
+ &len, &flags, &rc);
784
+ assert(rc == MEMCACHED_SUCCESS);
785
+ assert(val != NULL);
786
+ @@ -3721,7 +4058,8 @@ static test_return replication_mget_test(memcached_st *memc)
787
+ {
788
+ const char key[2]= { [0]= (const char)x };
789
+
790
+ - rc= memcached_mget_by_key(new_clone, key, 1, keys, len, 4);
791
+ + rc= memcached_mget_by_key(new_clone, key, 1, keys, len,
792
+ + 4, GET_LEN_ARG_UNSPECIFIED);
793
+ assert(rc == MEMCACHED_SUCCESS);
794
+
795
+ memcached_result_st *results= memcached_result_create(new_clone, &result_obj);
796
+ @@ -3782,7 +4120,8 @@ static test_return replication_delete_test(memcached_st *memc)
797
+ {
798
+ const char key[2]= { [0]= (const char)x };
799
+
800
+ - rc= memcached_mget_by_key(memc_clone, key, 1, keys, len, 4);
801
+ + rc= memcached_mget_by_key(memc_clone, key, 1, keys, len,
802
+ + 4, GET_LEN_ARG_UNSPECIFIED);
803
+ assert(rc == MEMCACHED_SUCCESS);
804
+
805
+ memcached_result_st *results= memcached_result_create(memc_clone, &result_obj);
806
+ @@ -4437,6 +4776,9 @@ test_st tests[] ={
807
+ {"get3", 0, get_test3 },
808
+ {"get4", 0, get_test4 },
809
+ {"partial mget", 0, get_test5 },
810
+ + {"get_len", 1, get_len_test },
811
+ + {"get_len2", 0, get_len_test2 },
812
+ + {"get_len3", 0, get_len_test3 },
813
+ {"stats_servername", 0, stats_servername_test },
814
+ {"increment", 0, increment_test },
815
+ {"increment_with_initial", 1, increment_with_initial_test },
816
+ @@ -4445,6 +4787,7 @@ test_st tests[] ={
817
+ {"quit", 0, quit_test },
818
+ {"mget", 1, mget_test },
819
+ {"mget_result", 1, mget_result_test },
820
+ + {"mget_len_result", 1, mget_len_result_test },
821
+ {"mget_result_alloc", 1, mget_result_alloc_test },
822
+ {"mget_result_function", 1, mget_result_function },
823
+ {"get_stats", 0, get_stats },
824
+ @@ -4492,6 +4835,8 @@ test_st version_1_2_3[] ={
825
+ {"prepend", 0, prepend_test },
826
+ {"cas", 0, cas_test },
827
+ {"cas2", 0, cas2_test },
828
+ + {"mget_len_no_cas", 0, mget_len_no_cas_test },
829
+ + {"mget_len_cas", 0, mget_len_cas_test },
830
+ {"append_binary", 0, append_binary_test },
831
+ {0, 0, 0}
832
+ };