[Originally posted May 21...]
I encountered a problem when doing a mod-mono-server restart through the
mod_mono control panel that when requests came in while the restart was
in progress, the restart would fail, mod-mono-server would be forked but
fail to start, and it would be continually forked at each request but
still fail to start.
My solution was to disallow requests while a restart is in progress.
The attached patch allows mod-mono-server backends to be 'paused' with
requests coming in dropped with 503s during that time. The control panel
restart now pauses and resumes around the restart. You can also
pause/resume from the control panel.
The patch also changes where locking is done for the active requests
counter. (This should have no consequences.)
Attached. I'll commit if it's ok.
--
- Josh Tauberer
http://razor.occams.info
Index: ChangeLog
===================================================================
--- ChangeLog (revision 103720)
+++ ChangeLog (working copy)
@@ -1,3 +1,16 @@
+2008-05-21 Joshua Tauberer <[EMAIL PROTECTED]>
+
+ * src/mod_mono.c: Always acquire a lock at the start of processing
+ a request. The active requests counter function now assumes the
+ lock is already aquired. Also added a accepting_requests flag
+ to the dashboard so that xsp configurations can be paused. Now
+ when restarting mod-mono-server from the control panel, the
+ configuration is set to not accepting requests (503s returned)
+ until after the restart. This fixed a problem that when requests
+ came in during a restart, mod-mono-server would never successfully
+ come back but it would keep getting forked. The flag can also
+ be turned on and off through the control panel.
+
2008-05-20 Marek Habersack <[EMAIL PROTECTED]>
* src/mod_mono.c: work correctly with IPv6 sockets, by detecting
Index: src/mod_mono.c
===================================================================
--- src/mod_mono.c (revision 103720)
+++ src/mod_mono.c (working copy)
@@ -65,6 +65,7 @@
char restart_issued;
int active_requests;
int waiting_requests;
+ int accepting_requests;
} dashboard_data;
typedef struct xsp_data {
@@ -452,6 +453,7 @@
xsp->dashboard->restart_issued = 0;
xsp->dashboard->active_requests = 0;
xsp->dashboard->waiting_requests = 0;
+ xsp->dashboard->accepting_requests = 1;
}
}
}
@@ -1933,6 +1935,13 @@
increment_active_requests (xsp_data *conf)
{
#ifndef APACHE13
+ /* This function tries to increment the counters that limit
+ * the number of simultaenous requests being processed. It
+ * assumes that the mutex is held when the function is called
+ * and returns with the mutex still held, although it may
+ * unlock and lock the mutex itself.
+ */
+
apr_status_t rv;
int max_active_requests = atoi(conf->max_active_requests);
@@ -1941,21 +1950,20 @@
/* Limit the number of concurrent requests. If no
* limiting is in effect (or can't be done because
* there is no dashboard), return the OK status.
- * Same test as in the decrement function. */
- if (max_active_requests == 0 || !conf->dashboard_mutex || !conf->dashboard)
+ * Same test as in the decrement function and the
+ * control panel. */
+ if (!conf->dashboard_mutex || !conf->dashboard)
return 1;
- rv = apr_global_mutex_lock (conf->dashboard_mutex);
- /* Drop the request on failure to lock the dashboard because
- * we don't want to decrement the counter later since we couldn't
- * increment it here. */
- if (rv != APR_SUCCESS)
- return 0;
-
// From here on, rv holds onto whether we still have
// the lock acquired, just in case some error ocurrs
// acquiring it during the loop.
- if (conf->dashboard->active_requests >= max_active_requests) {
+ rv = APR_SUCCESS;
+
+ /* If any limiting is in effect, and if there are the maximum
+ * allowed concurrent requests, then we have to hold the request
+ * for a bit of time. */
+ if (max_active_requests > 0 && conf->dashboard->active_requests >= max_active_requests) {
/* We need to wait until the active requests
* go below the maximum. */
@@ -1965,7 +1973,6 @@
* is max_active_req+max_waiting_req.
*/
if (conf->dashboard->waiting_requests >= max_waiting_requests) {
- apr_global_mutex_unlock (conf->dashboard_mutex);
ap_log_error (APLOG_MARK, APLOG_ERR, STATUS_AND_SERVER,
"Maximum number of concurrent mod_mono requests to %s reached (%d active, %d waiting). Request dropped.",
conf->dashboard_lock_file, max_active_requests, max_waiting_requests);
@@ -2000,7 +2007,6 @@
// many requests are going, stop processing the
// request.
if (rv == APR_SUCCESS && conf->dashboard->active_requests >= max_active_requests) {
- apr_global_mutex_unlock (conf->dashboard_mutex);
ap_log_error (APLOG_MARK, APLOG_ERR, STATUS_AND_SERVER,
"Maximum number (%d) of concurrent mod_mono requests to %s reached. Droping request.",
max_active_requests, conf->dashboard_lock_file);
@@ -2015,7 +2021,6 @@
return 0;
conf->dashboard->active_requests++;
- apr_global_mutex_unlock (conf->dashboard_mutex);
return 1;
#else
@@ -2029,11 +2034,9 @@
#ifndef APACHE13
apr_status_t rv;
- int max_active_requests = atoi(conf->max_active_requests);
-
/* Check if limiting is in effect. Same test as in the
- * increment function. */
- if (max_active_requests == 0 || !conf->dashboard_mutex || !conf->dashboard)
+ * increment function and the control panel. */
+ if (!conf->dashboard_mutex || !conf->dashboard)
return;
rv = apr_global_mutex_lock (conf->dashboard_mutex);
@@ -2131,12 +2134,23 @@
} else
conf->dashboard_mutex_initialized_in_child = 1;
}
+
+ if (conf->dashboard_mutex && conf->dashboard) {
+ if (apr_global_mutex_lock (conf->dashboard_mutex) == APR_SUCCESS) {
+ int ok = conf->dashboard->accepting_requests;
+ if (ok)
+ ok = increment_active_requests (conf);
+
+ apr_global_mutex_unlock (conf->dashboard_mutex);
+
+ if (!ok)
+ return HTTP_SERVICE_UNAVAILABLE;
+ }
+ }
#endif
rv = -1; /* avoid a warning about uninitialized value */
- if (!increment_active_requests (conf))
- return HTTP_SERVICE_UNAVAILABLE;
-
+
while (connect_attempts--) {
rv = setup_socket (&sock, conf, r->pool);
DEBUG_PRINT (2, "After setup_socket");
@@ -2540,6 +2554,31 @@
return terminate_xsp2(data, NULL, 0, 0);
}
+static void
+set_accepting_requests (void *data, char *alias, int accepting_requests)
+{
+ server_rec *server;
+ module_cfg *config;
+ xsp_data *xsp;
+ int i;
+
+ server = (server_rec *) data;
+ config = ap_get_module_config (server->module_config, &mono_module);
+
+ for (i = 0; i < config->nservers; i++) {
+ xsp = &config->servers [i];
+
+ /* If alias isn't null, skip XSPs that don't have that alias. */
+ if (alias != NULL && strcmp(xsp->alias, alias))
+ continue;
+
+#ifndef APACHE13
+ if (xsp->dashboard)
+ xsp->dashboard->accepting_requests = accepting_requests;
+#endif
+ }
+}
+
static int
mono_control_panel_handler (request_rec *r)
{
@@ -2567,43 +2606,63 @@
uri = &r->parsed_uri;
if (!uri->query || !strcmp (uri->query, "")) {
/* No query string -> Emit links for configuration commands. */
- request_send_response_string (r, "<ul style=\"text-align: center;\">\n");
+ request_send_response_string (r, "<ul>\n");
+ request_send_response_string (r, "<li><div>All Backends</div>\n<ul>\n");
request_send_response_string (r, "<li><a href=\"?restart=ALL\">Restart all mod-mono-server processes</a></li>\n");
+ request_send_response_string (r, "<li><a href=\"?pause=ALL\">Stop Accepting Requests</a></li>\n");
+ request_send_response_string (r, "<li><a href=\"?resume=ALL\">Resume Accepting Requests</a></li>\n");
+ request_send_response_string (r, "</ul></li>\n");
for (i = 0; i < config->nservers; i++) {
xsp = &config->servers [i];
if (xsp->run_xsp && !strcasecmp (xsp->run_xsp, "false"))
continue;
- buffer = apr_psprintf (r->pool, "<li>%s: <a href=\"?restart=%s\">"
- "Restart Server</a>", xsp->alias, xsp->alias);
+ buffer = apr_psprintf (r->pool, "<li><div>%s</div><ul>\n", xsp->alias);
request_send_response_string(r, buffer);
+ buffer = apr_psprintf (r->pool, "<li><a href=\"?restart=%s\">Restart Server</a></li>\n", xsp->alias);
+ request_send_response_string(r, buffer);
+
#ifndef APACHE13
ensure_dashboard_initialized (config, xsp, pconf);
- if (xsp->dashboard_mutex) {
- rv = apr_global_mutex_lock (xsp->dashboard_mutex);
- if (rv == APR_SUCCESS) {
- if (xsp->restart_mode == AUTORESTART_MODE_REQUESTS) {
- buffer = apr_psprintf (r->pool, " [%d requests served; limit: %d]",
- xsp->dashboard->handled_requests, xsp->restart_requests);
- request_send_response_string(r, buffer);
- } else if (xsp->restart_mode == AUTORESTART_MODE_TIME) {
- buffer = apr_psprintf (r->pool, " [%ds time running; limit: %ds]",
- (int)(time(NULL) - xsp->dashboard->start_time), (int)xsp->restart_time);
- request_send_response_string(r, buffer);
- }
+ if (xsp->dashboard_mutex && xsp->dashboard
+ && apr_global_mutex_lock (xsp->dashboard_mutex) == APR_SUCCESS) {
- rv = apr_global_mutex_unlock (xsp->dashboard_mutex);
- if (rv != APR_SUCCESS)
- ap_log_error (APLOG_MARK, APLOG_ALERT, STATCODE_AND_SERVER (rv),
- "Failed to release %s lock after mono-ctrl output, the process may deadlock!",
- xsp->dashboard_lock_file);
+ if (xsp->dashboard->accepting_requests)
+ buffer = apr_psprintf (r->pool, "<li><a href=\"?pause=%s\">Stop Accepting Requests</a></li>\n", xsp->alias);
+ else
+ buffer = apr_psprintf (r->pool, "<li><a href=\"?resume=%s\">Resume Accepting Requests</a></li>\n", xsp->alias);
+ request_send_response_string(r, buffer);
+
+ if (xsp->restart_mode == AUTORESTART_MODE_REQUESTS) {
+ buffer = apr_psprintf (r->pool, "<li>%d requests served; limit: %d</li>\n",
+ xsp->dashboard->handled_requests, xsp->restart_requests);
+ request_send_response_string(r, buffer);
+ } else if (xsp->restart_mode == AUTORESTART_MODE_TIME) {
+ buffer = apr_psprintf (r->pool, "<li>%ds time running; limit: %ds</li>\n",
+ (int)(time(NULL) - xsp->dashboard->start_time), (int)xsp->restart_time);
+ request_send_response_string(r, buffer);
}
+
+ buffer = apr_psprintf (r->pool, "<li>%d requests currently being processed; limit: %s</li>\n",
+ xsp->dashboard->active_requests, xsp->max_active_requests);
+ request_send_response_string(r, buffer);
+
+ buffer = apr_psprintf (r->pool, "<li>%d requests currently waiting to be processed; limit: %s</li>\n",
+ xsp->dashboard->waiting_requests, xsp->max_waiting_requests);
+ request_send_response_string(r, buffer);
+
+
+ rv = apr_global_mutex_unlock (xsp->dashboard_mutex);
+ if (rv != APR_SUCCESS)
+ ap_log_error (APLOG_MARK, APLOG_ALERT, STATCODE_AND_SERVER (rv),
+ "Failed to release %s lock after mono-ctrl output, the process may deadlock!",
+ xsp->dashboard_lock_file);
}
#endif
- request_send_response_string(r, "</li>\n");
+ request_send_response_string(r, "</ul></li>\n");
}
request_send_response_string (r, "</ul>\n");
@@ -2613,9 +2672,25 @@
char *alias = uri->query + 8; /* +8 == .Substring(8) */
if (!strcmp (alias, "ALL"))
alias = NULL;
+ set_accepting_requests (r->server, alias, 0);
terminate_xsp2 (r->server, alias, 1, 0);
start_xsp (config, 1, alias);
+ set_accepting_requests (r->server, alias, 1);
request_send_response_string (r, "<div style=\"text-align: center;\">mod-mono-server processes restarted.</div><br>\n");
+ } else if (uri->query && !strncmp (uri->query, "pause=", 6)) {
+ /* Stop accepting requests for this server */
+ char *alias = uri->query + 6; /* +6 == .Substring(6) */
+ if (!strcmp (alias, "ALL"))
+ alias = NULL;
+ set_accepting_requests (r->server, alias, 0);
+ request_send_response_string (r, "<div style=\"text-align: center;\">no longer accepting requests</div><br>\n");
+ } else if (uri->query && !strncmp (uri->query, "resume=", 7)) {
+ /* Resume accepting requests for this server */
+ char *alias = uri->query + 7; /* +7 == .Substring(7) */
+ if (!strcmp (alias, "ALL"))
+ alias = NULL;
+ set_accepting_requests (r->server, alias, 1);
+ request_send_response_string (r, "<div style=\"text-align: center;\">resumed accepting requests</div><br>\n");
} else {
/* Invalid command. */
request_send_response_string (r, "<div style=\"text-align: center;\">Invalid query string command.</div>\n");
_______________________________________________
Mono-devel-list mailing list
Mono-devel-list@lists.ximian.com
http://lists.ximian.com/mailman/listinfo/mono-devel-list