Merge in pid/ping status.
[awesomized/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 #define SOCKET_FILE "/tmp/memcached.socket"
72
73 static pid_t __getpid(server_st& server)
74 {
75 memcached_return_t rc;
76 pid_t pid= libmemcached_util_getpid(server.hostname, server.port(), &rc);
77 return pid;
78 }
79
80 static bool __ping(server_st& server)
81 {
82 memcached_return_t rc;
83 bool ret= libmemcached_util_ping(server.hostname, server.port(), &rc);
84 return ret;
85 }
86
87 static bool cycle_server(server_st& server)
88 {
89 while (1)
90 {
91 if (libmemcached_util_ping(server.hostname, server.port(), NULL))
92 {
93 // First we try to kill it, and on fail of that we flush it.
94 pid_t pid= libmemcached_util_getpid(server.hostname, server.port(), NULL);
95
96 if (pid > 0 and kill_pid(pid))
97 {
98 std::cerr << CERR_PREFIX << "Killed existing server," << server << " with pid:" << pid << std::endl;
99 continue;
100 }
101 else if (libmemcached_util_flush(server.hostname, server.port(), NULL)) // If we can flush it, we will just use it
102 {
103 std::cerr << CERR_PREFIX << "Found server on port " << int(server.port()) << ", flushed it!" << std::endl;
104 server.set_used();
105 return true;
106 } // No idea what is wrong here, so we need to find a different port
107 else
108 {
109 return false;
110 }
111 }
112
113 break;
114 }
115
116 return true;
117 }
118
119 bool server_startup(server_startup_st *construct)
120 {
121 if (getenv(((char *)"MEMCACHED_SERVERS")))
122 {
123 construct->server_list= getenv(((char *)"MEMCACHED_SERVERS"));
124 printf("servers %s\n", construct->server_list.c_str());
125 construct->count= 0;
126 }
127 else
128 {
129 for (uint32_t x= 0; x < construct->count; x++)
130 {
131 server_st &server= construct->server[x];
132 server.set_methods(__getpid, __ping);
133 }
134
135 std::string server_config_string;
136
137 uint32_t port_base= 0;
138 for (uint32_t x= 0; x < (construct->count -1); x++)
139 {
140 server_st &server= construct->server[x];
141
142 {
143 char *var;
144 char variable_buffer[1024];
145
146 snprintf(variable_buffer, sizeof(variable_buffer), "LIBMEMCACHED_PORT_%u", x);
147
148 if ((var= getenv(variable_buffer)))
149 {
150 server.set_port((in_port_t)atoi(var));
151 }
152 else
153 {
154 server.set_port(in_port_t(x + TEST_PORT_BASE + port_base));
155
156 while (not cycle_server(server))
157 {
158 std::cerr << CERR_PREFIX << "Found server " << server << ", could not flush it, so trying next port." << std::endl;
159 port_base++;
160 server.set_port(in_port_t(x + TEST_PORT_BASE + port_base));
161 }
162 }
163 }
164
165 if (server.is_used())
166 {
167 std::cerr << std::endl << "Using server at : " << server << std::endl;
168 }
169 else
170 {
171 char buffer[FILENAME_MAX];
172 if (x == 0)
173 {
174 snprintf(buffer, sizeof(buffer), "%s -d -t 1 -p %u -U %u -m 128",
175 MEMCACHED_BINARY, server.port(), server.port());
176 }
177 else
178 {
179 snprintf(buffer, sizeof(buffer), "%s -d -t 1 -p %u -U %u",
180 MEMCACHED_BINARY, server.port(), server.port());
181 }
182 server.set_command(buffer);
183
184 if (not server.start())
185 {
186 std::cerr << CERR_PREFIX << "Failed system(" << buffer << ")" << std::endl;
187 return false;
188 }
189 std::cerr << "STARTING SERVER: " << buffer << " pid:" << server.pid() << std::endl;
190 }
191
192 server_config_string+= "--server=";
193 server_config_string+= server.hostname;
194 server_config_string+= ":";
195 server_config_string+= boost::lexical_cast<std::string>(server.port());
196 server_config_string+= " ";
197 }
198
199 // Socket
200 {
201 server_st &server= construct->server[construct->count -1];
202
203 {
204 std::string socket_file;
205 char *var;
206
207 server.set_hostname(SOCKET_FILE);
208
209 if ((var= getenv("LIBMEMCACHED_SOCKET")))
210 {
211 socket_file+= var;
212 }
213 else
214 {
215 if (not cycle_server(server))
216 {
217 std::cerr << CERR_PREFIX << "Found server " << server << ", could not flush it, failing since socket file is not available." << std::endl;
218 return false;
219 }
220 }
221 }
222
223 if (server.is_used())
224 {
225 std::cerr << std::endl << "Using server at : " << server << std::endl;
226 }
227 else
228 {
229 char buffer[FILENAME_MAX];
230 snprintf(buffer, sizeof(buffer), "%s -d -t 1 -s %s", MEMCACHED_BINARY, SOCKET_FILE);
231 server.set_command(buffer);
232
233 if (not server.start())
234 {
235 std::cerr << CERR_PREFIX << "Failed system(" << buffer << ")" << std::endl;
236 return false;
237 }
238 std::cerr << "STARTING SERVER: " << buffer << " pid:" << server.pid() << std::endl;
239 }
240
241 {
242 set_default_socket(server.hostname);
243 server_config_string+= "--socket=\"";
244 server_config_string+= server.hostname;
245 server_config_string+= "\" ";
246 }
247 }
248
249 server_config_string.resize(server_config_string.size() -1); // Remove final space
250 construct->server_list= server_config_string;
251 }
252
253 srandom((unsigned int)time(NULL));
254
255 std::cerr << std::endl;
256 return true;
257 }
258
259 void server_shutdown(server_startup_st *construct)
260 {
261 for (uint32_t x= 0; x < construct->count; x++)
262 {
263 if (construct->server[x].is_used())
264 continue;
265
266 construct->server[x].kill();
267 }
268 }