2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-22 09:57:34 +00:00

postfix-2.7-20100101

This commit is contained in:
Wietse Venema 2010-01-01 00:00:00 -05:00 committed by Viktor Dukhovni
parent 2ccf57f4ac
commit a92fc14c5d
32 changed files with 348 additions and 219 deletions

View File

@ -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.

View File

@ -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).

View File

@ -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

View File

@ -785,7 +785,7 @@ commas. </p>
/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#virtual_alias_maps">virtual_alias_maps</a> = hash:/etc/postfix/virtual
/etc/postfix/<a href="virtual.8.html">virtual</a>:
/etc/postfix/virtual:
Wietse.Venema wietse
</pre>
</blockquote>

View File

@ -299,6 +299,11 @@ created with the <a href="postmap.1.html">postmap(1)</a> or <a href="postalias.1
name as used in "hash:table" is the database file name without the
".db" suffix. </dd>
<dt> <b>internal</b> </dt>
<dd> A non-shared, in-memory hash table. Its content are lost when
a process terminates. </dd>
<dt> <b>ldap</b> (read-only) </dt>
<dd> Perform lookups using the LDAP protocol. Configuration details

View File

@ -211,7 +211,7 @@ href="STANDARD_CONFIGURATION_README.html#null_client">null client</a>:
#
root mtaadmin+root=mta1
/etc/postfix/<a href="virtual.8.html">virtual</a>:
/etc/postfix/virtual:
# Caretaker aliases:
#
root mtaadmin

View File

@ -180,7 +180,7 @@ discussed the first half of this document. </p>
9 /etc/postfix/canonical:
10 your-login-name your-account@your-isp.com
11
12 /etc/postfix/<a href="virtual.8.html">virtual</a>:
12 /etc/postfix/virtual:
13 your-account@your-isp.com your-login-name
</pre>
</blockquote>

View File

@ -319,7 +319,7 @@ All the mail to these two accounts is forwarded to an inside address.
1 /etc/postfix/<a href="postconf.5.html">main.cf</a>:
2 <a href="postconf.5.html#virtual_alias_maps">virtual_alias_maps</a> = hash:/etc/postfix/virtual
3
4 /etc/postfix/<a href="virtual.8.html">virtual</a>:
4 /etc/postfix/virtual:
5 postmaster postmaster@example.com
6 abuse abuse@example.com
</pre>
@ -425,7 +425,7 @@ follows: </p>
1 /etc/postfix/<a href="postconf.5.html">main.cf</a>:
2 <a href="postconf.5.html#virtual_alias_maps">virtual_alias_maps</a> = hash:/etc/postfix/virtual
3
4 /etc/postfix/<a href="virtual.8.html">virtual</a>:
4 /etc/postfix/virtual:
5 root root@localhost
6 . . .
</pre>
@ -785,7 +785,7 @@ discussed the first half of this document. </p>
9 /etc/postfix/canonical:
10 your-login-name your-account@your-isp.com
11
12 /etc/postfix/<a href="virtual.8.html">virtual</a>:
12 /etc/postfix/virtual:
13 your-account@your-isp.com your-login-name
</pre>
</blockquote>

View File

