diff options
author | Christian Grothoff <christian@grothoff.org> | 2012-03-04 20:59:41 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2012-03-04 20:59:41 +0000 |
commit | fa2373ff7a4291216be7c00f76e276ee60aec654 (patch) | |
tree | 7f5da264095f18358b3abe772d88498ba6627407 /src/statistics/gnunet-service-statistics.c | |
parent | 6cdff36159de7a4fe5bc31564cc7dc3a2f94b0ed (diff) | |
download | gnunet-fa2373ff7a4291216be7c00f76e276ee60aec654.tar.gz gnunet-fa2373ff7a4291216be7c00f76e276ee60aec654.zip |
make gnunet-service-statistics not exit on external shutdown signal as long as there are connected clients to be managed
Diffstat (limited to 'src/statistics/gnunet-service-statistics.c')
-rw-r--r-- | src/statistics/gnunet-service-statistics.c | 157 |
1 files changed, 110 insertions, 47 deletions
diff --git a/src/statistics/gnunet-service-statistics.c b/src/statistics/gnunet-service-statistics.c index a890d6d8e..c57013987 100644 --- a/src/statistics/gnunet-service-statistics.c +++ b/src/statistics/gnunet-service-statistics.c | |||
@@ -41,14 +41,29 @@ | |||
41 | struct WatchEntry | 41 | struct WatchEntry |
42 | { | 42 | { |
43 | 43 | ||
44 | /** | ||
45 | * Watch entries are kept in a linked list. | ||
46 | */ | ||
44 | struct WatchEntry *next; | 47 | struct WatchEntry *next; |
45 | 48 | ||
49 | /** | ||
50 | * Watch entries are kept in a linked list. | ||
51 | */ | ||
46 | struct WatchEntry *prev; | 52 | struct WatchEntry *prev; |
47 | 53 | ||
54 | /** | ||
55 | * For which client is this watch entry? | ||
56 | */ | ||
48 | struct GNUNET_SERVER_Client *client; | 57 | struct GNUNET_SERVER_Client *client; |
49 | 58 | ||
59 | /** | ||
60 | * Last value we communicated to the client for this watch entry. | ||
61 | */ | ||
50 | uint64_t last_value; | 62 | uint64_t last_value; |
51 | 63 | ||
64 | /** | ||
65 | * Unique watch number for this client and this watched value. | ||
66 | */ | ||
52 | uint32_t wid; | 67 | uint32_t wid; |
53 | 68 | ||
54 | }; | 69 | }; |
@@ -59,13 +74,24 @@ struct WatchEntry | |||
59 | */ | 74 | */ |
60 | struct ClientEntry | 75 | struct ClientEntry |
61 | { | 76 | { |
62 | 77 | /** | |
78 | * Clients are kept in a linked list. | ||
79 | */ | ||
63 | struct ClientEntry *next; | 80 | struct ClientEntry *next; |
64 | 81 | ||
82 | /** | ||
83 | * Clients are kept in a linked list. | ||
84 | */ | ||
65 | struct ClientEntry *prev; | 85 | struct ClientEntry *prev; |
66 | 86 | ||
87 | /** | ||
88 | * Corresponding server handle. | ||
89 | */ | ||
67 | struct GNUNET_SERVER_Client *client; | 90 | struct GNUNET_SERVER_Client *client; |
68 | 91 | ||
92 | /** | ||
93 | * Maximum watch ID used by this client so far. | ||
94 | */ | ||
69 | uint32_t max_wid; | 95 | uint32_t max_wid; |
70 | 96 | ||
71 | }; | 97 | }; |
@@ -138,11 +164,22 @@ static const struct GNUNET_CONFIGURATION_Handle *cfg; | |||
138 | */ | 164 | */ |
139 | static struct StatsEntry *start; | 165 | static struct StatsEntry *start; |
140 | 166 | ||
167 | /** | ||
168 | * Head of linked list of connected clients. | ||
169 | */ | ||
141 | static struct ClientEntry *client_head; | 170 | static struct ClientEntry *client_head; |
142 | 171 | ||
172 | /** | ||
173 | * Tail of linked list of connected clients. | ||
174 | */ | ||
143 | static struct ClientEntry *client_tail; | 175 | static struct ClientEntry *client_tail; |
144 | 176 | ||
145 | /** | 177 | /** |
178 | * Handle to our server. | ||
179 | */ | ||
180 | static struct GNUNET_SERVER_Handle *srv; | ||
181 | |||
182 | /** | ||
146 | * Our notification context. | 183 | * Our notification context. |
147 | */ | 184 | */ |
148 | static struct GNUNET_SERVER_NotificationContext *nc; | 185 | static struct GNUNET_SERVER_NotificationContext *nc; |
@@ -152,7 +189,19 @@ static struct GNUNET_SERVER_NotificationContext *nc; | |||
152 | */ | 189 | */ |
153 | static uint32_t uidgen; | 190 | static uint32_t uidgen; |
154 | 191 | ||
192 | /** | ||
193 | * Set to YES if we are shutting down as soon as possible. | ||
194 | */ | ||
195 | static int in_shutdown; | ||
196 | |||
155 | 197 | ||
198 | /** | ||
199 | * Inject a message to our server with a client of 'NULL'. | ||
200 | * | ||
201 | * @param cls the 'struct GNUNET_SERVER_Handle' | ||
202 | * @param client unused | ||
203 | * @param msg message to inject | ||
204 | */ | ||
156 | static void | 205 | static void |
157 | inject_message (void *cls, void *client, const struct GNUNET_MessageHeader *msg) | 206 | inject_message (void *cls, void *client, const struct GNUNET_MessageHeader *msg) |
158 | { | 207 | { |
@@ -219,6 +268,7 @@ load (struct GNUNET_SERVER_Handle *server) | |||
219 | GNUNET_free (fn); | 268 | GNUNET_free (fn); |
220 | } | 269 | } |
221 | 270 | ||
271 | |||
222 | /** | 272 | /** |
223 | * Write persistent statistics to disk. | 273 | * Write persistent statistics to disk. |
224 | */ | 274 | */ |
@@ -272,6 +322,9 @@ save () | |||
272 | 322 | ||
273 | /** | 323 | /** |
274 | * Transmit the given stats value. | 324 | * Transmit the given stats value. |
325 | * | ||
326 | * @param client receiver of the value | ||
327 | * @param e value to transmit | ||
275 | */ | 328 | */ |
276 | static void | 329 | static void |
277 | transmit (struct GNUNET_SERVER_Client *client, const struct StatsEntry *e) | 330 | transmit (struct GNUNET_SERVER_Client *client, const struct StatsEntry *e) |
@@ -294,11 +347,9 @@ transmit (struct GNUNET_SERVER_Client *client, const struct StatsEntry *e) | |||
294 | GNUNET_assert (size == | 347 | GNUNET_assert (size == |
295 | GNUNET_STRINGS_buffer_fill ((char *) &m[1], size, 2, | 348 | GNUNET_STRINGS_buffer_fill ((char *) &m[1], size, 2, |
296 | e->service, e->name)); | 349 | e->service, e->name)); |
297 | #if DEBUG_STATISTICS | ||
298 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 350 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
299 | "Transmitting value for `%s:%s' (%d): %llu\n", e->service, | 351 | "Transmitting value for `%s:%s' (%d): %llu\n", e->service, |
300 | e->name, e->persistent, e->value); | 352 | e->name, e->persistent, e->value); |
301 | #endif | ||
302 | GNUNET_SERVER_notification_context_unicast (nc, client, &m->header, | 353 | GNUNET_SERVER_notification_context_unicast (nc, client, &m->header, |
303 | GNUNET_NO); | 354 | GNUNET_NO); |
304 | GNUNET_free (m); | 355 | GNUNET_free (m); |
@@ -307,6 +358,11 @@ transmit (struct GNUNET_SERVER_Client *client, const struct StatsEntry *e) | |||
307 | 358 | ||
308 | /** | 359 | /** |
309 | * Does this entry match the request? | 360 | * Does this entry match the request? |
361 | * | ||
362 | * @param e an entry | ||
363 | * @param service name of service to match | ||
364 | * @param name value to match | ||
365 | * @return 1 if they match, 0 if not | ||
310 | */ | 366 | */ |
311 | static int | 367 | static int |
312 | matches (const struct StatsEntry *e, const char *service, const char *name) | 368 | matches (const struct StatsEntry *e, const char *service, const char *name) |
@@ -316,6 +372,12 @@ matches (const struct StatsEntry *e, const char *service, const char *name) | |||
316 | } | 372 | } |
317 | 373 | ||
318 | 374 | ||
375 | /** | ||
376 | * Find a client entry for the given client handle, or create one. | ||
377 | * | ||
378 | * @param client handle to match | ||
379 | * @return corresponding client entry struct | ||
380 | */ | ||
319 | static struct ClientEntry * | 381 | static struct ClientEntry * |
320 | make_client_entry (struct GNUNET_SERVER_Client *client) | 382 | make_client_entry (struct GNUNET_SERVER_Client *client) |
321 | { | 383 | { |
@@ -368,18 +430,12 @@ handle_get (void *cls, struct GNUNET_SERVER_Client *client, | |||
368 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | 430 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); |
369 | return; | 431 | return; |
370 | } | 432 | } |
371 | #if DEBUG_STATISTICS | ||
372 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 433 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
373 | "Received request for statistics on `%s:%s'\n", | 434 | "Received request for statistics on `%s:%s'\n", |
374 | strlen (service) ? service : "*", strlen (name) ? name : "*"); | 435 | strlen (service) ? service : "*", strlen (name) ? name : "*"); |
375 | #endif | 436 | for (pos = start; NULL != pos; pos = pos->next) |
376 | pos = start; | ||
377 | while (pos != NULL) | ||
378 | { | ||
379 | if (matches (pos, service, name)) | 437 | if (matches (pos, service, name)) |
380 | transmit (client, pos); | 438 | transmit (client, pos); |
381 | pos = pos->next; | ||
382 | } | ||
383 | end.size = htons (sizeof (struct GNUNET_MessageHeader)); | 439 | end.size = htons (sizeof (struct GNUNET_MessageHeader)); |
384 | end.type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_END); | 440 | end.type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_END); |
385 | GNUNET_SERVER_notification_context_unicast (nc, client, &end, GNUNET_NO); | 441 | GNUNET_SERVER_notification_context_unicast (nc, client, &end, GNUNET_NO); |
@@ -387,29 +443,31 @@ handle_get (void *cls, struct GNUNET_SERVER_Client *client, | |||
387 | } | 443 | } |
388 | 444 | ||
389 | 445 | ||
446 | /** | ||
447 | * Notify all clients listening about a change to a value. | ||
448 | * | ||
449 | * @param se value that changed | ||
450 | */ | ||
390 | static void | 451 | static void |
391 | notify_change (struct StatsEntry *se) | 452 | notify_change (struct StatsEntry *se) |
392 | { | 453 | { |
393 | struct GNUNET_STATISTICS_WatchValueMessage wvm; | 454 | struct GNUNET_STATISTICS_WatchValueMessage wvm; |
394 | struct WatchEntry *pos; | 455 | struct WatchEntry *pos; |
395 | 456 | ||
396 | pos = se->we_head; | 457 | for (pos = se->we_head; NULL != pos; pos = pos->next) |
397 | while (pos != NULL) | ||
398 | { | 458 | { |
399 | if (pos->last_value != se->value) | 459 | if (pos->last_value == se->value) |
400 | { | 460 | continue; |
401 | wvm.header.type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_WATCH_VALUE); | 461 | wvm.header.type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_WATCH_VALUE); |
402 | wvm.header.size = | 462 | wvm.header.size = |
403 | htons (sizeof (struct GNUNET_STATISTICS_WatchValueMessage)); | 463 | htons (sizeof (struct GNUNET_STATISTICS_WatchValueMessage)); |
404 | wvm.flags = htonl (se->persistent ? GNUNET_STATISTICS_PERSIST_BIT : 0); | 464 | wvm.flags = htonl (se->persistent ? GNUNET_STATISTICS_PERSIST_BIT : 0); |
405 | wvm.wid = htonl (pos->wid); | 465 | wvm.wid = htonl (pos->wid); |
406 | wvm.reserved = htonl (0); | 466 | wvm.reserved = htonl (0); |
407 | wvm.value = GNUNET_htonll (se->value); | 467 | wvm.value = GNUNET_htonll (se->value); |
408 | GNUNET_SERVER_notification_context_unicast (nc, pos->client, &wvm.header, | 468 | GNUNET_SERVER_notification_context_unicast (nc, pos->client, &wvm.header, |
409 | GNUNET_NO); | 469 | GNUNET_NO); |
410 | pos->last_value = se->value; | 470 | pos->last_value = se->value; |
411 | } | ||
412 | pos = pos->next; | ||
413 | } | 471 | } |
414 | } | 472 | } |
415 | 473 | ||
@@ -458,11 +516,9 @@ handle_set (void *cls, struct GNUNET_SERVER_Client *client, | |||
458 | } | 516 | } |
459 | flags = ntohl (msg->flags); | 517 | flags = ntohl (msg->flags); |
460 | value = GNUNET_ntohll (msg->value); | 518 | value = GNUNET_ntohll (msg->value); |
461 | #if DEBUG_STATISTICS | ||
462 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 519 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
463 | "Received request to update statistic on `%s:%s' (%u) to/by %llu\n", | 520 | "Received request to update statistic on `%s:%s' (%u) to/by %llu\n", |
464 | service, name, (unsigned int) flags, (unsigned long long) value); | 521 | service, name, (unsigned int) flags, (unsigned long long) value); |
465 | #endif | ||
466 | pos = start; | 522 | pos = start; |
467 | prev = NULL; | 523 | prev = NULL; |
468 | while (pos != NULL) | 524 | while (pos != NULL) |
@@ -499,11 +555,9 @@ handle_set (void *cls, struct GNUNET_SERVER_Client *client, | |||
499 | pos->next = start; | 555 | pos->next = start; |
500 | start = pos; | 556 | start = pos; |
501 | } | 557 | } |
502 | #if DEBUG_STATISTICS | ||
503 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 558 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
504 | "Statistic `%s:%s' updated to value %llu.\n", service, name, | 559 | "Statistic `%s:%s' updated to value %llu.\n", service, name, |
505 | pos->value); | 560 | pos->value); |
506 | #endif | ||
507 | if (changed) | 561 | if (changed) |
508 | notify_change (pos); | 562 | notify_change (pos); |
509 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | 563 | GNUNET_SERVER_receive_done (client, GNUNET_OK); |
@@ -525,11 +579,9 @@ handle_set (void *cls, struct GNUNET_SERVER_Client *client, | |||
525 | pos->name = &pos->service[strlen (pos->service) + 1]; | 579 | pos->name = &pos->service[strlen (pos->service) + 1]; |
526 | 580 | ||
527 | start = pos; | 581 | start = pos; |
528 | #if DEBUG_STATISTICS | ||
529 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 582 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
530 | "New statistic on `%s:%s' with value %llu created.\n", service, | 583 | "New statistic on `%s:%s' with value %llu created.\n", service, |
531 | name, pos->value); | 584 | name, pos->value); |
532 | #endif | ||
533 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | 585 | GNUNET_SERVER_receive_done (client, GNUNET_OK); |
534 | } | 586 | } |
535 | 587 | ||
@@ -571,11 +623,9 @@ handle_watch (void *cls, struct GNUNET_SERVER_Client *client, | |||
571 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | 623 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); |
572 | return; | 624 | return; |
573 | } | 625 | } |
574 | #if DEBUG_STATISTICS | ||
575 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 626 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
576 | "Received request to watch statistic on `%s:%s'\n", service, | 627 | "Received request to watch statistic on `%s:%s'\n", service, |
577 | name); | 628 | name); |
578 | #endif | ||
579 | pos = start; | 629 | pos = start; |
580 | while (pos != NULL) | 630 | while (pos != NULL) |
581 | { | 631 | { |
@@ -613,27 +663,18 @@ handle_watch (void *cls, struct GNUNET_SERVER_Client *client, | |||
613 | 663 | ||
614 | 664 | ||
615 | /** | 665 | /** |
616 | * Task run during shutdown. | 666 | * Actually perform the shutdown. |
617 | * | ||
618 | * @param cls unused | ||
619 | * @param tc unused | ||
620 | */ | 667 | */ |
621 | static void | 668 | static void |
622 | shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | 669 | do_shutdown () |
623 | { | 670 | { |
624 | struct ClientEntry *ce; | ||
625 | struct WatchEntry *we; | 671 | struct WatchEntry *we; |
626 | struct StatsEntry *se; | 672 | struct StatsEntry *se; |
627 | 673 | ||
628 | save (); | 674 | save (); |
629 | GNUNET_SERVER_notification_context_destroy (nc); | 675 | GNUNET_SERVER_notification_context_destroy (nc); |
630 | nc = NULL; | 676 | nc = NULL; |
631 | while (NULL != (ce = client_head)) | 677 | GNUNET_assert (NULL == client_head); |
632 | { | ||
633 | GNUNET_SERVER_client_drop (ce->client); | ||
634 | GNUNET_CONTAINER_DLL_remove (client_head, client_tail, ce); | ||
635 | GNUNET_free (ce); | ||
636 | } | ||
637 | while (NULL != (se = start)) | 678 | while (NULL != (se = start)) |
638 | { | 679 | { |
639 | start = se->next; | 680 | start = se->next; |
@@ -645,6 +686,23 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
645 | } | 686 | } |
646 | GNUNET_free (se); | 687 | GNUNET_free (se); |
647 | } | 688 | } |
689 | GNUNET_SERVER_destroy (srv); | ||
690 | } | ||
691 | |||
692 | |||
693 | /** | ||
694 | * Task run during shutdown. | ||
695 | * | ||
696 | * @param cls unused | ||
697 | * @param tc unused | ||
698 | */ | ||
699 | static void | ||
700 | shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
701 | { | ||
702 | in_shutdown = GNUNET_YES; | ||
703 | if (NULL != client_head) | ||
704 | return; | ||
705 | do_shutdown (); | ||
648 | } | 706 | } |
649 | 707 | ||
650 | 708 | ||
@@ -689,6 +747,9 @@ handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) | |||
689 | } | 747 | } |
690 | se = se->next; | 748 | se = se->next; |
691 | } | 749 | } |
750 | if ( (NULL == client_head) && | ||
751 | (GNUNET_YES == in_shutdown) ) | ||
752 | do_shutdown (); | ||
692 | } | 753 | } |
693 | 754 | ||
694 | 755 | ||
@@ -710,7 +771,9 @@ run (void *cls, struct GNUNET_SERVER_Handle *server, | |||
710 | {NULL, NULL, 0, 0} | 771 | {NULL, NULL, 0, 0} |
711 | }; | 772 | }; |
712 | cfg = c; | 773 | cfg = c; |
774 | srv = server; | ||
713 | GNUNET_SERVER_add_handlers (server, handlers); | 775 | GNUNET_SERVER_add_handlers (server, handlers); |
776 | GNUNET_SERVER_ignore_shutdown (server, GNUNET_YES); | ||
714 | nc = GNUNET_SERVER_notification_context_create (server, 16); | 777 | nc = GNUNET_SERVER_notification_context_create (server, 16); |
715 | GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL); | 778 | GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL); |
716 | load (server); | 779 | load (server); |