Adding custom IOSTREAM for libtest.
[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 Log;
115 if (getenv(((char *)"MEMCACHED_SERVERS")))
116 {
117 construct->server_list= getenv(((char *)"MEMCACHED_SERVERS"));
118 Log << "MEMCACHED_SERVERS " << construct->server_list;
119 construct->count= 0;
120 }
121 else
122 {
123 std::string server_config_string;
124
125 uint32_t port_base= 0;
126 for (uint32_t x= 0; x < (construct->count -1); x++)
127 {
128 server_st *server= NULL;
129
130 {
131 char *var;
132 char variable_buffer[1024];
133
134 snprintf(variable_buffer, sizeof(variable_buffer), "LIBMEMCACHED_PORT_%u", x);
135
136 if ((var= getenv(variable_buffer)))
137 {
138 server= new server_st((in_port_t)atoi(var), __getpid, __ping);
139 }
140 else
141 {
142 server= new server_st(in_port_t(x +TEST_PORT_BASE +port_base), __getpid, __ping);
143
144 while (not cycle_server(server))
145 {
146 Error << "Found server " << *server << ", could not flush it, so trying next port.";
147 port_base++;
148 server->set_port(in_port_t(x +TEST_PORT_BASE +port_base));
149 }
150 }
151 }
152
153 if (server->is_used())
154 {
155 Log << "Using server at : " << server;
156 }
157 else
158 {
159 char buffer[FILENAME_MAX];
160 if (x == 0)
161 {
162 snprintf(buffer, sizeof(buffer), "%s -d -t 1 -p %u -U %u -m 128",
163 MEMCACHED_BINARY, server->port(), server->port());
164 }
165 else
166 {
167 snprintf(buffer, sizeof(buffer), "%s -d -t 1 -p %u -U %u",
168 MEMCACHED_BINARY, server->port(), server->port());
169 }
170 server->set_command(buffer);
171
172 if (not server->start())
173 {
174 Error << "Failed system(" << buffer << ")";
175 delete server;
176 return false;
177 }
178 Log << "STARTING SERVER: " << buffer << " pid:" << server->pid();
179 }
180 construct->push_server(server);
181
182 if (x == 0)
183 {
184 assert(server->has_port());
185 set_default_port(server->port());
186 }
187
188 char port_str[NI_MAXSERV];
189 snprintf(port_str, sizeof(port_str), "%u", int(server->port()));
190
191 server_config_string+= "--server=";
192 server_config_string+= server->hostname();
193 server_config_string+= ":";
194 server_config_string+= port_str;
195 server_config_string+= " ";
196 }
197
198 // Socket
199 {
200
201 std::string socket_file(SOCKET_FILE);
202 char *var;
203
204 if ((var= getenv("LIBMEMCACHED_SOCKET")))
205 {
206 socket_file= var;
207 }
208
209 server_st *server= new server_st(SOCKET_FILE, __getpid, __ping);
210
211 if (not cycle_server(server))
212 {
213 Error << "Found server " << server << ", could not flush it, failing since socket file is not available.";
214 return false;
215 }
216
217 if (server->is_used())
218 {
219 Log << "Using server at : " << *server;
220 }
221 else
222 {
223 char buffer[FILENAME_MAX];
224 snprintf(buffer, sizeof(buffer), "%s -d -t 1 -s %s", MEMCACHED_BINARY, SOCKET_FILE);
225 server->set_command(buffer);
226
227 if (not server->start())
228 {
229 Error << "Failed system(" << buffer << ")";
230 delete server;
231 return false;
232 }
233 Log << "STARTING SERVER: " << buffer << " pid:" << server->pid();
234 }
235 set_default_socket(server->hostname());
236 construct->push_server(server);
237
238 {
239 server_config_string+= "--socket=\"";
240 server_config_string+= server->hostname();
241 server_config_string+= "\" ";
242 }
243 }
244
245 server_config_string.resize(server_config_string.size() -1); // Remove final space
246 construct->server_list= server_config_string;
247 }
248
249 Log;
250
251 srandom((unsigned int)time(NULL));
252
253 return true;
254 }
255
256 void server_shutdown(server_startup_st *construct)
257 {
258 if (not construct)
259 return;
260
261 construct->shutdown();
262 }