@ -167,7 +167,7 @@ below shows how to use this mechanism for the example.com domain.
2 <a href="postconf.5.html#virtual_alias_domains">virtual_alias_domains</a> = example.com ...other <a href="VIRTUAL_README.html#canonical">hosted domains</a>...
3 <a href="postconf.5.html#virtual_alias_maps">virtual_alias_maps</a> = hash:/etc/postfix/virtual
4
5 /etc/postfix/<a href="virtual.8.html">virtual</a>:
5 /etc/postfix/virtual:
6 postmaster@example.com postmaster
7 info@example.com joe
8 sales@example.com jane
@ -271,7 +271,7 @@ section at the top of this document.</p>
14 # @example.com example.com/catchall
15 ...virtual mailboxes for more domains...
16
17 /etc/postfix/<a href="virtual.8.html">virtual</a>:
17 /etc/postfix/virtual:
18 postmaster@example.com postmaster
</pre>
</blockquote>
@ -389,7 +389,7 @@ to a non-Postfix delivery agent: </p>
12 # @example.com whatever
13 ...virtual mailboxes for more domains...
14
15 /etc/postfix/<a href="virtual.8.html">virtual</a>:
15 /etc/postfix/virtual:
16 postmaster@example.com postmaster
</pre>
</blockquote>
@ -486,7 +486,7 @@ as a mail forwarding domain: </p>
2 <a href="postconf.5.html#virtual_alias_domains">virtual_alias_domains</a> = example.com ...other <a href="VIRTUAL_README.html#canonical">hosted domains</a>...
3 <a href="postconf.5.html#virtual_alias_maps">virtual_alias_maps</a> = hash:/etc/postfix/virtual
4
5 /etc/postfix/<a href="virtual.8.html">virtual</a>:
5 /etc/postfix/virtual:
6 postmaster@example.com postmaster
7 joe@example.com joe@somewhere
8 jane@example.com jane@somewhere-else
@ -553,7 +553,7 @@ virtual addresses to the local delivery agent: </p>
/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#virtual_alias_maps">virtual_alias_maps</a> = hash:/etc/postfix/virtual
/etc/postfix/<a href="virtual.8.html">virtual</a>:
/etc/postfix/virtual:
listname-request@example.com listname-request
listname@example.com listname
owner-listname@example.com owner-listname
@ -601,7 +601,7 @@ table: </p>
/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#virtual_alias_maps">virtual_alias_maps</a> = hash:/etc/postfix/virtual
/etc/postfix/<a href="virtual.8.html">virtual</a>:
/etc/postfix/virtual:
user@domain.tld user@domain.tld, user@domain.tld@autoreply.<a href="postconf.5.html#mydomain">mydomain</a>.tld
</pre>
</blockquote>

View File

