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