7 /* create or open database, DB style
11 /* MKMAP *mkmap_hash_open(path)
14 /* MKMAP *mkmap_btree_open(path)
17 /* This module implements support for creating DB databases.
19 /* mkmap_hash_open() and mkmap_btree_open() take a file name,
20 /* append the ".db" suffix, and do whatever initialization is
21 /* required before the Berkeley DB open routine is called.
23 /* All errors are fatal.
25 /* dict_db(3), DB dictionary interface.
29 /* The Secure Mailer license must be distributed with this software.
32 /* IBM T.J. Watson Research
34 /* Yorktown Heights, NY 10598, USA
44 /* Utility library. */
48 #include <stringops.h>
55 #include <mail_params.h>
57 /* Application-specific. */
68 typedef struct MKMAP_DB
{
69 MKMAP mkmap
; /* parent class */
70 char *lock_file
; /* path name */
71 int lock_fd
; /* -1 or open locked file */
74 /* mkmap_db_after_close - clean up after closing database */
76 static void mkmap_db_after_close(MKMAP
*mp
)
78 MKMAP_DB
*mkmap
= (MKMAP_DB
*) mp
;
80 if (mkmap
->lock_fd
>= 0 && close(mkmap
->lock_fd
) < 0)
81 msg_warn("close %s: %m", mkmap
->lock_file
);
82 myfree(mkmap
->lock_file
);
85 /* mkmap_db_after_open - lock newly created database */
87 static void mkmap_db_after_open(MKMAP
*mp
)
89 MKMAP_DB
*mkmap
= (MKMAP_DB
*) mp
;
91 if (mkmap
->lock_fd
< 0) {
92 if ((mkmap
->lock_fd
= open(mkmap
->lock_file
, O_RDWR
, 0644)) < 0)
93 msg_fatal("open lockfile %s: %m", mkmap
->lock_file
);
94 if (myflock(mkmap
->lock_fd
, INTERNAL_LOCK
, MYFLOCK_OP_EXCLUSIVE
) < 0)
95 msg_fatal("lock %s: %m", mkmap
->lock_file
);
99 /* mkmap_db_before_open - lock existing database */
101 static MKMAP
*mkmap_db_before_open(const char *path
,
102 DICT
*(*db_open
) (const char *, int, int))
104 MKMAP_DB
*mkmap
= (MKMAP_DB
*) mymalloc(sizeof(*mkmap
));
108 * Override the default per-table cache size for map (re)builds.
110 * db_cache_size" is defined in util/dict_db.c and defaults to 128kB, which
111 * works well for the lookup code.
113 * We use a larger per-table cache when building ".db" files. For "hash"
114 * files performance degrades rapidly unless the memory pool is O(file
117 * For "btree" files peformance is good with sorted input even for small
118 * memory pools, but with random input degrades rapidly unless the memory
119 * pool is O(file size).
121 * XXX This should be specified via the DICT interface so that the buffer
122 * size becomes an object property, instead of being specified by poking
123 * a global variable so that it becomes a class property.
125 dict_db_cache_size
= var_db_create_buf
;
128 * Fill in the generic members.
130 mkmap
->lock_file
= concatenate(path
, ".db", (char *) 0);
131 mkmap
->mkmap
.open
= db_open
;
132 mkmap
->mkmap
.after_open
= mkmap_db_after_open
;
133 mkmap
->mkmap
.after_close
= mkmap_db_after_close
;
136 * Unfortunately, not all systems that might support db databases do
137 * support locking on open(), so we open the file before updating it.
139 * XXX Berkeley DB 4.1 refuses to open a zero-length file. This means we can
140 * open and lock only an existing file, and that we must not truncate it.
142 if ((mkmap
->lock_fd
= open(mkmap
->lock_file
, O_RDWR
, 0644)) < 0) {
144 msg_fatal("open %s: %m", mkmap
->lock_file
);
148 * Get an exclusive lock - we're going to change the database so we can't
149 * have any spectators.
151 * XXX Horror. Berkeley DB 4.1 refuses to open a zero-length file. This
152 * means that we must examine the size while the file is locked, and that
153 * we must unlink a zero-length file while it is locked. Avoid a race
154 * condition where two processes try to open the same zero-length file
155 * and where the second process ends up deleting the wrong file.
158 if (myflock(mkmap
->lock_fd
, INTERNAL_LOCK
, MYFLOCK_OP_EXCLUSIVE
) < 0)
159 msg_fatal("lock %s: %m", mkmap
->lock_file
);
160 if (fstat(mkmap
->lock_fd
, &st
) < 0)
161 msg_fatal("fstat %s: %m", mkmap
->lock_file
);
162 if (st
.st_size
== 0) {
163 if (st
.st_nlink
> 0) {
164 if (unlink(mkmap
->lock_file
) < 0)
165 msg_fatal("cannot remove zero-length database file %s: %m",
167 msg_warn("removing zero-length database file: %s",
170 close(mkmap
->lock_fd
);
175 return (&mkmap
->mkmap
);
178 /* mkmap_hash_open - create or open hashed DB file */
180 MKMAP
*mkmap_hash_open(const char *path
)
182 return (mkmap_db_before_open(path
, dict_hash_open
));
185 /* mkmap_btree_open - create or open btree DB file */
187 MKMAP
*mkmap_btree_open(const char *path
)
189 return (mkmap_db_before_open(path
, dict_btree_open
));