X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fhousekeeping.c;h=0ca383202c2bb1f27275e2d92cedb5f7d5a860f5;hb=fa2dd842abb5feedea3e2253255722fcaecc3c6f;hp=b4d76e970cd7e3cac98ad37566e9e8aa4a27b19b;hpb=ae822088bca5cce3d6c3ef7f6d312a6d5de7a77c;p=citadel.git diff --git a/citadel/housekeeping.c b/citadel/housekeeping.c index b4d76e970..0ca383202 100644 --- a/citadel/housekeeping.c +++ b/citadel/housekeeping.c @@ -1,94 +1,217 @@ /* - * This file contains housekeeping tasks which periodically - * need to be executed. + * This file contains miscellaneous housekeeping tasks. * + * Copyright (c) 1987-2021 by the citadel.org team + * + * This program is open source software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ -#include -#include #include -#include -#include -#include -#include -#include -#include "citadel.h" -#include "server.h" -#include "proto.h" -#include "citserver.h" +#include + +#include "ctdl_module.h" +#include "serv_extensions.h" +#include "room_ops.h" +#include "internet_addressing.h" +#include "config.h" +#include "journaling.h" +#include "citadel_ldap.h" + +void check_sched_shutdown(void) { + if ((ScheduledShutdown == 1) && (ContextList == NULL)) { + syslog(LOG_NOTICE, "housekeeping: scheduled shutdown initiating"); + server_shutting_down = 1; + } +} + /* - * Terminate idle sessions. This function pounds through the session table - * comparing the current time to each session's time-of-last-command. If an - * idle session is found it is terminated, then the search restarts at the - * beginning because the pointer to our place in the list becomes invalid. + * Check (and fix) floor reference counts. This doesn't need to be done + * very often, since the counts should remain correct during normal operation. */ -void terminate_idle_sessions(void) { - struct CitContext *ccptr; - time_t now; - - time(&now); - for (ccptr = ContextList; ccptr != NULL; ccptr = ccptr->next) { - if ( (ccptr!=CC) - && (config.c_sleeping > 0) - && (now - (ccptr->lastcmd) > config.c_sleeping) ) { - lprintf(3, "Session %d timed out\n", ccptr->cs_pid); - kill_session(ccptr->cs_pid); - ccptr = ContextList; - } +void check_ref_counts_backend(struct ctdlroom *qrbuf, void *data) { + + int *new_refcounts; + + new_refcounts = (int *) data; + + ++new_refcounts[(int)qrbuf->QRfloor]; +} + + +void check_ref_counts(void) { + struct floor flbuf; + int a; + + int new_refcounts[MAXFLOORS]; + + syslog(LOG_DEBUG, "housekeeping: checking floor reference counts"); + for (a=0; a 0) { + flbuf.f_flags = flbuf.f_flags | QR_INUSE; + } + else { + flbuf.f_flags = flbuf.f_flags & ~QR_INUSE; } + lputfloor(&flbuf, a); + syslog(LOG_DEBUG, "housekeeping: floor %d has %d rooms", a, new_refcounts[a]); } +} /* - * Main housekeeping function. This gets run whenever a session terminates. + * Provide hints as to whether we have any memory leaks */ +void keep_an_eye_on_memory_usage(void) { + static void *original_brk = NULL; + if (!original_brk) original_brk = sbrk(0); // Remember the original program break so we can test for leaks + syslog(LOG_DEBUG, "original_brk=%lx, current_brk=%lx, addl=%ld", (long)original_brk, (long)sbrk(0), (long)(sbrk(0)-original_brk)); // FIXME not so noisy please +} + + +/* + * This is the housekeeping loop. Worker threads come through here after + * processing client requests but before jumping back into the pool. We + * only allow housekeeping to execute once per minute, and we only allow one + * instance to run at a time. + */ +static int housekeeping_in_progress = 0; +static time_t last_timer = 0L; void do_housekeeping(void) { + int do_housekeeping_now = 0; + int do_perminute_housekeeping_now = 0; + time_t now; - begin_critical_section(S_HOUSEKEEPING); /* - * Terminate idle sessions. + * We do it this way instead of wrapping the whole loop in an + * S_HOUSEKEEPING critical section because it eliminates the need to + * potentially have multiple concurrent mutexes in progress. */ - lprintf(7, "Calling terminate_idle_sessions()\n"); - terminate_idle_sessions(); + begin_critical_section(S_HOUSEKEEPING); + if (housekeeping_in_progress == 0) { + do_housekeeping_now = 1; + housekeeping_in_progress = 1; + } + end_critical_section(S_HOUSEKEEPING); + + now = time(NULL); + if ( (do_housekeeping_now == 0) && (!CtdlIsSingleUser()) ) { + if ( (now - last_timer) > (time_t)300 ) { + syslog(LOG_WARNING, + "housekeeping: WARNING: housekeeping loop has not run for %ld minutes. Is something stuck?", + ((now - last_timer) / 60) + ); + } + return; + } /* - * If the server is scheduled to shut down the next time all - * users are logged out, now's the time to do it. + * Ok, at this point we've made the decision to run the housekeeping + * loop. Everything below this point is real work. */ - if ((ScheduledShutdown == 1) && (ContextList == NULL)) { - lprintf(3, "Scheduled shutdown initiating.\n"); - master_cleanup(); + + if ( (now - last_timer) > (time_t)60 ) { + do_perminute_housekeeping_now = 1; + last_timer = time(NULL); + } + + /* First, do the "as often as needed" stuff... */ + JournalRunQueue(); + PerformSessionHooks(EVT_HOUSE); + + /* Then, do the "once per minute" stuff... */ + if (do_perminute_housekeeping_now) { + cdb_check_handles(); + PerformSessionHooks(EVT_TIMER); // Run all registered TIMER hooks + +#ifdef HAVE_LDAP // LDAP sync isn't in a module so we can put it here + static time_t last_ldap_sync = 0L; + if ( (now - last_ldap_sync) > (time_t)CtdlGetConfigLong("c_ldap_sync_freq") ) { + CtdlSynchronizeUsersFromLDAP(); + last_ldap_sync = time(NULL); } - end_critical_section(S_HOUSEKEEPING); +#endif + + keep_an_eye_on_memory_usage(); } + /* + * All done. + */ + begin_critical_section(S_HOUSEKEEPING); + housekeeping_in_progress = 0; + end_critical_section(S_HOUSEKEEPING); +} -/* - * Check (and fix) floor reference counts. This doesn't need to be done - * very often, since the counts should remain correct during normal operation. - */ -void check_ref_counts(void) { - int ref[MAXFLOORS]; - struct quickroom qrbuf; - struct floor flbuf; - int a; +void CtdlDisableHouseKeeping(void) { + int ActiveBackgroundJobs; + int do_housekeeping_now = 0; + struct CitContext *nptr; + int nContexts, i; + +retry_block_housekeeping: + syslog(LOG_INFO, "housekeeping: trying to disable services"); + begin_critical_section(S_HOUSEKEEPING); + if (housekeeping_in_progress == 0) { + do_housekeeping_now = 1; + housekeeping_in_progress = 1; + } + end_critical_section(S_HOUSEKEEPING); + if (do_housekeeping_now == 0) { + usleep(1000000); + goto retry_block_housekeeping; + } + + syslog(LOG_INFO, "housekeeping: checking for running server jobs"); - for (a=0; a 0) flbuf.f_flags = flbuf.f_flags | QR_INUSE ; - lputfloor(&flbuf, a); - } - } +void CtdlEnableHouseKeeping(void) { + begin_critical_section(S_HOUSEKEEPING); + housekeeping_in_progress = 0; + end_critical_section(S_HOUSEKEEPING); +}