ee94c945007c2ad2887091843db0a79d0e907cf2
[m6w6/libmemcached] / libtest / server.cc
1 /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
2 *
3 * libtest
4 *
5 * Copyright (C) 2011 Data Differential, http://datadifferential.com/
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 3 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22
23 #include <libtest/common.h>
24
25 #include <cassert>
26 #include <cerrno>
27 #include <cstdlib>
28 #include <iostream>
29
30 #include <algorithm>
31 #include <functional>
32 #include <locale>
33
34 // trim from end
35 static inline std::string &rtrim(std::string &s)
36 {
37 s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
38 return s;
39 }
40
41 #include <libtest/server.h>
42 #include <libtest/stream.h>
43 #include <libtest/killpid.h>
44
45 extern "C" {
46 static bool exited_successfully(int status)
47 {
48 if (WEXITSTATUS(status) == 0)
49 {
50 return true;
51 }
52
53 return true;
54 }
55 }
56
57
58 namespace libtest {
59
60 std::ostream& operator<<(std::ostream& output, const Server &arg)
61 {
62 if (arg.is_socket())
63 {
64 output << arg.hostname();
65 }
66 else
67 {
68 output << arg.hostname() << ":" << arg.port();
69 }
70
71 if (arg.has_pid())
72 {
73 output << " Pid:" << arg.pid();
74 }
75
76 if (arg.has_socket())
77 {
78 output << " Socket:" << arg.socket();
79 }
80
81 if (not arg.running().empty())
82 {
83 output << " Exec:" << arg.running();
84 }
85
86
87 return output; // for multiple << operators
88 }
89
90 void Server::nap(void)
91 {
92 #ifdef WIN32
93 sleep(1);
94 #else
95 struct timespec global_sleep_value= { 0, 50000 };
96 nanosleep(&global_sleep_value, NULL);
97 #endif
98 }
99
100 Server::Server(const std::string& host_arg, const in_port_t port_arg, bool is_socket_arg) :
101 _is_socket(is_socket_arg),
102 _pid(-1),
103 _port(port_arg),
104 _hostname(host_arg)
105 {
106 }
107
108 Server::~Server()
109 {
110 if (has_pid() and not kill(_pid))
111 {
112 Error << "Unable to kill:" << *this;
113 }
114 }
115
116 std::string server_startup_st::option_string() const
117 {
118 std::string temp= server_list;
119 rtrim(temp);
120 return temp;
121 }
122
123 // If the server exists, kill it
124 bool Server::cycle()
125 {
126 uint32_t limit= 3;
127
128 // Try to ping, and kill the server #limit number of times
129 pid_t current_pid;
130 while (--limit and (current_pid= get_pid()) != -1)
131 {
132 if (kill(current_pid))
133 {
134 Log << "Killed existing server," << *this << " with pid:" << current_pid;
135 nap();
136 continue;
137 }
138 }
139
140 // For whatever reason we could not kill it, and we reached limit
141 if (limit == 0)
142 {
143 Error << "Reached limit, could not kill server pid:" << current_pid;
144 return false;
145 }
146
147 return true;
148 }
149
150 // Grab a one off command
151 bool Server::command(std::string& command_arg)
152 {
153 rebuild_base_command();
154
155 command_arg+= _base_command;
156
157 if (args(command_arg))
158 {
159 return true;
160 }
161
162 return false;
163 }
164
165 bool Server::start()
166 {
167 // If we find that we already have a pid then kill it.
168 if (has_pid() and not kill(_pid))
169 {
170 Error << "Could not kill() existing server during start() pid:" << _pid;
171 return false;
172 }
173 assert(not has_pid());
174
175 _running.clear();
176 if (not command(_running))
177 {
178 Error << "Could not build command()";
179 return false;
180 }
181
182 if (is_valgrind() or is_helgrind())
183 {
184 _running+= " &";
185 }
186
187 int ret= system(_running.c_str());
188 if (not exited_successfully(ret))
189 {
190 Error << "system() failed:" << strerror(errno);
191 _running.clear();
192 return false;
193 }
194
195 if (is_helgrind())
196 {
197 sleep(4);
198 }
199
200 if (pid_file_option() and not pid_file().empty())
201 {
202 Wait wait(pid_file());
203
204 if (not wait.successful())
205 {
206 Error << "Unable to open pidfile: " << pid_file();
207 }
208 }
209
210 int count= is_helgrind() ? 20 : 5;
211 while (not ping() and --count)
212 {
213 nap();
214 }
215
216 if (count == 0)
217 {
218 Error << "Failed to ping() server once started:" << *this;
219 _running.clear();
220 return false;
221 }
222
223 // A failing get_pid() at this point is considered an error
224 _pid= get_pid(true);
225
226 return has_pid();
227 }
228
229 void Server::reset_pid()
230 {
231 _running.clear();
232 _pid_file.clear();
233 _pid= -1;
234 }
235
236 pid_t Server::pid()
237 {
238 return _pid;
239 }
240
241 bool Server::set_socket_file()
242 {
243 char file_buffer[FILENAME_MAX];
244 file_buffer[0]= 0;
245
246 if (broken_pid_file())
247 {
248 snprintf(file_buffer, sizeof(file_buffer), "/tmp/%s.socketXXXXXX", name());
249 }
250 else
251 {
252 snprintf(file_buffer, sizeof(file_buffer), "var/run/%s.socketXXXXXX", name());
253 }
254
255 int fd;
256 if ((fd= mkstemp(file_buffer)) == -1)
257 {
258 perror(file_buffer);
259 return false;
260 }
261 close(fd);
262 unlink(file_buffer);
263
264 _socket= file_buffer;
265
266 return true;
267 }
268
269 bool Server::set_pid_file()
270 {
271 char file_buffer[FILENAME_MAX];
272 file_buffer[0]= 0;
273
274 if (broken_pid_file())
275 {
276 snprintf(file_buffer, sizeof(file_buffer), "/tmp/%s.pidXXXXXX", name());
277 }
278 else
279 {
280 snprintf(file_buffer, sizeof(file_buffer), "var/run/%s.pidXXXXXX", name());
281 }
282
283 int fd;
284 if ((fd= mkstemp(file_buffer)) == -1)
285 {
286 perror(file_buffer);
287 return false;
288 }
289 close(fd);
290 unlink(file_buffer);
291
292 _pid_file= file_buffer;
293
294 return true;
295 }
296
297 bool Server::set_log_file()
298 {
299 char file_buffer[FILENAME_MAX];
300 file_buffer[0]= 0;
301
302 snprintf(file_buffer, sizeof(file_buffer), "var/log/%s.logXXXXXX", name());
303 int fd;
304 if ((fd= mkstemp(file_buffer)) == -1)
305 {
306 perror(file_buffer);
307 return false;
308 }
309 close(fd);
310
311 _log_file= file_buffer;
312
313 return true;
314 }
315
316 void Server::rebuild_base_command()
317 {
318 _base_command.clear();
319 if (is_libtool() and getenv("LIBTOOL_COMMAND"))
320 {
321 _base_command+= getenv("LIBTOOL_COMMAND");
322 _base_command+= " ";
323 }
324
325 if (is_debug() and getenv("GDB_COMMAND"))
326 {
327 _base_command+= getenv("GDB_COMMAND");
328 _base_command+= " ";
329 }
330 else if (is_valgrind() and getenv("VALGRIND_COMMAND"))
331 {
332 _base_command+= getenv("VALGRIND_COMMAND");
333 _base_command+= " ";
334 }
335 else if (is_helgrind() and getenv("HELGRIND_COMMAND"))
336 {
337 _base_command+= getenv("HELGRIND_COMMAND");
338 _base_command+= " ";
339 }
340
341 _base_command+= executable();
342 }
343
344 void Server::set_extra_args(const std::string &arg)
345 {
346 _extra_args= arg;
347 }
348
349 bool Server::args(std::string& options)
350 {
351 std::stringstream arg_buffer;
352
353 // Set a log file if it was requested (and we can)
354 if (getenv("LIBTEST_LOG") and log_file_option())
355 {
356 if (not set_log_file())
357 {
358 return false;
359 }
360
361 arg_buffer << " " << log_file_option() << _log_file;
362 }
363
364 // Update pid_file
365 if (pid_file_option())
366 {
367 if (not set_pid_file())
368 {
369 return false;
370 }
371
372 arg_buffer << " " << pid_file_option() << pid_file();
373 }
374
375 assert(daemon_file_option());
376 if (daemon_file_option() and not is_valgrind() and not is_helgrind())
377 {
378 arg_buffer << " " << daemon_file_option();
379 }
380
381 if (_is_socket and socket_file_option())
382 {
383 if (not set_socket_file())
384 {
385 return false;
386 }
387
388 arg_buffer << " " << socket_file_option() << "\"" << _socket << "\"";
389 }
390
391 assert(port_option());
392 if (port_option() and _port > 0)
393 {
394 arg_buffer << " " << port_option() << _port;
395 }
396
397 options+= arg_buffer.str();
398
399 if (not _extra_args.empty())
400 {
401 options+= _extra_args;
402 }
403
404 return true;
405 }
406
407 bool Server::is_debug() const
408 {
409 return bool(getenv("LIBTEST_MANUAL_GDB"));
410 }
411
412 bool Server::is_valgrind() const
413 {
414 return bool(getenv("LIBTEST_MANUAL_VALGRIND"));
415 }
416
417 bool Server::is_helgrind() const
418 {
419 return bool(getenv("LIBTEST_MANUAL_HELGRIND"));
420 }
421
422 bool Server::kill(pid_t pid_arg)
423 {
424 if (check_pid(pid_arg) and kill_pid(pid_arg)) // If we kill it, reset
425 {
426 if (broken_pid_file() and not pid_file().empty())
427 {
428 unlink(pid_file().c_str());
429 }
430
431 if (broken_socket_cleanup() and has_socket() and not socket().empty())
432 {
433 unlink(socket().c_str());
434 }
435
436 reset_pid();
437
438 return true;
439 }
440
441 return false;
442 }
443
444 void server_startup_st::push_server(Server *arg)
445 {
446 servers.push_back(arg);
447
448 char port_str[NI_MAXSERV];
449 snprintf(port_str, sizeof(port_str), "%u", int(arg->port()));
450
451 std::string server_config_string;
452 if (arg->has_socket())
453 {
454 server_config_string+= "--socket=";
455 server_config_string+= '"';
456 server_config_string+= arg->socket();
457 server_config_string+= '"';
458 server_config_string+= " ";
459 }
460 else
461 {
462 server_config_string+= "--server=";
463 server_config_string+= arg->hostname();
464 server_config_string+= ":";
465 server_config_string+= port_str;
466 server_config_string+= " ";
467 }
468
469 server_list+= server_config_string;
470
471 }
472
473 Server* server_startup_st::pop_server()
474 {
475 Server *tmp= servers.back();
476 servers.pop_back();
477 return tmp;
478 }
479
480 void server_startup_st::shutdown(bool remove)
481 {
482 if (remove)
483 {
484 for (std::vector<Server *>::iterator iter= servers.begin(); iter != servers.end(); iter++)
485 {
486 delete *iter;
487 }
488 servers.clear();
489 }
490 else
491 {
492 for (std::vector<Server *>::iterator iter= servers.begin(); iter != servers.end(); iter++)
493 {
494 if ((*iter)->has_pid() and not (*iter)->kill((*iter)->pid()))
495 {
496 Error << "Unable to kill:" << *(*iter);
497 }
498 }
499 }
500 }
501
502 server_startup_st::~server_startup_st()
503 {
504 shutdown(true);
505 }
506
507 bool server_startup_st::is_debug() const
508 {
509 return bool(getenv("LIBTEST_MANUAL_GDB"));
510 }
511
512 bool server_startup_st::is_valgrind() const
513 {
514 return bool(getenv("LIBTEST_MANUAL_VALGRIND"));
515 }
516
517 bool server_startup_st::is_helgrind() const
518 {
519 return bool(getenv("LIBTEST_MANUAL_HELGRIND"));
520 }
521
522
523 bool server_startup(server_startup_st& construct, const std::string& server_type, in_port_t try_port, int argc, const char *argv[])
524 {
525 Outn();
526 (void)try_port;
527
528 // Look to see if we are being provided ports to use
529 {
530 char variable_buffer[1024];
531 snprintf(variable_buffer, sizeof(variable_buffer), "LIBTEST_PORT_%lu", (unsigned long)construct.count());
532
533 char *var;
534 if ((var= getenv(variable_buffer)))
535 {
536 in_port_t tmp= in_port_t(atoi(var));
537
538 if (tmp > 0)
539 try_port= tmp;
540 }
541 }
542
543 libtest::Server *server= NULL;
544 if (0)
545 { }
546 else if (server_type.compare("gearmand") == 0)
547 {
548 if (GEARMAND_BINARY)
549 {
550 if (HAVE_LIBGEARMAN)
551 {
552 server= build_gearmand("localhost", try_port);
553 }
554 else
555 {
556 Error << "Libgearman was not found";
557 }
558 }
559 else
560 {
561 Error << "No gearmand binary is available";
562 }
563 }
564 else if (server_type.compare("blobslap_worker") == 0)
565 {
566 if (GEARMAND_BINARY)
567 {
568 if (HAVE_LIBGEARMAN)
569 {
570 server= build_blobslap_worker(try_port);
571 }
572 else
573 {
574 Error << "Libgearman was not found";
575 }
576 }
577 else
578 {
579 Error << "No gearmand binary is available";
580 }
581 }
582 else if (server_type.compare("memcached") == 0)
583 {
584 if (MEMCACHED_BINARY)
585 {
586 if (HAVE_LIBMEMCACHED)
587 {
588 server= build_memcached("localhost", try_port);
589 }
590 else
591 {
592 Error << "Libmemcached was not found";
593 }
594 }
595 else
596 {
597 Error << "No memcached binary is available";
598 }
599 }
600 else
601 {
602 Error << "Failed to start " << server_type << ", no support was found to be compiled in for it.";
603 }
604
605 if (server == NULL)
606 {
607 Error << "Failure occured while creating server: " << server_type;
608 return false;
609 }
610
611 /*
612 We will now cycle the server we have created.
613 */
614 if (not server->cycle())
615 {
616 Error << "Could not start up server " << *server;
617 delete server;
618 return false;
619 }
620
621 server->build(argc, argv);
622
623 if (construct.is_debug())
624 {
625 Out << "Pausing for startup, hit return when ready.";
626 std::string gdb_command= server->base_command();
627 std::string options;
628 Out << "run " << server->args(options);
629 getchar();
630 }
631 else if (not server->start())
632 {
633 Error << "Failed to start " << *server;
634 delete server;
635 return false;
636 }
637 else
638 {
639 Out << "STARTING SERVER(pid:" << server->pid() << "): " << server->running();
640 }
641
642 construct.push_server(server);
643
644 if (default_port() == 0)
645 {
646 assert(server->has_port());
647 set_default_port(server->port());
648 }
649
650 Outn();
651
652 return true;
653 }
654
655 bool server_startup_st::start_socket_server(const std::string& server_type, const in_port_t try_port, int argc, const char *argv[])
656 {
657 (void)try_port;
658 Outn();
659
660 Server *server= NULL;
661 if (0)
662 { }
663 else if (server_type.compare("gearmand") == 0)
664 {
665 Error << "Socket files are not supported for gearmand yet";
666 }
667 else if (server_type.compare("memcached") == 0)
668 {
669 if (MEMCACHED_BINARY)
670 {
671 if (HAVE_LIBMEMCACHED)
672 {
673 server= build_memcached_socket("localhost", try_port);
674 }
675 else
676 {
677 Error << "Libmemcached was not found";
678 }
679 }
680 else
681 {
682 Error << "No memcached binary is available";
683 }
684 }
685 else
686 {
687 Error << "Failed to start " << server_type << ", no support was found to be compiled in for it.";
688 }
689
690 if (server == NULL)
691 {
692 Error << "Failure occured while creating server: " << server_type;
693 return false;
694 }
695
696 /*
697 We will now cycle the server we have created.
698 */
699 if (not server->cycle())
700 {
701 Error << "Could not start up server " << *server;
702 delete server;
703 return false;
704 }
705
706 server->build(argc, argv);
707
708 if (is_debug())
709 {
710 Out << "Pausing for startup, hit return when ready.";
711 std::string gdb_command= server->base_command();
712 std::string options;
713 Out << "run " << server->args(options);
714 getchar();
715 }
716 else if (not server->start())
717 {
718 Error << "Failed to start " << *server;
719 delete server;
720 return false;
721 }
722 else
723 {
724 Out << "STARTING SERVER(pid:" << server->pid() << "): " << server->running();
725 }
726
727 push_server(server);
728
729 set_default_socket(server->socket().c_str());
730
731 Outn();
732
733 return true;
734 }
735
736 } // namespace libtest