You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Ruediger Pluem <rp...@apache.org> on 2009/07/30 21:27:12 UTC
Re: svn commit: r799334 - /httpd/httpd/trunk/modules/cluster/mod_heartmonitor.c
On 07/30/2009 05:37 PM, jfclere@apache.org wrote:
> Author: jfclere
> Date: Thu Jul 30 15:37:22 2009
> New Revision: 799334
>
> URL: http://svn.apache.org/viewvc?rev=799334&view=rev
> Log:
> Add the file logic for the handler.
> (Next step add the slotmem logic for the multicast socket).
>
> Modified:
> httpd/httpd/trunk/modules/cluster/mod_heartmonitor.c
>
> Modified: httpd/httpd/trunk/modules/cluster/mod_heartmonitor.c
> URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/cluster/mod_heartmonitor.c?rev=799334&r1=799333&r2=799334&view=diff
> ==============================================================================
> --- httpd/httpd/trunk/modules/cluster/mod_heartmonitor.c (original)
> +++ httpd/httpd/trunk/modules/cluster/mod_heartmonitor.c Thu Jul 30 15:37:22 2009
> +static apr_status_t hm_file_update_stat(hm_ctx_t *ctx, hm_server_t *s, apr_pool_t *pool)
> +{
> + apr_status_t rv;
> + apr_file_t *fp;
> + apr_file_t *fpin;
> + apr_hash_index_t *hi;
> + apr_time_t now;
> + unsigned int fage;
> + apr_finfo_t fi;
> + int updated = 0;
> + char *path = apr_pstrcat(pool, ctx->storage_path, ".tmp.XXXXXX", NULL);
> +
> +
> + /* TODO: Update stats file (!) */
> + rv = apr_file_mktemp(&fp, path, APR_CREATE | APR_WRITE, pool);
> +
> + if (rv) {
> + ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ctx->s,
> + "Heartmonitor: Unable to open tmp file: %s", path);
> + return rv;
> + }
> + rv = apr_file_open(&fpin, ctx->storage_path, APR_READ|APR_BINARY|APR_BUFFERED,
> + APR_OS_DEFAULT, pool);
> +
> + now = apr_time_now();
> + if (rv == APR_SUCCESS) {
> + char *t;
> + apr_table_t *hbt = apr_table_make(pool, 10);
> + apr_bucket_alloc_t *ba = apr_bucket_alloc_create(pool);
> + apr_bucket_brigade *bb = apr_brigade_create(pool, ba);
> + apr_bucket_brigade *tmpbb = apr_brigade_create(pool, ba);
> + rv = apr_file_info_get(&fi, APR_FINFO_SIZE | APR_FINFO_MTIME, fpin);
> + if (rv) {
> + ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ctx->s,
> + "Heartmonitor: Unable to read file: %s", ctx->storage_path);
> + return rv;
> + }
> +
> + /* Read the file and update the line corresponding to the node */
> + ba = apr_bucket_alloc_create(pool);
> + bb = apr_brigade_create(pool, ba);
> + apr_brigade_insert_file(bb, fpin, 0, fi.size, pool);
> + tmpbb = apr_brigade_create(pool, ba);
> + fage = (unsigned int) apr_time_sec(now - fi.mtime);
> + do {
> + char buf[4096];
> + const char *ip;
> + apr_size_t bsize = sizeof(buf);
> + apr_brigade_cleanup(tmpbb);
> + if (APR_BRIGADE_EMPTY(bb)) {
> + break;
> + }
> + rv = apr_brigade_split_line(tmpbb, bb,
> + APR_BLOCK_READ, sizeof(buf));
> +
> + if (rv) {
> + ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ctx->s,
> + "Heartmonitor: Unable to read from file: %s", ctx->storage_path);
> + return rv;
> + }
> +
> + apr_brigade_flatten(tmpbb, buf, &bsize);
> + if (bsize == 0) {
> + break;
> + }
> + buf[bsize - 1] = 0;
> + t = strchr(buf, ' ');
> + if (t) {
> + ip = apr_pstrndup(pool, buf, t - buf);
> + } else {
> + ip = NULL;
> + }
> + if (!ip || buf[0] == '#') {
> + /* copy things we can't process */
> + apr_file_printf(fp, "%s\n", buf);
> + } else if (strcmp(ip, s->ip) !=0 ) {
> + hm_server_t node;
> + unsigned int seen;
> + /* Update seen time according to the last file modification */
> + apr_table_clear(hbt);
> + argstr_to_table(pool, apr_pstrdup(pool, t), hbt);
> + if (apr_table_get(hbt, "busy")) {
> + node.busy = atoi(apr_table_get(hbt, "busy"));
> + }
> +
> + if (apr_table_get(hbt, "ready")) {
> + node.ready = atoi(apr_table_get(hbt, "ready"));
> + }
> +
> + if (apr_table_get(hbt, "lastseen")) {
> + node.seen = atoi(apr_table_get(hbt, "lastseen"));
> + }
> + seen = fage + node.seen;
> + apr_file_printf(fp, "%s &ready=%u&busy=%u&lastseen=%u\n",
> + ip, node.ready, node.busy, (unsigned int) seen);
The above seems to be a lot of parsing back and forth for just updating the lastseen parameter.
Couldn't we just keep the complete line until the 'lastseen=' and just update the number afterwards?
Or is the order of ready, busy and lastseen not defined?
> + }
> +
> + rv = apr_file_rename(path, ctx->storage_path, pool);
We need to consider that multiple handlers run in parallel in different threads / processes.
If we are in bad luck this can lock out node A as in the following example.
Node A and Node B sent the request at the same time and the handlers processing these requests are
running fairly in parallel.
If the handler processing Node B does the renaming one tick later then the handler processing
Node A then the update of Node A is lost. If this happens over and over again Node A is believed
to be dead although it is not.
I fear you need to use global locks here to avoid this.
Regards
RĂ¼diger
Re: svn commit: r799334 - /httpd/httpd/trunk/modules/cluster/mod_heartmonitor.c
Posted by Ruediger Pluem <rp...@apache.org>.
On 07/30/2009 09:27 PM, Ruediger Pluem wrote:
>
> On 07/30/2009 05:37 PM, jfclere@apache.org wrote:
>> Author: jfclere
>> Date: Thu Jul 30 15:37:22 2009
>> New Revision: 799334
>>
>> URL: http://svn.apache.org/viewvc?rev=799334&view=rev
>> Log:
>> Add the file logic for the handler.
>> (Next step add the slotmem logic for the multicast socket).
>>
>> Modified:
>> httpd/httpd/trunk/modules/cluster/mod_heartmonitor.c
Plus we get the following warnings:
mod_heartmonitor.c: In function 'hm_file_update_stat':
mod_heartmonitor.c:239: warning: unused variable 'hi'
mod_heartmonitor.c: In function 'hm_file_update_stats':
mod_heartmonitor.c:411: warning: dereferencing type-punned pointer will break st
rict-aliasing rules
mod_heartmonitor.c: In function 'hm_handler':
mod_heartmonitor.c:310: warning: 'node.busy' may be used uninitialized in this f
unction
mod_heartmonitor.c:310: warning: 'node.ready' may be used uninitialized in this
function
mod_heartmonitor.c:310: warning: 'node.seen' may be used uninitialized in this f
unction
Regards
RĂ¼diger
Re: svn commit: r799334 - /httpd/httpd/trunk/modules/cluster/mod_heartmonitor.c
Posted by jean-frederic clere <jf...@gmail.com>.
On 07/30/2009 09:27 PM, Ruediger Pluem wrote:
>
> On 07/30/2009 05:37 PM, jfclere@apache.org wrote:
>> Author: jfclere
>> Date: Thu Jul 30 15:37:22 2009
>> New Revision: 799334
>>
>> URL: http://svn.apache.org/viewvc?rev=799334&view=rev
>> Log:
>> Add the file logic for the handler.
>> (Next step add the slotmem logic for the multicast socket).
>>
>> Modified:
>> httpd/httpd/trunk/modules/cluster/mod_heartmonitor.c
>>
>> Modified: httpd/httpd/trunk/modules/cluster/mod_heartmonitor.c
>> URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/cluster/mod_heartmonitor.c?rev=799334&r1=799333&r2=799334&view=diff
>> ==============================================================================
>> --- httpd/httpd/trunk/modules/cluster/mod_heartmonitor.c (original)
>> +++ httpd/httpd/trunk/modules/cluster/mod_heartmonitor.c Thu Jul 30 15:37:22 2009
>
+++ CUT +++
>> +
>> + if (apr_table_get(hbt, "lastseen")) {
>> + node.seen = atoi(apr_table_get(hbt, "lastseen"));
>> + }
>> + seen = fage + node.seen;
>> + apr_file_printf(fp, "%s&ready=%u&busy=%u&lastseen=%u\n",
>> + ip, node.ready, node.busy, (unsigned int) seen);
>
> The above seems to be a lot of parsing back and forth for just updating the lastseen parameter.
> Couldn't we just keep the complete line until the 'lastseen=' and just update the number afterwards?
If only mod_heartmonitor writes there yes otherwise no.
Probably looking for lastseen= and digits should be enough.
> Or is the order of ready, busy and lastseen not defined?
If the order is defined we could use a structure but we would loose all
the flexibility the actual format allows.
>
>
>> + }
>> +
>> + rv = apr_file_rename(path, ctx->storage_path, pool);
>
> We need to consider that multiple handlers run in parallel in different threads / processes.
> If we are in bad luck this can lock out node A as in the following example.
>
> Node A and Node B sent the request at the same time and the handlers processing these requests are
> running fairly in parallel.
> If the handler processing Node B does the renaming one tick later then the handler processing
> Node A then the update of Node A is lost. If this happens over and over again Node A is believed
> to be dead although it is not.
> I fear you need to use global locks here to avoid this.
Yes, I will work of that asap.
Cheers
Jean-Frederic