@ -140,67 +140,71 @@ POSTCONF(1) POSTCONF(1)
is available on systems with support for
Berkeley DB databases.
<b>internal</b>
A non-shared, in-memory hash table. Its con-
tent are lost when a process terminates.
<b>ldap</b> (read-only)
Perform lookups using the LDAP protocol.
Perform lookups using the LDAP protocol.
This is described in <a href="ldap_table.5.html"><b>ldap_table</b>(5)</a>.
<b>mysql</b> (read-only)
Perform lookups using the MYSQL protocol.
Perform lookups using the MYSQL protocol.
This is described in <a href="mysql_table.5.html"><b>mysql_table</b>(5)</a>.
<b>pcre</b> (read-only)
A lookup table based on Perl Compatible Reg-
ular Expressions. The file format is
ular Expressions. The file format is
described in <a href="pcre_table.5.html"><b>pcre_table</b>(5)</a>.
<b>pgsql</b> (read-only)
Perform lookups using the PostgreSQL proto-
Perform lookups using the PostgreSQL proto-
col. This is described in <a href="pgsql_table.5.html"><b>pgsql_table</b>(5)</a>.
<b>proxy</b> (read-only)
A lookup table that is implemented via the
Postfix <a href="proxymap.8.html"><b>proxymap</b>(8)</a> service. The table name
A lookup table that is implemented via the
Postfix <a href="proxymap.8.html"><b>proxymap</b>(8)</a> service. The table name
syntax is <i>type</i><b>:</b><i>name</i>.
<b>regexp</b> (read-only)
A lookup table based on regular expressions.
The file format is described in <a href="regexp_table.5.html"><b>regexp_ta-</b></a>
The file format is described in <a href="regexp_table.5.html"><b>regexp_ta-</b></a>
<a href="regexp_table.5.html"><b>ble</b>(5)</a>.
<b>sdbm</b> An indexed file type based on hashing. This
is available on systems with support for
is available on systems with support for
SDBM databases.
<b>static</b> (read-only)
A table that always returns its name as
lookup result. For example, <b>static:foobar</b>
always returns the string <b>foobar</b> as lookup
A table that always returns its name as
lookup result. For example, <b>static:foobar</b>
always returns the string <b>foobar</b> as lookup
result.
<b>tcp</b> (read-only)
Perform lookups using a simple request-reply
protocol that is described in <a href="tcp_table.5.html"><b>tcp_table</b>(5)</a>.
protocol that is described in <a href="tcp_table.5.html"><b>tcp_table</b>(5)</a>.
This feature is not included with the stable
Postfix release.
<b>unix</b> (read-only)
A limited way to query the UNIX authentica-
A limited way to query the UNIX authentica-
tion database. The following tables are
implemented:
<b>unix:passwd.byname</b>
The table is the UNIX password data-
base. The key is a login name. The
result is a password file entry in
The table is the UNIX password data-
base. The key is a login name. The
result is a password file entry in
<b>passwd</b>(5) format.
<b>unix:group.byname</b>
The table is the UNIX group database.
The key is a group name. The result
is a group file entry in <b>group</b>(5)
The key is a group name. The result
is a group file entry in <b>group</b>(5)
format.
Other table types may exist depending on how Post-
Other table types may exist depending on how Post-
fix was built.
<b>-n</b> Print parameter settings that are not left at their
@ -209,29 +213,29 @@ POSTCONF(1) POSTCONF(1)
<b>-t</b> [<i>template</i><b>_</b><i>file</i>]
Display the templates for delivery status notifica-
tion (DSN) messages. To override the built-in tem-
plates, specify a template file at the end of the
tion (DSN) messages. To override the built-in tem-
plates, specify a template file at the end of the
command line, or specify a template file in <a href="postconf.5.html">main.cf</a>
with the <b><a href="postconf.5.html#bounce_template_file">bounce_template_file</a></b> parameter. To force
selection of the built-in templates, specify an
with the <b><a href="postconf.5.html#bounce_template_file">bounce_template_file</a></b> parameter. To force
selection of the built-in templates, specify an
empty template file name (in shell language: "").
This feature is available with Postfix 2.3 and
This feature is available with Postfix 2.3 and
later.
<b>-v</b> Enable verbose logging for debugging purposes. Mul-
tiple <b>-v</b> options make the software increasingly
tiple <b>-v</b> options make the software increasingly
verbose.
<b>-#</b> Edit the <a href="postconf.5.html"><b>main.cf</b></a> configuration file. The file is
<b>-#</b> Edit the <a href="postconf.5.html"><b>main.cf</b></a> configuration file. The file is
copied to a temporary file then renamed into place.
The parameters specified on the command line are
The parameters specified on the command line are
commented-out, so that they revert to their default
values. Specify a list of parameter names, not
name=value pairs. There is no <b>postconf</b> command to
values. Specify a list of parameter names, not
name=value pairs. There is no <b>postconf</b> command to
perform the reverse operation.
This feature is available with Postfix 2.6 and
This feature is available with Postfix 2.6 and
later.
<b>DIAGNOSTICS</b>
@ -242,18 +246,18 @@ POSTCONF(1) POSTCONF(1)
Directory with Postfix configuration files.
<b>CONFIGURATION PARAMETERS</b>
The following <a href="postconf.5.html"><b>main.cf</b></a> parameters are especially relevant
The following <a href="postconf.5.html"><b>main.cf</b></a> parameters are especially relevant
to this program.
The text below provides only a parameter summary. See
The text below provides only a parameter summary. See
<a href="postconf.5.html"><b>postconf</b>(5)</a> for more details including examples.
<b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
<a href="master.5.html">master.cf</a> configuration files.
<b><a href="postconf.5.html#bounce_template_file">bounce_template_file</a> (empty)</b>
Pathname of a configuration file with bounce mes-
Pathname of a configuration file with bounce mes-
sage templates.
<b>FILES</b>
@ -267,7 +271,7 @@ POSTCONF(1) POSTCONF(1)
<a href="DATABASE_README.html">DATABASE_README</a>, Postfix lookup table overview
<b>LICENSE</b>
The Secure Mailer license must be distributed with this
The Secure Mailer license must be distributed with this
software.
<b>AUTHOR(S)</b>

View File

@ -12226,6 +12226,9 @@ access restriction is specified. This prevents the Postfix queue
from filling up with undeliverable MAILER-DAEMON messages.
</p>
<p> An address is always considered "known" when it matches a
<a href="virtual.5.html">virtual(5)</a> alias or a <a href="canonical.5.html">canonical(5)</a> mapping.
<ul>
<li> The recipient domain matches $<a href="postconf.5.html#mydestination">mydestination</a>, $<a href="postconf.5.html#inet_interfaces">inet_interfaces</a>
@ -12260,6 +12263,9 @@ sender addresses, even when no explicit <a href="postconf.5.html#reject_unlisted
access restriction is specified. This can slow down an explosion
of forged mail from worms or viruses. </p>
<p> An address is always considered "known" when it matches a
<a href="virtual.5.html">virtual(5)</a> alias or a <a href="canonical.5.html">canonical(5)</a> mapping.
<ul>
<li> The sender domain matches $<a href="postconf.5.html#mydestination">mydestination</a>, $<a href="postconf.5.html#inet_interfaces">inet_interfaces</a> or
@ -15033,9 +15039,8 @@ value is backwards compatible with Postfix version 1.1.
(default: 51200000)</b></DT><DD>
<p>
The maximal size in bytes of an individual mailbox or maildir file,
or zero (no limit).
</p>
The maximal size in bytes of an individual <a href="virtual.8.html">virtual(8)</a> mailbox or
maildir file, or zero (no limit). </p>
</DD>

