e7e87f262006b0ed7f04bdccc93e61c806ceaf42
[m6w6/libmemcached] / libtest / memcached.cc
1 /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
2 *
3 * Libmemcached library
4 *
5 * Copyright (C) 2011 Data Differential, http://datadifferential.com/
6 * Copyright (C) 2006-2009 Brian Aker All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met:
11 *
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * * Redistributions in binary form must reproduce the above
16 * copyright notice, this list of conditions and the following disclaimer
17 * in the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * * The names of its contributors may not be used to endorse or
21 * promote products derived from this software without specific prior
22 * written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 *
36 */
37
38
39 /*
40 Startup, and shutdown the memcached servers.
41 */
42
43 #define TEST_PORT_BASE MEMCACHED_DEFAULT_PORT+10
44
45 #include <libtest/common.h>
46
47 #include <cassert>
48 #include <cerrno>
49 #include <cstdio>
50 #include <cstdlib>
51 #include <cstring>
52 #include <ctime>
53 #include <limits.h>
54 #include <signal.h>
55 #include <sys/time.h>
56 #include <unistd.h>
57 #include <iostream>
58
59 #include <libmemcached/memcached.h>
60 #include <libmemcached/util.h>
61
62 #include <libtest/server.h>
63 #include <libtest/killpid.h>
64 #include <libtest/wait.h>
65
66 #include <boost/lexical_cast.hpp>
67
68
69 #define CERR_PREFIX std::endl << __FILE__ << ":" << __LINE__ << " "
70
71 static void global_sleep(void)
72 {
73 static struct timespec global_sleep_value= { 0, 50000 };
74
75 #ifdef WIN32
76 sleep(1);
77 #else
78 nanosleep(&global_sleep_value, NULL);
79 #endif
80 }
81
82 #define SOCKET_FILE "/tmp/memcached.socket"
83
84 static bool cycle_server(server_st& server)
85 {
86 while (1)
87 {
88 if (libmemcached_util_ping(server.hostname, server.port(), NULL))
89 {
90 // First we try to kill it, and on fail of that we flush it.
91 pid_t pid= libmemcached_util_getpid(server.hostname, server.port(), NULL);
92
93 if (pid > 0 and kill_pid(pid))
94 {
95 std::cerr << CERR_PREFIX << "Killed existing server," << server << " with pid:" << pid << std::endl;
96 continue;
97 }
98 else if (libmemcached_util_flush(server.hostname, server.port(), NULL)) // If we can flush it, we will just use it
99 {
100 std::cerr << CERR_PREFIX << "Found server on port " << int(server.port()) << ", flushed it!" << std::endl;
101 server.set_used();
102 return true;
103 } // No idea what is wrong here, so we need to find a different port
104 else
105 {
106 return false;
107 }
108 }
109
110 break;
111 }
112
113 return true;
114 }
115
116 bool server_startup(server_startup_st *construct)
117 {
118 if (getenv(((char *)"MEMCACHED_SERVERS")))
119 {
120 construct->server_list= getenv(((char *)"MEMCACHED_SERVERS"));
121 printf("servers %s\n", construct->server_list.c_str());
122 construct->count= 0;
123 }
124 else
125 {
126 std::string server_config_string;
127
128 uint32_t port_base= 0;
129 for (uint32_t x= 0; x < (construct->count -1); x++)
130 {
131 server_st &server= construct->server[x];
132
133 {
134 char *var;
135 char variable_buffer[1024];
136
137 snprintf(variable_buffer, sizeof(variable_buffer), "LIBMEMCACHED_PORT_%u", x);
138
139 if ((var= getenv(variable_buffer)))
140 {
141 server.set_port((in_port_t)atoi(var));
142 }
143 else
144 {
145 server.set_port(in_port_t(x + TEST_PORT_BASE + port_base));
146
147 while (not cycle_server(server))
148 {
149 std::cerr << CERR_PREFIX << "Found server " << server << ", could not flush it, so trying next port." << std::endl;
150 port_base++;
151 server.set_port(in_port_t(x + TEST_PORT_BASE + port_base));
152 }
153 }
154 }
155
156 if (server.is_used())
157 {
158 std::cerr << std::endl << "Using server at : " << server << std::endl;
159 }
160 else
161 {
162 char buffer[FILENAME_MAX];
163 if (x == 0)
164 {
165 snprintf(buffer, sizeof(buffer), "%s -d -t 1 -p %u -U %u -m 128",
166 MEMCACHED_BINARY, server.port(), server.port());
167 }
168 else
169 {
170 snprintf(buffer, sizeof(buffer), "%s -d -t 1 -p %u -U %u",
171 MEMCACHED_BINARY, server.port(), server.port());
172 }
173
174 int status= system(buffer);
175 if (status == -1)
176 {
177 std::cerr << CERR_PREFIX << "Failed system(" << buffer << ")" << std::endl;
178 return false;
179 }
180 fprintf(stderr, "STARTING SERVER: %s\n", buffer);
181
182 int count= 30;
183 memcached_return_t rc;
184 while (not libmemcached_util_ping(server.hostname, server.port(), &rc) and --count)
185 {
186 global_sleep();
187 }
188
189 if (memcached_failed(rc))
190 {
191 std::cerr << CERR_PREFIX << "libmemcached_util_ping() failed:" << memcached_strerror(NULL, rc) << " Connection:" << server << std::endl;
192 return false;
193 }
194
195 server.set_pid(libmemcached_util_getpid(server.hostname, server.port(), &rc));
196 if (not server.has_pid())
197 {
198 std::cerr << CERR_PREFIX << "libmemcached_util_getpid() failed" << memcached_strerror(NULL, rc) << " Connection: " << server << std::endl;
199 return false;
200 }
201 }
202
203 server_config_string+= "--server=";
204 server_config_string+= server.hostname;
205 server_config_string+= ":";
206 server_config_string+= boost::lexical_cast<std::string>(server.port());
207 server_config_string+= " ";
208 fprintf(stderr, " Port %d\n", server.port());
209 }
210
211 {
212 server_st &server= construct->server[construct->count -1];
213
214 {
215 std::string socket_file;
216 char *var;
217
218 server.set_hostname(SOCKET_FILE);
219
220 if ((var= getenv("LIBMEMCACHED_SOCKET")))
221 {
222 socket_file+= var;
223 }
224 else
225 {
226 if (not cycle_server(server))
227 {
228 std::cerr << CERR_PREFIX << "Found server " << server << ", could not flush it, so trying next port." << std::endl;
229 return false;
230 }
231 }
232 }
233
234 if (server.is_used())
235 {
236 std::cerr << std::endl << "Using server at : " << server << std::endl;
237 }
238 else
239 {
240 char buffer[FILENAME_MAX];
241 snprintf(buffer, sizeof(buffer), "%s -d -t 1 -s %s", MEMCACHED_BINARY, SOCKET_FILE);
242
243 int status= system(buffer);
244 if (status == -1)
245 {
246 std::cerr << CERR_PREFIX << "Failed system(" << buffer << ")" << std::endl;
247 return false;
248 }
249 fprintf(stderr, "STARTING SERVER: %s\n", buffer);
250
251 int count= 30;
252 memcached_return_t rc;
253 while (not libmemcached_util_ping(server.hostname, server.port(), &rc) and --count)
254 {
255 global_sleep();
256 }
257
258 if (memcached_failed(rc))
259 {
260 std::cerr << CERR_PREFIX << "libmemcached_util_ping() failed:" << memcached_strerror(NULL, rc) << " Connection:" << server << std::endl;
261 return false;
262 }
263
264 server.set_pid(libmemcached_util_getpid(server.hostname, server.port(), &rc));
265 if (not server.has_pid())
266 {
267 std::cerr << CERR_PREFIX << "libmemcached_util_getpid() failed" << memcached_strerror(NULL, rc) << " Connection: " << server << std::endl;
268 return false;
269 }
270 }
271
272 {
273 set_default_socket(server.hostname);
274 server_config_string+= "--socket=\"";
275 server_config_string+= server.hostname;
276 server_config_string+= "\" ";
277 }
278 }
279
280 server_config_string.resize(server_config_string.size() -1); // Remove final space
281 construct->server_list= server_config_string;
282 }
283
284 srandom((unsigned int)time(NULL));
285
286 std::cerr << std::endl;
287 return true;
288 }
289
290 void server_shutdown(server_startup_st *construct)
291 {
292 for (uint32_t x= 0; x < construct->count; x++)
293 {
294 if (construct->server[x].is_used())
295 continue;
296
297 construct->server[x].kill();
298 }
299 }