diff --git a/postfix/HISTORY b/postfix/HISTORY index 3911a4883..7e074741d 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -15602,3 +15602,16 @@ Apologies for any names omitted. Final slution for the I/O event starvation problem when a timer call-back schedules a zero-delay timer request. File: util/events.c. + +20091231 + + Cleanup: the non-shared, in-memory hash table is now + accessible as the "internal:" map type. This simplifies + code by eliminating some special cases. Files: util/dict_ht.c, + util/dict_open.c, and documentation. + +20100101 + + Bugfix: the mantools/postlink script applied hyperlinks + for the "virtual:" transport to "/etc/postfix/virtual:". + Symptom reported by Christoph Anton Mitterer. diff --git a/postfix/README_FILES/DATABASE_README b/postfix/README_FILES/DATABASE_README index 31796e0a6..284f391e5 100644 --- a/postfix/README_FILES/DATABASE_README +++ b/postfix/README_FILES/DATABASE_README @@ -204,6 +204,9 @@ To find out what database types your Postfix system supports, use the "ppooss created with the postmap(1) or postalias(1) command. The database name as used in "hash:table" is the database file name without the ".db" suffix. + iinntteerrnnaall + A non-shared, in-memory hash table. Its content are lost when a process + terminates. llddaapp (read-only) Perform lookups using the LDAP protocol. Configuration details are given in the ldap_table(5). diff --git a/postfix/RELEASE_NOTES b/postfix/RELEASE_NOTES index 95f1d77df..2782086a5 100644 --- a/postfix/RELEASE_NOTES +++ b/postfix/RELEASE_NOTES @@ -14,7 +14,7 @@ specifies the release date of a stable release or snapshot release. If you upgrade from Postfix 2.5 or earlier, read RELEASE_NOTES-2.6 before proceeding. -Incompatibility with snapshot 20091229 +Incompatibility with snapshot 20100101 ====================================== The verify(8) service now uses a persistent cache by default @@ -24,9 +24,9 @@ disable, specify "address_verify_map =" in main.cf. When periodic cache cleanup is enabled (the default), the postscreen(8) and verify(8) servers now require that their cache databases support the "delete" and "sequence" operations. To disable periodic cache -cleanup specify a zero xxx_cache_cleanup_interval. +cleanup specify a zero xxx_cache_cleanup_interval value. -Major changes with snapshot 20091229 +Major changes with snapshot 20100101 ==================================== Periodic cache cleanup for the postscreen(8) and verify(8) cache diff --git a/postfix/html/ADDRESS_REWRITING_README.html b/postfix/html/ADDRESS_REWRITING_README.html index 609060dea..e934bf310 100644 --- a/postfix/html/ADDRESS_REWRITING_README.html +++ b/postfix/html/ADDRESS_REWRITING_README.html @@ -785,7 +785,7 @@ commas.
/etc/postfix/main.cf: virtual_alias_maps = hash:/etc/postfix/virtual -/etc/postfix/virtual: +/etc/postfix/virtual: Wietse.Venema wietse diff --git a/postfix/html/DATABASE_README.html b/postfix/html/DATABASE_README.html index 642ce78c4..5d85c8bee 100644 --- a/postfix/html/DATABASE_README.html +++ b/postfix/html/DATABASE_README.html @@ -299,6 +299,11 @@ created with the postmap(1) or +An address is always considered "known" when it matches a +virtual(5) alias or a canonical(5) mapping. +
-The maximal size in bytes of an individual mailbox or maildir file, -or zero (no limit). -
+The maximal size in bytes of an individual virtual(8) mailbox or +maildir file, or zero (no limit).An address is always considered "known" when it matches a +virtual(5) alias or a canonical(5) mapping. +
An address is always considered "known" when it matches a +virtual(5) alias or a canonical(5) mapping. +
-The maximal size in bytes of an individual mailbox or maildir file, -or zero (no limit). -
+The maximal size in bytes of an individual virtual(8) mailbox or +maildir file, or zero (no limit). %PARAM virtual_mailbox_lock see "postconf -d" output diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index 5da201516..ef6c78c8c 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -20,7 +20,7 @@ * Patches change both the patchlevel and the release date. Snapshots have no * patchlevel; they change the release date only. */ -#define MAIL_RELEASE_DATE "20091229" +#define MAIL_RELEASE_DATE "20100101" #define MAIL_VERSION_NUMBER "2.7" #ifdef SNAPSHOT diff --git a/postfix/src/postconf/postconf.c b/postfix/src/postconf/postconf.c index cebe6cacb..d1ae43427 100644 --- a/postfix/src/postconf/postconf.c +++ b/postfix/src/postconf/postconf.c @@ -121,6 +121,9 @@ /* An indexed file type based on hashing. /* This is available on systems with support for Berkeley DB /* databases. +/* .IP \fBinternal\fR +/* A non-shared, in-memory hash table. Its content are lost +/* when a process terminates. /* .IP "\fBldap\fR (read-only)" /* Perform lookups using the LDAP protocol. This is described /* in \fBldap_table\fR(5). diff --git a/postfix/src/postscreen/postscreen.c b/postfix/src/postscreen/postscreen.c index c0a6ede27..bef281ff4 100644 --- a/postfix/src/postscreen/postscreen.c +++ b/postfix/src/postscreen/postscreen.c @@ -1343,12 +1343,16 @@ static void post_jail_init(char *unused_name, char **unused_argv) * verbose logging more informative (we get positive confirmation that * the cleanup thread runs). */ - expire_flags = DICT_CACHE_FLAG_EXP_SUMMARY; + expire_flags = DICT_CACHE_FLAG_STATISTICS; if (msg_verbose) - expire_flags |= DICT_CACHE_FLAG_EXP_VERBOSE; + expire_flags |= DICT_CACHE_FLAG_VERBOSE; if (cache_map != 0 && var_ps_cache_scan > 0) - dict_cache_expire(cache_map, expire_flags, var_ps_cache_scan, - postscreen_cache_validator, (char *) 0); + dict_cache_control(cache_map, + DICT_CACHE_CTL_FLAGS, expire_flags, + DICT_CACHE_CTL_INTERVAL, var_ps_cache_scan, + DICT_CACHE_CTL_VALIDATOR, postscreen_cache_validator, + DICT_CACHE_CTL_CONTEXT, (char *) 0, + DICT_CACHE_CTL_END); } MAIL_VERSION_STAMP_DECLARE; diff --git a/postfix/src/smtpd/smtpd_exp.ref b/postfix/src/smtpd/smtpd_exp.ref index f514c5457..c4d518afa 100644 --- a/postfix/src/smtpd/smtpd_exp.ref +++ b/postfix/src/smtpd/smtpd_exp.ref @@ -118,7 +118,7 @@ OK >>> helo verisign.com OK >>> helo example.tld -./smtpd_check: warning: Unable to look up MX host for example.tld: Host not found +./smtpd_check: warning: Unable to look up MX host example.tld for Helo command example.tld: hostname nor servname provided, or not known OK >>> sender_restrictions check_sender_mx_access,hash:smtpd_check_access OK diff --git a/postfix/src/util/Makefile.in b/postfix/src/util/Makefile.in index 48f9fae22..4a8088840 100644 --- a/postfix/src/util/Makefile.in +++ b/postfix/src/util/Makefile.in @@ -820,6 +820,7 @@ dict_ht.o: dict_ht.c dict_ht.o: dict_ht.h dict_ht.o: htable.h dict_ht.o: mymalloc.h +dict_ht.o: stringops.h dict_ht.o: sys_defs.h dict_ht.o: vbuf.h dict_ht.o: vstream.h @@ -855,6 +856,7 @@ dict_open.o: dict_cidr.h dict_open.o: dict_db.h dict_open.o: dict_dbm.h dict_open.o: dict_env.h +dict_open.o: dict_ht.h dict_open.o: dict_ni.h dict_open.o: dict_nis.h dict_open.o: dict_nisplus.h diff --git a/postfix/src/util/dict.c b/postfix/src/util/dict.c index 68645d401..b8813f831 100644 --- a/postfix/src/util/dict.c +++ b/postfix/src/util/dict.c @@ -290,7 +290,7 @@ void dict_update(const char *dict_name, const char *member, const char *value if ((node = dict_node(dict_name)) == 0) { if (dict_unknown_allowed == 0) msg_fatal("%s: unknown dictionary: %s", myname, dict_name); - dict = dict_ht_open(dict_name, htable_create(0), myfree); + dict = dict_ht_open(dict_name, O_CREAT | O_RDWR, 0); dict_register(dict_name, dict); } else dict = node->dict; @@ -334,7 +334,7 @@ int dict_delete(const char *dict_name, const char *member) if ((node = dict_node(dict_name)) == 0) { if (dict_unknown_allowed == 0) msg_fatal("%s: unknown dictionary: %s", myname, dict_name); - dict = dict_ht_open(dict_name, htable_create(0), myfree); + dict = dict_ht_open(dict_name, O_CREAT | O_RDWR, 0); dict_register(dict_name, dict); } else dict = node->dict; @@ -358,7 +358,7 @@ int dict_sequence(const char *dict_name, const int func, if ((node = dict_node(dict_name)) == 0) { if (dict_unknown_allowed == 0) msg_fatal("%s: unknown dictionary: %s", myname, dict_name); - dict = dict_ht_open(dict_name, htable_create(0), myfree); + dict = dict_ht_open(dict_name, O_CREAT | O_RDWR, 0); dict_register(dict_name, dict); } else dict = node->dict; diff --git a/postfix/src/util/dict_cache.c b/postfix/src/util/dict_cache.c index 16e17037d..e079dcbc0 100644 --- a/postfix/src/util/dict_cache.c +++ b/postfix/src/util/dict_cache.c @@ -32,20 +32,16 @@ /* int first_next; /* const char **cache_key; /* const char **cache_val; -/* -/* void dict_cache_expire(cache, flags, interval, validator, context) -/* DICT_CACHE *cache; -/* int flags; -/* int interval; -/* int (*validator)(const char *cache_key, const char *cache_val, -/* char *context); -/* char *context; /* AUXILIARY FUNCTIONS +/* void dict_cache_control(cache, name, value, ...) +/* DICT_CACHE *cache; +/* int name; +/* +/* typedef int (*DICT_CACHE_VALIDATOR_FN) (const char *cache_key, +/* const char *cache_val, char *context); +/* /* const char *dict_cache_name(cache) /* DICT_CACHE *cache; -/* -/* DICT_CACHE *dict_cache_import(table) -/* DICT *table; /* DESCRIPTION /* This module maintains external cache files with support /* for expiration. The underlying table must implement the @@ -56,22 +52,23 @@ /* between the iterators that access all cache elements, and /* other operations that access individual cache elements. /* -/* In particular, when a "sequence" or "expire" operation is +/* In particular, when a "sequence" or "cleanup" operation is /* in progress the cache intercepts requests to delete the /* "current" entry, as this would cause some databases to /* mis-behave. Instead, the cache implements a "delete behind" /* strategy, and deletes such an entry after the "sequence" -/* or "expire" operation moves on to the next cache element. +/* or "cleanup" operation moves on to the next cache element. /* The "delete behind" strategy also affects the cache lookup /* and update operations as detailed below. /* -/* dict_cache_open() opens the specified cache and returns a -/* handle that must be used for subsequent access. This function -/* does not return in case of error. +/* dict_cache_open() is a wrapper around the dict_open() +/* function. It opens the specified cache and returns a handle +/* that must be used for subsequent access. This function does +/* not return in case of error. /* /* dict_cache_close() closes the specified cache and releases /* memory that was allocated by dict_cache_open(), and terminates -/* any thread that was started with dict_cache_expire(). +/* any thread that was started with dict_cache_control(). /* /* dict_cache_lookup() looks up the specified cache entry. /* The result value is a null pointer when the cache entry was @@ -80,9 +77,9 @@ /* /* dict_cache_update() updates the specified cache entry. If /* the entry is scheduled for "delete behind", the delete -/* operation is canceled (meaning that the cache must be opened -/* with DICT_FLAG_DUP_REPLACE). This function does not return -/* in case of error. +/* operation is canceled (because of this, the cache must be +/* opened with DICT_FLAG_DUP_REPLACE). This function does not +/* return in case of error. /* /* dict_cache_delete() removes the specified cache entry. If /* this is the "current" entry of a "sequence" operation, the @@ -91,25 +88,45 @@ /* /* dict_cache_sequence() iterates over the specified cache and /* returns each entry in an implementation-defined order. The -/* result value is zero when a cache entry was found. Programs -/* must not use both dict_cache_sequence() and dict_cache_expire(). +/* result value is zero when a cache entry was found. /* -/* dict_cache_expire() schedules a thread that expires cache -/* entries periodically. Specify a null validator argument to -/* cancel the thread. It is an error to schedule a cache -/* cleanup thread when one already exists. Programs must not -/* use both dict_cache_sequence() and dict_cache_expire(). +/* Important: programs must not use both dict_cache_sequence() +/* and the built-in cache cleanup feature. /* +/* dict_cache_control() provides control over the built-in +/* cache cleanup feature and logging. The arguments are a list +/* of (name, value) pairs, terminated with DICT_CACHE_CTL_END. +/* The following lists the names and the types of the corresponding +/* value arguments. +/* .IP "DICT_CACHE_FLAGS (int flags)" +/* The arguments to this command are the bit-wise OR of zero +/* or more of the following: +/* .RS +/* .IP DICT_CACHE_FLAG_VERBOSE +/* Enable verbose logging of cache activity. +/* .IP DICT_CACHE_FLAG_EXP_SUMMARY +/* Log cache statistics after each cache cleanup run. +/* .RE +/* .IP "DICT_CACHE_CTL_INTERVAL (int interval)" +/* The interval between cache cleanup runs. Specify a null +/* validator or interval to stop cache cleanup. +/* .IP "DICT_CACHE_CTL_VALIDATOR (DICT_CACHE_VALIDATOR_FN validator)" +/* An application call-back routine that returns non-zero when +/* a cache entry should be kept. The call-back function should +/* not make changes to the cache. Specify a null validator or +/* interval to stop cache cleanup. +/* .IP "DICT_CACHE_CTL_CONTEXT (char *context)" +/* Application context that is passed to the validator function. +/* .RE +/* .PP /* dict_cache_name() returns the name of the specified cache. /* -/* dict_cache_import() encapsulates a pre-opened database -/* handle and adds the above features. -/* /* Arguments: /* .IP "dbname, open_flags, dict_flags" -/* These are passed unchanged to dict_open(). +/* These are passed unchanged to dict_open(). The cache must +/* be opened with DICT_FLAG_DUP_REPLACE. /* .IP cache -/* Cache handle created with dict_cache_open()or dict_cache_import(). +/* Cache handle created with dict_cache_open(). /* .IP cache_key /* Cache lookup key. /* .IP cache_val @@ -121,24 +138,6 @@ /* Note: there is no "stop" request. To ensure that the "delete /* behind" strategy does not interfere with database access, /* allow dict_cache_sequence() to run to completion. -/* .IP flags -/* Bit-wise OR of zero or more of the following: -/* .RS -/* .IP DICT_CACHE_FLAG_EXP_VERBOSE -/* Log each cache entry's status during a cache cleanup run. -/* .IP DICT_CACHE_FLAG_EXP_SUMMARY -/* Log the number of cache entries retained and dropped after -/* a cache cleaning run. -/* .RE -/* .IP interval -/* The non-zero time between scans for expired cache entries. -/* The interval timer starts after a scan completes. -/* .IP validator -/* Application call-back routine that returns non-zero when a -/* cache entry should be kept. The validator must not modify -/* or close the cache. -/* .IP context -/* Application-specific context. /* .IP table /* A bare dictonary handle. /* DIAGNOSTICS @@ -198,15 +197,15 @@ * underlying database. */ struct DICT_CACHE { - int flags; /* see below */ + int cache_flags; /* see below */ + int user_flags; /* logging */ DICT *db; /* database handle */ - /* Iterator support. */ + /* Delete-behind support. */ char *saved_curr_key; /* "current" cache lookup key */ char *saved_curr_val; /* "current" cache lookup result */ /* Cleanup support. */ - int exp_flags; /* logging */ int exp_interval; /* time between cleanup runs */ DICT_CACHE_VALIDATOR_FN exp_validator; /* expiration call-back */ char *exp_context; /* call-back context */ @@ -220,20 +219,20 @@ struct DICT_CACHE { * Macros to make obscure code more readable. */ #define DC_SCHEDULE_FOR_DELETE_BEHIND(cp) \ - ((cp)->flags |= DC_FLAG_DEL_SAVED_CURRENT_KEY) + ((cp)->cache_flags |= DC_FLAG_DEL_SAVED_CURRENT_KEY) #define DC_MATCH_SAVED_CURRENT_KEY(cp, cache_key) \ ((cp)->saved_curr_key && strcmp((cp)->saved_curr_key, (cache_key)) == 0) #define DC_IS_SCHEDULED_FOR_DELETE_BEHIND(cp) \ (/* NOT: (cp)->saved_curr_key && */ \ - ((cp)->flags & DC_FLAG_DEL_SAVED_CURRENT_KEY) != 0) + ((cp)->cache_flags & DC_FLAG_DEL_SAVED_CURRENT_KEY) != 0) #define DC_CANCEL_DELETE_BEHIND(cp) \ - ((cp)->flags &= ~DC_FLAG_DEL_SAVED_CURRENT_KEY) + ((cp)->cache_flags &= ~DC_FLAG_DEL_SAVED_CURRENT_KEY) /* - * Special key to store the time of last cache cleanup run completion. + * Special key to store the time of the last cache cleanup run completion. */ #define DC_LAST_CACHE_CLEANUP_COMPLETED "_LAST_CACHE_CLEANUP_COMPLETED_" @@ -241,16 +240,25 @@ struct DICT_CACHE { const char *dict_cache_lookup(DICT_CACHE *cp, const char *cache_key) { + const char *myname = "dict_cache_lookup"; + const char *cache_val; /* - * Search for the cache entry. Don't return an entry that was scheduled - * for deletion. + * Search for the cache entry. Don't return an entry that is scheduled + * for delete-behind. */ if (DC_IS_SCHEDULED_FOR_DELETE_BEHIND(cp) && DC_MATCH_SAVED_CURRENT_KEY(cp, cache_key)) { + if (cp->user_flags & DICT_CACHE_FLAG_VERBOSE) + msg_info("%s: key=%s (pretend not found - scheduled for deletion)", + myname, cache_key); return (0); } else { - return (dict_get(cp->db, cache_key)); + cache_val = dict_get(cp->db, cache_key); + if (cp->user_flags & DICT_CACHE_FLAG_VERBOSE) + msg_info("%s: key=%s value=%s", myname, cache_key, + cache_val ? cache_val : "(not found)"); + return (cache_val); } } @@ -259,13 +267,19 @@ const char *dict_cache_lookup(DICT_CACHE *cp, const char *cache_key) void dict_cache_update(DICT_CACHE *cp, const char *cache_key, const char *cache_val) { + const char *myname = "dict_cache_update"; /* - * Store the cache entry and cancel a scheduled delete-behind operation. + * Store the cache entry and cancel the delete-behind operation. */ if (DC_IS_SCHEDULED_FOR_DELETE_BEHIND(cp) - && DC_MATCH_SAVED_CURRENT_KEY(cp, cache_key)) + && DC_MATCH_SAVED_CURRENT_KEY(cp, cache_key)) { + if (cp->user_flags & DICT_CACHE_FLAG_VERBOSE) + msg_info("%s: cancel delete-behind for key=%s", myname, cache_key); DC_CANCEL_DELETE_BEHIND(cp); + } + if (cp->user_flags & DICT_CACHE_FLAG_VERBOSE) + msg_info("%s: key=%s value=%s", myname, cache_key, cache_val); dict_put(cp->db, cache_key, cache_val); } @@ -273,18 +287,25 @@ void dict_cache_update(DICT_CACHE *cp, const char *cache_key, int dict_cache_delete(DICT_CACHE *cp, const char *cache_key) { + const char *myname = "dict_cache_delete"; int zero_means_found; /* * Delete the entry, unless we would delete the current first/next entry. - * Instead, schedule the "current" entry for delete-behind to avoid + * In that case, schedule the "current" entry for delete-behind to avoid * mis-behavior by some databases. */ if (DC_MATCH_SAVED_CURRENT_KEY(cp, cache_key)) { DC_SCHEDULE_FOR_DELETE_BEHIND(cp); + if (cp->user_flags & DICT_CACHE_FLAG_VERBOSE) + msg_info("%s: key=%s (current entry - schedule for delete-behind)", + myname, cache_key); zero_means_found = 0; } else { zero_means_found = dict_del(cp->db, cache_key); + if (cp->user_flags & DICT_CACHE_FLAG_VERBOSE) + msg_info("%s: key=%s (%s)", myname, cache_key, + zero_means_found == 0 ? "found" : "not found"); } return (zero_means_found); } @@ -295,6 +316,7 @@ int dict_cache_sequence(DICT_CACHE *cp, int first_next, const char **cache_key, const char **cache_val) { + const char *myname = "dict_cache_sequence"; int zero_means_found; const char *raw_cache_key; const char *raw_cache_val; @@ -311,6 +333,10 @@ int dict_cache_sequence(DICT_CACHE *cp, int first_next, && strcmp(raw_cache_key, DC_LAST_CACHE_CLEANUP_COMPLETED) == 0) zero_means_found = dict_seq(cp->db, DICT_SEQ_FUN_NEXT, &raw_cache_key, &raw_cache_val); + if (cp->user_flags & DICT_CACHE_FLAG_VERBOSE) + msg_info("%s: key=%s value=%s", myname, + zero_means_found == 0 ? raw_cache_key : "(not found)", + zero_means_found == 0 ? raw_cache_val : "(not found)"); /* * Save the current cache_key and cache_val before they are clobbered by @@ -335,6 +361,9 @@ int dict_cache_sequence(DICT_CACHE *cp, int first_next, */ if (DC_IS_SCHEDULED_FOR_DELETE_BEHIND(cp)) { DC_CANCEL_DELETE_BEHIND(cp); + if (cp->user_flags & DICT_CACHE_FLAG_VERBOSE) + msg_info("%s: delete-behind key=%s value=%s", + myname, previous_curr_key, previous_curr_val); if (dict_del(cp->db, previous_curr_key) != 0) msg_warn("database %s: could not delete entry for %s", cp->db->name, previous_curr_key); @@ -370,18 +399,19 @@ static void dict_cache_delete_behind_reset(DICT_CACHE *cp) /* dict_cache_clean_stat_log_reset - log and reset cache cleanup statistics */ static void dict_cache_clean_stat_log_reset(DICT_CACHE *cp, - const char *full_partial) + const char *full_partial) { - if (cp->flags & DICT_CACHE_FLAG_EXP_SUMMARY) + if (cp->user_flags & DICT_CACHE_FLAG_STATISTICS) msg_info("cache %s %s cleanup: retained=%d dropped=%d entries", cp->db->name, full_partial, cp->retained, cp->dropped); cp->retained = cp->dropped = 0; } -/* dict_cache_expire_event - examine one cache entry */ +/* dict_cache_clean_event - examine one cache entry */ -static void dict_cache_expire_event(int unused_event, char *cache_context) +static void dict_cache_clean_event(int unused_event, char *cache_context) { + const char *myname = "dict_cache_clean_event"; DICT_CACHE *cp = (DICT_CACHE *) cache_context; const char *cache_key; const char *cache_val; @@ -401,8 +431,8 @@ static void dict_cache_expire_event(int unused_event, char *cache_context) if (cp->saved_curr_key == 0) { cp->retained = cp->dropped = 0; first_next = DICT_SEQ_FUN_FIRST; - if (cp->exp_flags & DICT_CACHE_FLAG_EXP_VERBOSE) - msg_info("start %s cache cleanup", cp->db->name); + if (cp->user_flags & DICT_CACHE_FLAG_VERBOSE) + msg_info("%s: start %s cache cleanup", myname, cp->db->name); } /* @@ -419,12 +449,14 @@ static void dict_cache_expire_event(int unused_event, char *cache_context) if (cp->exp_validator(cache_key, cache_val, cp->exp_context) == 0) { DC_SCHEDULE_FOR_DELETE_BEHIND(cp); cp->dropped++; - if (cp->exp_flags & DICT_CACHE_FLAG_EXP_VERBOSE) - msg_info("drop %s cache entry for %s", cp->db->name, cache_key); + if (cp->user_flags & DICT_CACHE_FLAG_VERBOSE) + msg_info("%s: drop %s cache entry for %s", + myname, cp->db->name, cache_key); } else { cp->retained++; - if (cp->exp_flags & DICT_CACHE_FLAG_EXP_VERBOSE) - msg_info("keep %s cache entry for %s", cp->db->name, cache_key); + if (cp->user_flags & DICT_CACHE_FLAG_VERBOSE) + msg_info("%s: keep %s cache entry for %s", + myname, cp->db->name, cache_key); } next_interval = 0; } @@ -433,8 +465,8 @@ static void dict_cache_expire_event(int unused_event, char *cache_context) * Cache cleanup completed. Report vital statistics. */ else { - if (cp->exp_flags & DICT_CACHE_FLAG_EXP_VERBOSE) - msg_info("done %s cache cleanup scan", cp->db->name); + if (cp->user_flags & DICT_CACHE_FLAG_VERBOSE) + msg_info("%s: done %s cache cleanup scan", myname, cp->db->name); dict_cache_clean_stat_log_reset(cp, "full"); stamp_buf = vstring_alloc(100); vstring_sprintf(stamp_buf, "%ld", (long) event_time()); @@ -443,37 +475,60 @@ static void dict_cache_expire_event(int unused_event, char *cache_context) vstring_free(stamp_buf); next_interval = cp->exp_interval; } - event_request_timer(dict_cache_expire_event, cache_context, next_interval); + event_request_timer(dict_cache_clean_event, cache_context, next_interval); } -/* dict_cache_expire - schedule or stop the cache cleanup thread */ +/* dict_cache_control - schedule or stop the cache cleanup thread */ -void dict_cache_expire(DICT_CACHE *cp, int flags, int interval, - DICT_CACHE_VALIDATOR_FN validator, - char *context) +void dict_cache_control(DICT_CACHE *cp,...) { - const char *myname = "dict_cache_expire"; + const char *myname = "dict_cache_control"; const char *last_done; time_t next_interval; + int cache_cleanup_is_active = (cp->exp_validator && cp->exp_interval); + va_list ap; + int name; + + /* + * Update the control settings. + */ + va_start(ap, cp); + while ((name = va_arg(ap, int)) > 0) { + switch (name) { + case DICT_CACHE_CTL_END: + break; + case DICT_CACHE_CTL_FLAGS: + cp->user_flags = va_arg(ap, int); + break; + case DICT_CACHE_CTL_INTERVAL: + cp->exp_interval = va_arg(ap, int); + if (cp->exp_interval < 0) + msg_panic("%s: bad %s cache cleanup interval %d", + myname, cp->db->name, cp->exp_interval); + break; + case DICT_CACHE_CTL_VALIDATOR: + cp->exp_validator = va_arg(ap, DICT_CACHE_VALIDATOR_FN); + break; + case DICT_CACHE_CTL_CONTEXT: + cp->exp_context = va_arg(ap, char *); + break; + default: + msg_panic("%s: bad command: %d", myname, name); + } + } + va_end(ap); /* * Schedule the cache cleanup thread. */ - if (validator != 0) { + if (cp->exp_interval && cp->exp_validator) { /* * Sanity checks. */ - if (cp->exp_validator != 0) + if (cache_cleanup_is_active) msg_panic("%s: %s cache cleanup is already scheduled", myname, cp->db->name); - if (interval <= 0) - msg_panic("%s: bad %s cache cleanup interval %d", - myname, cp->db->name, interval); - cp->exp_flags = flags; - cp->exp_interval = interval; - cp->exp_validator = validator; - cp->exp_context = context; /* * The next start time depends on the last completion time. @@ -482,28 +537,25 @@ void dict_cache_expire(DICT_CACHE *cp, int flags, int interval, #define NOW (time((time_t *) 0)) /* NOT: event_time() */ if ((last_done = dict_get(cp->db, DC_LAST_CACHE_CLEANUP_COMPLETED)) == 0 - || (next_interval = (NEXT_START(last_done, interval) - NOW)) < 0) + || (next_interval = (NEXT_START(last_done, cp->exp_interval) - NOW)) < 0) next_interval = 0; - if (next_interval > interval) - next_interval = interval; - if ((cp->exp_flags & DICT_CACHE_FLAG_EXP_VERBOSE) && next_interval > 0) + if (next_interval > cp->exp_interval) + next_interval = cp->exp_interval; + if ((cp->user_flags & DICT_CACHE_FLAG_VERBOSE) && next_interval > 0) msg_info("%s cache cleanup will start after %ds", cp->db->name, (int) next_interval); - event_request_timer(dict_cache_expire_event, (char *) cp, + event_request_timer(dict_cache_clean_event, (char *) cp, (int) next_interval); } /* * Cancel the cache cleanup thread. */ - else if (cp->exp_validator) { + else if (cache_cleanup_is_active) { if (cp->retained || cp->dropped) dict_cache_clean_stat_log_reset(cp, "partial"); dict_cache_delete_behind_reset(cp); - cp->exp_interval = 0; - cp->exp_validator = 0; - cp->exp_context = 0; - event_cancel_timer(dict_cache_expire_event, (char *) cp); + event_cancel_timer(dict_cache_clean_event, (char *) cp); } } @@ -511,6 +563,7 @@ void dict_cache_expire(DICT_CACHE *cp, int flags, int interval, DICT_CACHE *dict_cache_open(const char *dbname, int open_flags, int dict_flags) { + DICT_CACHE *cp; DICT *dict; /* @@ -518,20 +571,13 @@ DICT_CACHE *dict_cache_open(const char *dbname, int open_flags, int dict_flags) * application. */ dict = dict_open(dbname, open_flags, dict_flags); - return (dict_cache_import(dict)); -} - -/* dict_cache_import - encapsulate pre-opened database */ - -DICT_CACHE *dict_cache_import(DICT *dict) -{ - DICT_CACHE *cp; /* * Create the DICT_CACHE object. */ cp = (DICT_CACHE *) mymalloc(sizeof(*cp)); - cp->flags = 0; + cp->cache_flags = 0; + cp->user_flags = 0; cp->db = dict; cp->saved_curr_key = 0; cp->saved_curr_val = 0; @@ -552,8 +598,7 @@ void dict_cache_close(DICT_CACHE *cp) /* * Destroy the DICT_CACHE object. */ - if (cp->exp_validator) - dict_cache_expire(cp, 0, 0, (DICT_CACHE_VALIDATOR_FN) 0, (char *) 0); + dict_cache_control(cp, DICT_CACHE_CTL_INTERVAL, 0, DICT_CACHE_CTL_END); dict_close(cp->db); if (cp->saved_curr_key) myfree(cp->saved_curr_key); diff --git a/postfix/src/util/dict_cache.h b/postfix/src/util/dict_cache.h index 08523c412..33d606124 100644 --- a/postfix/src/util/dict_cache.h +++ b/postfix/src/util/dict_cache.h @@ -28,12 +28,17 @@ extern const char *dict_cache_lookup(DICT_CACHE *, const char *); extern void dict_cache_update(DICT_CACHE *, const char *, const char *); extern int dict_cache_delete(DICT_CACHE *, const char *); extern int dict_cache_sequence(DICT_CACHE *, int, const char **, const char **); -extern void dict_cache_expire(DICT_CACHE *, int, int, DICT_CACHE_VALIDATOR_FN, char *); +extern void dict_cache_control(DICT_CACHE *,...); extern const char *dict_cache_name(DICT_CACHE *); -extern DICT_CACHE *dict_cache_import(DICT *); -#define DICT_CACHE_FLAG_EXP_VERBOSE (1<<0) -#define DICT_CACHE_FLAG_EXP_SUMMARY (1<<1) +#define DICT_CACHE_FLAG_VERBOSE (1<<0) /* verbose operation */ +#define DICT_CACHE_FLAG_STATISTICS (1<<1) /* log cache statistics */ + +#define DICT_CACHE_CTL_END 0 /* list terminator */ +#define DICT_CACHE_CTL_FLAGS 1 /* see above */ +#define DICT_CACHE_CTL_INTERVAL 2 /* cleanup interval */ +#define DICT_CACHE_CTL_VALIDATOR 3 /* call-back validator */ +#define DICT_CACHE_CTL_CONTEXT 4 /* call-back context */ /* LICENSE /* .ad diff --git a/postfix/src/util/dict_ht.c b/postfix/src/util/dict_ht.c index 55b7c0d62..8e44bad19 100644 --- a/postfix/src/util/dict_ht.c +++ b/postfix/src/util/dict_ht.c @@ -6,17 +6,15 @@ /* SYNOPSIS /* #include