More tests, and new code for append/prepend.
[awesomized/libmemcached] / lib / memcached_storage.c
1 /*
2 Memcached library
3
4 memcached_set()
5 memcached_replace()
6 memcached_add()
7
8 */
9
10 #include "common.h"
11 #include "memcached_io.h"
12
13 typedef enum {
14 SET_OP,
15 REPLACE_OP,
16 ADD_OP,
17 PREPEND_OP,
18 APPEND_OP,
19 CAS_OP,
20 } memcached_storage_action;
21
22 /* Inline this */
23 char *storage_op_string(memcached_storage_action verb)
24 {
25 switch (verb)
26 {
27 case SET_OP:
28 return "set";
29 case REPLACE_OP:
30 return "replace";
31 case ADD_OP:
32 return "add";
33 case PREPEND_OP:
34 return "prepend";
35 case APPEND_OP:
36 return "append";
37 case CAS_OP:
38 return "cas";
39 };
40
41 return SET_OP;
42 }
43
44 static inline memcached_return memcached_send(memcached_st *ptr,
45 char *key, size_t key_length,
46 char *value, size_t value_length,
47 time_t expiration,
48 uint16_t flags,
49 uint64_t cas,
50 memcached_storage_action verb)
51 {
52 char to_write;
53 size_t write_length;
54 ssize_t sent_length;
55 memcached_return rc;
56 char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
57 unsigned int server_key;
58
59 WATCHPOINT_ASSERT(value);
60 WATCHPOINT_ASSERT(value_length);
61
62 if (key_length == 0)
63 return MEMCACHED_NO_KEY_PROVIDED;
64
65 /* Leaving this WATCHPOINT_ASSERT in since only a library fubar could blow this */
66 #ifdef NOT_DONE
67 if (!(ptr->flags & MEM_NO_BLOCK) && ptr->write_buffer_offset != 0)
68 WATCHPOINT_ASSERT(0);
69 #endif
70
71 if (ptr->hosts == NULL || ptr->number_of_hosts == 0)
72 return MEMCACHED_NO_SERVERS;
73
74 server_key= memcached_generate_hash(ptr, key, key_length);
75
76 rc= memcached_connect(ptr, server_key);
77 if (rc != MEMCACHED_SUCCESS)
78 return rc;
79
80
81 if (cas)
82 write_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
83 "%s %.*s %u %llu %zu\r\n", storage_op_string(verb),
84 (int)key_length, key, flags,
85 (unsigned long long)expiration, value_length);
86 else
87 write_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
88 "%s %.*s %u %llu %zu %llu\r\n", storage_op_string(verb),
89 (int)key_length, key, flags,
90 (unsigned long long)expiration, value_length,
91 (unsigned long long)cas);
92
93 if (write_length >= MEMCACHED_DEFAULT_COMMAND_SIZE)
94 {
95 rc= MEMCACHED_WRITE_FAILURE;
96 goto error;
97 }
98
99 /*
100 We have to flush after sending the command. Memcached is not smart enough
101 to just keep reading from the socket :(
102 */
103 if ((sent_length= memcached_io_write(ptr, server_key, buffer, write_length, 0)) == -1)
104 {
105 rc= MEMCACHED_WRITE_FAILURE;
106 goto error;
107 }
108
109 if ((sent_length= memcached_io_write(ptr, server_key, value, value_length, 0)) == -1)
110 {
111 rc= MEMCACHED_WRITE_FAILURE;
112 goto error;
113 }
114
115 if ((ptr->flags & MEM_NO_BLOCK) && verb == SET_OP)
116 to_write= 0;
117 else
118 to_write= 1;
119
120 if ((sent_length= memcached_io_write(ptr, server_key, "\r\n", 2, to_write)) == -1)
121 {
122 memcached_quit_server(ptr, server_key);
123 rc= MEMCACHED_WRITE_FAILURE;
124 goto error;
125 }
126
127 if ((ptr->flags & MEM_NO_BLOCK) && verb == SET_OP)
128 {
129 rc= MEMCACHED_SUCCESS;
130 memcached_server_response_increment(ptr, server_key);
131 }
132 else
133 {
134 rc= memcached_response(ptr, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, server_key);
135 }
136 if (rc == MEMCACHED_STORED)
137 return MEMCACHED_SUCCESS;
138 else
139 return rc;
140
141 error:
142 memcached_io_reset(ptr, server_key);
143
144 return rc;
145 }
146
147 memcached_return memcached_set(memcached_st *ptr, char *key, size_t key_length,
148 char *value, size_t value_length,
149 time_t expiration,
150 uint16_t flags)
151 {
152 memcached_return rc;
153 LIBMEMCACHED_MEMCACHED_SET_START();
154 rc= memcached_send(ptr, key, key_length, value, value_length,
155 expiration, flags, 0, SET_OP);
156 LIBMEMCACHED_MEMCACHED_SET_END();
157 return rc;
158 }
159
160 memcached_return memcached_add(memcached_st *ptr,
161 char *key, size_t key_length,
162 char *value, size_t value_length,
163 time_t expiration,
164 uint16_t flags)
165 {
166 memcached_return rc;
167 LIBMEMCACHED_MEMCACHED_ADD_START();
168 rc= memcached_send(ptr, key, key_length, value, value_length,
169 expiration, flags, 0, ADD_OP);
170 LIBMEMCACHED_MEMCACHED_ADD_END();
171 return rc;
172 }
173
174 memcached_return memcached_replace(memcached_st *ptr,
175 char *key, size_t key_length,
176 char *value, size_t value_length,
177 time_t expiration,
178 uint16_t flags)
179 {
180 memcached_return rc;
181 LIBMEMCACHED_MEMCACHED_REPLACE_START();
182 rc= memcached_send(ptr, key, key_length, value, value_length,
183 expiration, flags, 0, REPLACE_OP);
184 LIBMEMCACHED_MEMCACHED_REPLACE_END();
185 return rc;
186 }
187
188 memcached_return memcached_prepend(memcached_st *ptr,
189 char *key, size_t key_length,
190 char *value, size_t value_length,
191 time_t expiration,
192 uint16_t flags)
193 {
194 memcached_return rc;
195 rc= memcached_send(ptr, key, key_length, value, value_length,
196 expiration, flags, 0, PREPEND_OP);
197 return rc;
198 }
199
200 memcached_return memcached_append(memcached_st *ptr,
201 char *key, size_t key_length,
202 char *value, size_t value_length,
203 time_t expiration,
204 uint16_t flags)
205 {
206 memcached_return rc;
207 rc= memcached_send(ptr, key, key_length, value, value_length,
208 expiration, flags, 0, APPEND_OP);
209 return rc;
210 }
211
212 memcached_return memcached_cas(memcached_st *ptr,
213 char *key, size_t key_length,
214 char *value, size_t value_length,
215 time_t expiration,
216 uint16_t flags,
217 uint64_t cas)
218 {
219 memcached_return rc;
220 rc= memcached_send(ptr, key, key_length, value, value_length,
221 expiration, flags, cas, APPEND_OP);
222 return rc;
223 }