View File

@ -168,7 +168,7 @@ VIRTUAL(5) VIRTUAL(5)
the output from "<b>postconf -m</b>" for available database
types.
/etc/postfix/<a href="virtual.8.html">virtual</a>:
/etc/postfix/virtual:
<i>virtual-alias.domain anything</i> (right-hand content does not matter)
<i>postmaster@virtual-alias.domain postmaster</i>
<i>user1@virtual-alias.domain address1</i>

View File

@ -127,6 +127,9 @@ useful someday.
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).

View File

@ -7539,6 +7539,9 @@ Request that the Postfix SMTP server rejects mail for unknown
recipient addresses, even when no explicit reject_unlisted_recipient
access restriction is specified. This prevents the Postfix queue
from filling up with undeliverable MAILER-DAEMON messages.
.PP
An address is always considered "known" when it matches a
\fBvirtual\fR(5) alias or a \fBcanonical\fR(5) mapping.
.IP \(bu
The recipient domain matches $mydestination, $inet_interfaces
or $proxy_interfaces, but the recipient is not listed in
@ -7561,6 +7564,9 @@ Request that the Postfix SMTP server rejects mail from unknown
sender addresses, even when no explicit reject_unlisted_sender
access restriction is specified. This can slow down an explosion
of forged mail from worms or viruses.
.PP
An address is always considered "known" when it matches a
\fBvirtual\fR(5) alias or a \fBcanonical\fR(5) mapping.
.IP \(bu
The sender domain matches $mydestination, $inet_interfaces or
$proxy_interfaces, but the sender is not listed in
@ -9411,8 +9417,8 @@ configuration parameter.
This feature is available in Postfix 2.0 and later. The default
value is backwards compatible with Postfix version 1.1.
.SH virtual_mailbox_limit (default: 51200000)
The maximal size in bytes of an individual mailbox or maildir file,
or zero (no limit).
The maximal size in bytes of an individual \fBvirtual\fR(8) mailbox or
maildir file, or zero (no limit).
.SH virtual_mailbox_lock (default: see "postconf -d" output)
How to lock a UNIX-style \fBvirtual\fR(8) mailbox before attempting
delivery. For a list of available file locking methods, use the

View File

@ -981,7 +981,7 @@ while (<>) {
s/\b(smtp):/<a href="smtp.8.html">$1<\/a>:/g;
s/\b(lmtp):/<a href="lmtp.8.html">$1<\/a>:/g;
s/\b(local):/<a href="local.8.html">$1<\/a>:/g;
s/\b(virtual):/<a href="virtual.8.html">$1<\/a>:/g;
s/([^\/])\b(virtual):/$1<a href="virtual.8.html">$2<\/a>:/g;
}
continue {
if ($printit)

View File

@ -299,6 +299,11 @@ 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. </dd>
<dt> <b>internal</b> </dt>
<dd> A non-shared, in-memory hash table. Its content are lost when
a process terminates. </dd>
<dt> <b>ldap</b> (read-only) </dt>
<dd> Perform lookups using the LDAP protocol. Configuration details

View File

@ -7846,6 +7846,9 @@ access restriction is specified. This prevents the Postfix queue
from filling up with undeliverable MAILER-DAEMON messages.
</p>
<p> An address is always considered "known" when it matches a
virtual(5) alias or a canonical(5) mapping.
<ul>
<li> The recipient domain matches $mydestination, $inet_interfaces
@ -7876,6 +7879,9 @@ sender addresses, even when no explicit reject_unlisted_sender
access restriction is specified. This can slow down an explosion
of forged mail from worms or viruses. </p>
<p> An address is always considered "known" when it matches a
virtual(5) alias or a canonical(5) mapping.
<ul>
<li> The sender domain matches $mydestination, $inet_interfaces or
@ -8143,9 +8149,8 @@ value is backwards compatible with Postfix version 1.1.
%PARAM virtual_mailbox_limit 51200000
<p>
The maximal size in bytes of an individual mailbox or maildir file,
or zero (no limit).
</p>
The maximal size in bytes of an individual virtual(8) mailbox or
maildir file, or zero (no limit). </p>
%PARAM virtual_mailbox_lock see "postconf -d" output

View File

@ -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

View File

@ -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).

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -6,17 +6,15 @@
/* SYNOPSIS
/* #include <dict_ht.h>
/*
/* DICT *dict_ht_open(name, table, remove)
/* DICT *dict_ht_open(name, open_flags, dict_flags)
/* const char *name;
/* HTABLE *table;
/* void (*remove)(char *value)
/* int open_flags;
/* int dict_flags;
/* DESCRIPTION
/* dict_ht_open() makes specified hash table accessible via the
/* generic dictionary operations documented in dict_open(3).
/* \fIremove\fR specifies an optional callback function
/* that is called by the hash table manager when the hash table is
/* removed from the dictionary manager's care. The hash table is not
/* destroyed when \fIremove\fR is a null pointer.
/* dict_ht_open() creates a memory-resident hash table and
/* makes it accessible via the generic dictionary operations
/* documented in dict_open(3). The open_flags argument is
/* ignored.
/* SEE ALSO
/* dict(3) generic dictionary manager
/* LICENSE
@ -40,13 +38,14 @@
#include "htable.h"
#include "dict.h"
#include "dict_ht.h"
#include "stringops.h"
#include "vstring.h"
/* Application-specific. */
typedef struct {
DICT dict; /* generic members */
HTABLE *table; /* hash table */
void (*remove) (char *); /* callback */
} DICT_HT;
/* dict_ht_lookup - find hash-table entry */
@ -57,6 +56,15 @@ static const char *dict_ht_lookup(DICT *dict, const char *name)
dict_errno = 0;
/*
* Optionally fold the key.
*/
if (dict->flags & DICT_FLAG_FOLD_FIX) {
if (dict->fold_buf == 0)
dict->fold_buf = vstring_alloc(10);
vstring_strcpy(dict->fold_buf, name);
name = lowercase(vstring_str(dict->fold_buf));
}
return (htable_find(dict_ht->table, name));
}
@ -67,6 +75,15 @@ static void dict_ht_update(DICT *dict, const char *name, const char *value)
DICT_HT *dict_ht = (DICT_HT *) dict;
HTABLE_INFO *ht;
/*
* Optionally fold the key.
*/
if (dict->flags & DICT_FLAG_FOLD_FIX) {
if (dict->fold_buf == 0)
dict->fold_buf = vstring_alloc(10);
vstring_strcpy(dict->fold_buf, name);
name = lowercase(vstring_str(dict->fold_buf));
}
if ((ht = htable_locate(dict_ht->table, name)) != 0) {
myfree(ht->value);
} else {
@ -104,14 +121,13 @@ static void dict_ht_close(DICT *dict)
{
DICT_HT *dict_ht = (DICT_HT *) dict;
if (dict_ht->remove)
htable_free(dict_ht->table, dict_ht->remove);
htable_free(dict_ht->table, myfree);
dict_free(dict);
}
/* dict_ht_open - create association with hash table */
DICT *dict_ht_open(const char *name, HTABLE *table, void (*remove) (char *))
DICT *dict_ht_open(const char *name, int unused_open_flags, int dict_flags)
{
DICT_HT *dict_ht;
@ -120,7 +136,9 @@ DICT *dict_ht_open(const char *name, HTABLE *table, void (*remove) (char *))
dict_ht->dict.update = dict_ht_update;
dict_ht->dict.sequence = dict_ht_sequence;
dict_ht->dict.close = dict_ht_close;
dict_ht->table = table;
dict_ht->remove = remove;
dict_ht->dict.flags = dict_flags | DICT_FLAG_FIXED;
if (dict_flags & DICT_FLAG_FOLD_FIX)
dict_ht->dict.fold_buf = vstring_alloc(10);
dict_ht->table = htable_create(0);
return (&dict_ht->dict);
}

View File

@ -22,7 +22,7 @@
*/
#define DICT_TYPE_HT "internal"
extern DICT *dict_ht_open(const char *, HTABLE *, void (*) (char *));
extern DICT *dict_ht_open(const char *, int, int);
/* LICENSE
/* .ad

View File

@ -203,6 +203,7 @@
#include <dict_regexp.h>
#include <dict_static.h>
#include <dict_cidr.h>
#include <dict_ht.h>
#include <stringops.h>
#include <split_at.h>
#include <htable.h>
@ -220,6 +221,7 @@ static const DICT_OPEN_INFO dict_open_info[] = {
DICT_TYPE_CDB, dict_cdb_open,
#endif
DICT_TYPE_ENVIRON, dict_env_open,
DICT_TYPE_HT, dict_ht_open,
DICT_TYPE_UNIX, dict_unix_open,
#ifdef SNAPSHOT
DICT_TYPE_TCP, dict_tcp_open,

View File

@ -110,8 +110,8 @@
/* event_drain() repeatedly calls event_loop() until no more timer
/* events or I/O events are pending or until the time limit is reached.
/* This routine must not be called from an event_whatever() callback
/* routine. Note: this function ignores pending timer events, and
/* assumes that no new I/O events will be registered.
/* routine. Note: this function assumes that no new I/O events
/* will be registered.
/*
/* event_fork() must be called by a child process after it is
/* created with fork(), to re-initialize event processing.
@ -912,6 +912,7 @@ time_t event_request_timer(EVENT_NOTIFY_TIME callback, char *context, int delay
timer = RING_TO_TIMER(ring);
if (timer->callback == callback && timer->context == context) {
timer->when = event_present + delay;
timer->loop_instance = event_loop_instance;
ring_detach(ring);
if (msg_verbose > 2)
msg_info("%s: reset 0x%lx 0x%lx %d", myname,

View File

@ -343,7 +343,7 @@ HTABLE_INFO **htable_list(HTABLE *table)
return (list);
}
/* htable_sequence - dict_cache(3) compatibility iterator */
/* htable_sequence - dict(3) compatibility iterator */
HTABLE_INFO *htable_sequence(HTABLE *table, int how)
{

View File

@ -26,7 +26,7 @@ typedef struct HTABLE {
int size; /* length of entries array */
int used; /* number of entries in table */
HTABLE_INFO **data; /* entries array, auto-resized */
HTABLE_INFO **seq_bucket; /* current sequence bucket */
HTABLE_INFO **seq_bucket; /* current sequence hash bucket */
HTABLE_INFO *seq_element; /* current sequence element */
} HTABLE;

View File

@ -605,12 +605,15 @@ static void post_jail_init(char *unused_name, char **unused_argv)
if (var_verify_scan_cache > 0) {
int expire_flags;
expire_flags = DICT_CACHE_FLAG_EXP_SUMMARY;
expire_flags = DICT_CACHE_FLAG_STATISTICS;
if (msg_verbose)
expire_flags |= DICT_CACHE_FLAG_EXP_VERBOSE;
dict_cache_expire(verify_map, expire_flags, var_verify_scan_cache,
verify_cache_validator,
(char *) vstring_alloc(100));
expire_flags |= DICT_CACHE_FLAG_VERBOSE;
dict_cache_control(verify_map,
DICT_CACHE_CTL_FLAGS, expire_flags,
DICT_CACHE_CTL_INTERVAL, var_verify_scan_cache,
DICT_CACHE_CTL_VALIDATOR, verify_cache_validator,
DICT_CACHE_CTL_CONTEXT, (char *) vstring_alloc(100),
DICT_CACHE_CTL_END);
}
}
@ -658,16 +661,13 @@ static void pre_jail_init(char *unused_name, char **unused_argv)
*/
#define VERIFY_DICT_OPEN_FLAGS (DICT_FLAG_DUP_REPLACE | DICT_FLAG_SYNC_UPDATE)
if (*var_verify_map) {
saved_mask = umask(022);
verify_map =
dict_cache_open(data_redirect_map(redirect, var_verify_map),
O_CREAT | O_RDWR, VERIFY_DICT_OPEN_FLAGS);
(void) umask(saved_mask);
} else {
verify_map =
dict_cache_import(dict_ht_open("verify", htable_create(0), myfree));
}
saved_mask = umask(022);
verify_map =
dict_cache_open(*var_verify_map ?
data_redirect_map(redirect, var_verify_map) :
"internal:verify",
O_CREAT | O_RDWR, VERIFY_DICT_OPEN_FLAGS);
(void) umask(saved_mask);
/*
* Clean up and restore privilege.