Next pass through the framework. Also removing boost files since we don't use them...
[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 #define CERR_PREFIX std::endl << __FILE__ << ":" << __LINE__ << " "
67
68 #define SOCKET_FILE "/tmp/memcached.socket"
69
70 static pid_t __getpid(server_st& server)
71 {
72 memcached_return_t rc;
73 pid_t pid= libmemcached_util_getpid(server.hostname(), server.port(), &rc);
74 return pid;
75 }
76
77 static bool __ping(server_st& server)
78 {
79 memcached_return_t rc;
80 bool ret= libmemcached_util_ping(server.hostname(), server.port(), &rc);
81 return ret;
82 }
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= NULL;
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= new server_st((in_port_t)atoi(var), __getpid, __ping);
142 }
143 else
144 {
145 server= new server_st(in_port_t(x +TEST_PORT_BASE +port_base), __getpid, __ping);
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 server->set_command(buffer);
174
175 if (not server->start())
176 {
177 std::cerr << CERR_PREFIX << "Failed system(" << buffer << ")" << std::endl;
178 delete server;
179 return false;
180 }
181 std::cerr << "STARTING SERVER: " << buffer << " pid:" << server->pid() << std::endl;
182 }
183 construct->push_server(server);
184
185 if (x == 0)
186 {
187 assert(server->has_port());
188 set_default_port(server->port());
189 }
190
191 char port_str[NI_MAXSERV];
192 snprintf(port_str, sizeof(port_str), "%u", int(server->port()));
193
194 server_config_string+= "--server=";
195 server_config_string+= server->hostname();
196 server_config_string+= ":";
197 server_config_string+= port_str;
198 server_config_string+= " ";
199 }
200
201 // Socket
202 {
203
204 std::string socket_file(SOCKET_FILE);
205 char *var;
206
207 if ((var= getenv("LIBMEMCACHED_SOCKET")))
208 {
209 socket_file= var;
210 }
211
212 server_st *server= new server_st(SOCKET_FILE, __getpid, __ping);
213
214 if (not cycle_server(server))
215 {
216 std::cerr << CERR_PREFIX << "Found server " << server << ", could not flush it, failing since socket file is not available." << std::endl;
217 return false;
218 }
219
220 if (server->is_used())
221 {
222 std::cerr << std::endl << "Using server at : " << *server << std::endl;
223 }
224 else
225 {
226 char buffer[FILENAME_MAX];
227 snprintf(buffer, sizeof(buffer), "%s -d -t 1 -s %s", MEMCACHED_BINARY, SOCKET_FILE);
228 server->set_command(buffer);
229
230 if (not server->start())
231 {
232 std::cerr << CERR_PREFIX << "Failed system(" << buffer << ")" << std::endl;
233 delete server;
234 return false;
235 }
236 std::cerr << "STARTING SERVER: " << buffer << " pid:" << server->pid() << std::endl;
237 }
238 set_default_socket(server->hostname());
239 construct->push_server(server);
240
241 {
242 server_config_string+= "--socket=\"";
243 server_config_string+= server->hostname();
244 server_config_string+= "\" ";
245 }
246 }
247
248 server_config_string.resize(server_config_string.size() -1); // Remove final space
249 construct->server_list= server_config_string;
250 }
251
252 srandom((unsigned int)time(NULL));
253
254 std::cerr << std::endl;
255 return true;
256 }
257
258 void server_shutdown(server_startup_st *construct)
259 {
260 if (not construct)
261 return;
262
263 construct->shutdown();
264 }