1 /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
5 * Copyright (C) 2011 Data Differential, http://datadifferential.com/
6 * Copyright (C) 2006-2009 Brian Aker All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
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
20 * * The names of its contributors may not be used to endorse or
21 * promote products derived from this software without specific prior
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.
40 Startup, and shutdown the memcached servers.
43 #define TEST_PORT_BASE MEMCACHED_DEFAULT_PORT+10
60 #include <libmemcached/memcached.h>
61 #include <libmemcached/util.h>
63 #include <libtest/server.h>
65 static struct timespec global_sleep_value
= { .tv_sec
= 0, .tv_nsec
= 50000 };
67 static void global_sleep(void)
72 nanosleep(&global_sleep_value
, NULL
);
76 static bool wait_for_file(const char *filename
)
83 for (waited
= 0, retry
= 1; ; retry
++, waited
+= this_wait
)
85 if ((! access(filename
, R_OK
)) || (waited
>= timeout
))
90 this_wait
= retry
* retry
/ 3 + 1;
97 static void kill_file(const char *file_buffer
)
101 while ((fp
= fopen(file_buffer
, "r")))
103 char pid_buffer
[1024];
105 if (fgets(pid_buffer
, sizeof(pid_buffer
), fp
) != NULL
)
107 pid_t pid
= (pid_t
)atoi(pid_buffer
);
110 if (kill(pid
, SIGTERM
) == -1)
112 remove(file_buffer
); // If this happens we may be dealing with a dead server that left its pid file.
117 while ((kill(pid
, 0) == 0) && --counter
)
131 void server_startup(server_startup_st
*construct
)
133 if ((construct
->server_list
= getenv("MEMCACHED_SERVERS")))
135 printf("servers %s\n", construct
->server_list
);
136 construct
->servers
= memcached_servers_parse(construct
->server_list
);
137 construct
->server_list
= NULL
;
143 char server_string_buffer
[8096];
145 end_ptr
= server_string_buffer
;
147 uint32_t port_base
= 0;
148 for (uint32_t x
= 0; x
< construct
->count
; x
++)
152 snprintf(construct
->pid_file
[x
], FILENAME_MAX
, "/tmp/memcached.pidXXXXXX");
154 if ((fd
= mkstemp(construct
->pid_file
[x
])) == -1)
163 char variable_buffer
[1024];
165 snprintf(variable_buffer
, sizeof(variable_buffer
), "LIBMEMCACHED_PORT_%u", x
);
167 if ((var
= getenv(variable_buffer
)))
169 construct
->port
[x
]= (in_port_t
)atoi(var
);
174 construct
->port
[x
]= (in_port_t
)(x
+ TEST_PORT_BASE
+ port_base
);
176 if (libmemcached_util_ping("localhost", construct
->port
[x
], NULL
))
178 if (libmemcached_util_flush("localhost", construct
->port
[x
], NULL
))
180 fprintf(stderr
, "Found server on port %d, flushed it!\n", (int)construct
->port
[x
]);
181 construct
->is_used
[x
]= true;
182 } // If we can flush it, we will just use it
185 fprintf(stderr
, "Found server on port %d, could not flush it, so trying next port.\n", (int)construct
->port
[x
]);
187 construct
->port
[x
]= 0;
190 } while (construct
->port
[x
] == 0);
194 char buffer
[FILENAME_MAX
];
197 snprintf(buffer
, sizeof(buffer
), "%s -d -P %s -t 1 -p %u -U %u -m 128",
198 MEMCACHED_BINARY
, construct
->pid_file
[x
], construct
->port
[x
], construct
->port
[x
]);
202 snprintf(buffer
, sizeof(buffer
), "%s -d -P %s -t 1 -p %u -U %u",
203 MEMCACHED_BINARY
, construct
->pid_file
[x
], construct
->port
[x
], construct
->port
[x
]);
206 if (construct
->is_used
[x
])
208 fprintf(stderr
, "USING SERVER: %s\n", buffer
);
212 if (libmemcached_util_ping("localhost", construct
->port
[x
], NULL
))
214 fprintf(stderr
, "Server on port %u already exists\n", construct
->port
[x
]);
218 status
= system(buffer
);
219 fprintf(stderr
, "STARTING SERVER: %s status:%d\n", buffer
, status
);
224 size_t remaining_length
= sizeof(server_string_buffer
) - (size_t)(end_ptr
-server_string_buffer
);
225 count
= snprintf(end_ptr
, remaining_length
, "localhost:%u,", construct
->port
[x
]);
227 if ((size_t)count
>= remaining_length
|| count
< 0)
229 fprintf(stderr
, "server names grew to be larger then buffer allowed\n");
237 for (uint32_t x
= 0; x
< construct
->count
; x
++)
239 if (! wait_for_file(construct
->pid_file
[x
]))
245 for (uint32_t x
= 0; x
< construct
->count
; x
++)
247 uint32_t counter
= 3000; // Absurd, just to catch run away process
249 if (construct
->is_used
[x
])
252 while (construct
->pids
[x
] <= 0 && --counter
)
254 FILE *file
= fopen(construct
->pid_file
[x
], "r");
257 char pid_buffer
[1024];
258 char *found
= fgets(pid_buffer
, sizeof(pid_buffer
), file
);
262 construct
->pids
[x
]= atoi(pid_buffer
);
265 if (construct
->pids
[x
] > 0)
274 fprintf(stderr
, "Could not open pid file %s -> fopen(%s) -> %s:%d\n", construct
->pid_file
[x
], strerror(errno
), __FILE__
, __LINE__
);
287 // Safety 3rd, check to see if the file has gone away
288 if (! wait_for_file(construct
->pid_file
[x
]))
294 bool was_started
= false;
295 if (construct
->pids
[x
] > 0)
300 if (kill(construct
->pids
[x
], 0) == 0)
309 if (was_started
== false)
311 fprintf(stderr
, "Failed to open buffer %s(%d)\n", construct
->pid_file
[x
], construct
->pids
[x
]);
312 for (uint32_t y
= 0; y
< construct
->count
; y
++)
314 if (construct
->pids
[y
] > 0)
315 kill(construct
->pids
[y
], SIGTERM
);
321 construct
->server_list
= strdup(server_string_buffer
);
323 printf("servers %s\n", construct
->server_list
);
324 construct
->servers
= memcached_servers_parse(construct
->server_list
);
327 assert(construct
->servers
);
329 srandom((unsigned int)time(NULL
));
331 for (uint32_t x
= 0; x
< memcached_server_list_count(construct
->servers
); x
++)
333 printf("\t%s : %d\n", memcached_server_name(&construct
->servers
[x
]), memcached_server_port(&construct
->servers
[x
]));
334 assert(construct
->servers
[x
].fd
== -1);
335 assert(construct
->servers
[x
].cursor_active
== 0);
341 void server_shutdown(server_startup_st
*construct
)
343 if (construct
->server_list
)
345 for (uint32_t x
= 0; x
< construct
->count
; x
++)
347 if (construct
->is_used
[x
])
350 kill_file(construct
->pid_file
[x
]);
353 free(construct
->server_list
);