Merge in all changes related to being able to read configuration files.
[awesomized/libmemcached] / libtest / server.c
1 /* LibMemcached
2 * Copyright (C) 2006-2009 Brian Aker
3 * All rights reserved.
4 *
5 * Use and distribution licensed under the BSD license. See
6 * the COPYING file in the parent directory for full text.
7 *
8 * Summary:
9 *
10 */
11
12 /*
13 Startup, and shutdown the memcached servers.
14 */
15
16 #define TEST_PORT_BASE MEMCACHED_DEFAULT_PORT+10
17
18 #define PID_FILE_BASE "/tmp/%ulibmemcached_memc.pid"
19
20 #include "config.h"
21
22 #include <assert.h>
23 #include <limits.h>
24 #include <signal.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/time.h>
29 #include <time.h>
30 #include <unistd.h>
31
32 #include <libmemcached/memcached.h>
33 #include <libmemcached/util.h>
34
35 #include <libtest/server.h>
36
37 static struct timespec global_sleep_value= { .tv_sec= 0, .tv_nsec= 50000 };
38
39 static void global_sleep(void)
40 {
41 #ifdef WIN32
42 sleep(1);
43 #else
44 nanosleep(&global_sleep_value, NULL);
45 #endif
46 }
47
48 static void kill_file(const char *file_buffer)
49 {
50 FILE *fp;
51
52 while ((fp= fopen(file_buffer, "r")))
53 {
54 char pid_buffer[1024];
55
56 if (fgets(pid_buffer, sizeof(pid_buffer), fp) != NULL)
57 {
58 pid_t pid= (pid_t)atoi(pid_buffer);
59 if (pid != 0)
60 {
61 if (kill(pid, SIGTERM) == -1)
62 {
63 remove(file_buffer); // If this happens we may be dealing with a dead server that left its pid file.
64 }
65 else
66 {
67 uint32_t counter= 3;
68 while ((kill(pid, 0) == 0) && --counter)
69 {
70 global_sleep();
71 }
72 }
73 }
74 }
75
76 global_sleep();
77
78 fclose(fp);
79 }
80 }
81
82 void server_startup(server_startup_st *construct)
83 {
84 if ((construct->server_list= getenv("MEMCACHED_SERVERS")))
85 {
86 printf("servers %s\n", construct->server_list);
87 construct->servers= memcached_servers_parse(construct->server_list);
88 construct->server_list= NULL;
89 construct->count= 0;
90 }
91 else
92 {
93 {
94 char server_string_buffer[8096];
95 char *end_ptr;
96 end_ptr= server_string_buffer;
97
98 for (uint32_t x= 0; x < construct->count; x++)
99 {
100 int status;
101 in_port_t port;
102
103 {
104 char *var;
105 char variable_buffer[1024];
106
107 snprintf(variable_buffer, sizeof(variable_buffer), "LIBMEMCACHED_PORT_%u", x);
108
109 if ((var= getenv(variable_buffer)))
110 {
111 port= (in_port_t)atoi(var);
112 }
113 else
114 {
115 port= (in_port_t)(x + TEST_PORT_BASE);
116 }
117 }
118
119 char buffer[PATH_MAX];
120 snprintf(buffer, sizeof(buffer), PID_FILE_BASE, x);
121 kill_file(buffer);
122
123 if (x == 0)
124 {
125 snprintf(buffer, sizeof(buffer), "%s -d -u root -P "PID_FILE_BASE" -t 1 -p %u -U %u -m 128",
126 MEMCACHED_BINARY, x, port, port);
127 }
128 else
129 {
130 snprintf(buffer, sizeof(buffer), "%s -d -u root -P "PID_FILE_BASE" -t 1 -p %u -U %u",
131 MEMCACHED_BINARY, x, port, port);
132 }
133 if (libmemcached_util_ping("localhost", port, NULL))
134 {
135 fprintf(stderr, "Server on port %u already exists\n", port);
136 }
137 else
138 {
139 status= system(buffer);
140 fprintf(stderr, "STARTING SERVER: %s status:%d\n", buffer, status);
141 }
142 int count;
143 size_t remaining_length= sizeof(server_string_buffer) - (size_t)(end_ptr -server_string_buffer);
144 count= snprintf(end_ptr, remaining_length, "localhost:%u,", port);
145
146 if ((size_t)count >= remaining_length || count < 0)
147 {
148 fprintf(stderr, "server names grew to be larger then buffer allowed\n");
149 abort();
150 }
151 end_ptr+= count;
152 }
153 *end_ptr= 0;
154
155
156 int *pids= calloc(construct->count, sizeof(int));
157 for (uint32_t x= 0; x < construct->count; x++)
158 {
159 char buffer[PATH_MAX]; /* Nothing special for number */
160
161 snprintf(buffer, sizeof(buffer), PID_FILE_BASE, x);
162
163 uint32_t counter= 3000; // Absurd, just to catch run away process
164 while (pids[x] <= 0 && --counter)
165 {
166 FILE *file= fopen(buffer, "r");
167 if (file)
168 {
169 char pid_buffer[1024];
170 char *found= fgets(pid_buffer, sizeof(pid_buffer), file);
171
172 if (found)
173 {
174 pids[x]= atoi(pid_buffer);
175 fclose(file);
176
177 if (pids[x] > 0)
178 break;
179 }
180 fclose(file);
181 }
182 global_sleep();
183 }
184
185 bool was_started= false;
186 if (pids[x] > 0)
187 {
188 counter= 30;
189 while (--counter)
190 {
191 if (kill(pids[x], 0) == 0)
192 {
193 was_started= true;
194 break;
195 }
196 global_sleep();
197 }
198 }
199
200 if (was_started == false)
201 {
202 fprintf(stderr, "Failed to open buffer %s(%d)\n", buffer, pids[x]);
203 for (uint32_t y= 0; y < construct->count; y++)
204 {
205 if (pids[y] > 0)
206 kill(pids[y], SIGTERM);
207 }
208 abort();
209 }
210 }
211 free(pids);
212
213 construct->server_list= strdup(server_string_buffer);
214 }
215 printf("servers %s\n", construct->server_list);
216 construct->servers= memcached_servers_parse(construct->server_list);
217 }
218
219 assert(construct->servers);
220
221 srandom((unsigned int)time(NULL));
222
223 for (uint32_t x= 0; x < memcached_server_list_count(construct->servers); x++)
224 {
225 printf("\t%s : %d\n", memcached_server_name(&construct->servers[x]), memcached_server_port(&construct->servers[x]));
226 assert(construct->servers[x].fd == -1);
227 assert(construct->servers[x].cursor_active == 0);
228 }
229
230 printf("\n");
231 }
232
233 void server_shutdown(server_startup_st *construct)
234 {
235 if (construct->server_list)
236 {
237 for (uint32_t x= 0; x < construct->count; x++)
238 {
239 char file_buffer[PATH_MAX]; /* Nothing special for number */
240 snprintf(file_buffer, sizeof(file_buffer), PID_FILE_BASE, x);
241 kill_file(file_buffer);
242 }
243
244 free(construct->server_list);
245 }
246 }