2 +--------------------------------------------------------------------+
3 | libmemcached - C/C++ Client Library for memcached |
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted under the terms of the BSD license. |
7 | You should have received a copy of the license in a bundled file |
8 | named LICENSE; in case you did not receive a copy you can review |
9 | the terms online at: https://opensource.org/licenses/BSD-3-Clause |
10 +--------------------------------------------------------------------+
11 | Copyright (c) 2006-2014 Brian Aker https://datadifferential.com/ |
12 | Copyright (c) 2020 Michael Wallner <mike@php.net> |
13 +--------------------------------------------------------------------+
16 #include "libmemcached/common.h"
18 static memcached_return_t
meta_touch(memcached_instance_st
*instance
, const char *key
, size_t key_len
, time_t expiration
) {
19 char ex_buf
[32] = " T";
20 size_t ex_len
= strlen(ex_buf
);
22 ex_len
+= snprintf(ex_buf
+ ex_len
, sizeof(ex_buf
) - ex_len
, "%lu", (unsigned long) expiration
);
24 libmemcached_io_vector_st io_vec
[] = {
25 {memcached_literal_param("mg ")},
26 {memcached_array_string(instance
->root
->_namespace
),
27 memcached_array_size(instance
->root
->_namespace
)},
30 {memcached_literal_param("\r\n")}
33 memcached_return_t rc
;
34 if (memcached_failed(rc
= memcached_vdo(instance
, io_vec
, 5, true))) {
35 return memcached_set_error(*instance
, MEMCACHED_WRITE_FAILURE
, MEMCACHED_AT
);
41 static memcached_return_t
ascii_touch(memcached_instance_st
*instance
, const char *key
,
42 size_t key_length
, time_t expiration
) {
43 char expiration_buffer
[MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH
+ 1];
44 int expiration_buffer_length
= snprintf(expiration_buffer
, sizeof(expiration_buffer
), " %llu",
45 (unsigned long long) expiration
);
46 if (size_t(expiration_buffer_length
) >= sizeof(expiration_buffer
) + 1
47 or expiration_buffer_length
< 0)
49 return memcached_set_error(
50 *instance
, MEMCACHED_MEMORY_ALLOCATION_FAILURE
, MEMCACHED_AT
,
51 memcached_literal_param("snprintf(MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH)"));
54 libmemcached_io_vector_st vector
[] = {{NULL
, 0},
55 {memcached_literal_param("touch ")},
56 {memcached_array_string(instance
->root
->_namespace
),
57 memcached_array_size(instance
->root
->_namespace
)},
59 {expiration_buffer
, size_t(expiration_buffer_length
)},
60 {memcached_literal_param("\r\n")}};
62 memcached_return_t rc
;
63 if (memcached_failed(rc
= memcached_vdo(instance
, vector
, 6, true))) {
64 return memcached_set_error(*instance
, MEMCACHED_WRITE_FAILURE
, MEMCACHED_AT
);
70 static memcached_return_t
binary_touch(memcached_instance_st
*instance
, const char *key
,
71 size_t key_length
, time_t expiration
) {
72 protocol_binary_request_touch request
= {}; //{.bytes= {0}};
74 initialize_binary_request(instance
, request
.message
.header
);
76 request
.message
.header
.request
.opcode
= PROTOCOL_BINARY_CMD_TOUCH
;
77 request
.message
.header
.request
.extlen
= 4;
78 request
.message
.header
.request
.keylen
=
79 htons((uint16_t)(key_length
+ memcached_array_size(instance
->root
->_namespace
)));
80 request
.message
.header
.request
.datatype
= PROTOCOL_BINARY_RAW_BYTES
;
81 request
.message
.header
.request
.bodylen
=
82 htonl((uint32_t)(key_length
+ memcached_array_size(instance
->root
->_namespace
)
83 + request
.message
.header
.request
.extlen
));
84 request
.message
.body
.expiration
= htonl((uint32_t) expiration
);
86 libmemcached_io_vector_st vector
[] = {{NULL
, 0},
87 {request
.bytes
, sizeof(request
.bytes
)},
88 {memcached_array_string(instance
->root
->_namespace
),
89 memcached_array_size(instance
->root
->_namespace
)},
92 memcached_return_t rc
;
93 if (memcached_failed(rc
= memcached_vdo(instance
, vector
, 4, true))) {
94 return memcached_set_error(*instance
, MEMCACHED_WRITE_FAILURE
, MEMCACHED_AT
);
100 memcached_return_t
memcached_touch(memcached_st
*ptr
, const char *key
, size_t key_length
,
102 return memcached_touch_by_key(ptr
, key
, key_length
, key
, key_length
, expiration
);
105 memcached_return_t
memcached_touch_by_key(memcached_st
*shell
, const char *group_key
,
106 size_t group_key_length
, const char *key
,
107 size_t key_length
, time_t expiration
) {
108 Memcached
*ptr
= memcached2Memcached(shell
);
109 LIBMEMCACHED_MEMCACHED_TOUCH_START();
111 memcached_return_t rc
;
112 if (memcached_failed(rc
= initialize_query(ptr
, true))) {
116 if (memcached_failed(rc
= memcached_key_test(*ptr
, (const char **) &key
, &key_length
, 1))) {
117 return memcached_set_error(*ptr
, rc
, MEMCACHED_AT
);
120 uint32_t server_key
=
121 memcached_generate_hash_with_redistribution(ptr
, group_key
, group_key_length
);
122 memcached_instance_st
*instance
= memcached_instance_fetch(ptr
, server_key
);
124 if (memcached_is_binary(ptr
)) {
125 rc
= binary_touch(instance
, key
, key_length
, expiration
);
126 } else if (memcached_is_meta(ptr
)) {
127 rc
= meta_touch(instance
, key
, key_length
, expiration
);
129 rc
= ascii_touch(instance
, key
, key_length
, expiration
);
132 if (memcached_failed(rc
)) {
133 return memcached_set_error(
134 *instance
, rc
, MEMCACHED_AT
,
135 memcached_literal_param("Error occcured while writing touch command to server"));
138 char buffer
[MEMCACHED_DEFAULT_COMMAND_SIZE
];
139 rc
= memcached_response(instance
, buffer
, sizeof(buffer
), NULL
);
141 if (rc
== MEMCACHED_SUCCESS
or rc
== MEMCACHED_NOTFOUND
) {
145 return memcached_set_error(*instance
, rc
, MEMCACHED_AT
,
146 memcached_literal_param("Error occcured while reading response"));