---
name: "dbz"
section: "3"
platform: "linux"
package: "inn"
version: "1:1.7.2q-52"
release: "Debian 13 (Trixie)"
platforms: ["linux"]
url: "https://new.carta.tech/dbz/3"
---

# dbz(3)

somewhat dbm-compatible database routines dbzfresh, dbzagain, dbzfetch, dbzstore - database routines dbzsync, dbzsize, dbzincore, dbzcancel, dbzdebug - database routines

## NAME

dbminit, fetch, store, dbmclose - somewhat dbm-compatible database routines\
 dbzfresh, dbzagain, dbzfetch, dbzstore - database routines\
 dbzsync, dbzsize, dbzincore, dbzcancel, dbzdebug - database routines

## SYNOPSIS

```
#include <dbz.h>
```

**dbminit(base)** **char \*base;**

**datum** **fetch(key)** **datum key;**

**store(key, value)** **datum key;** **datum value;**

**dbmclose()**

**dbzfresh(base, size, fieldsep, cmap, tagmask)** **char \*base;** **long size;** **int fieldsep;** **int cmap;** **long tagmask;**

**dbzagain(base, oldbase)** **char \*base;** **char \*oldbase;**

**datum** **dbzfetch(key)** **datum key;**

**dbzstore(key, value)** **datum key;** **datum value;**

**dbzsync()**

**long** **dbzsize(nentries)** **long nentries;**

**dbzincore(newvalue)**

**dbzcancel()**

**dbzdebug(newvalue)**

## DESCRIPTION

These functions provide an indexing system for rapid random access to a text file (the *base* *file*). Subject to certain constraints, they are call-compatible with [*dbm*(3)](/dbm/3.md), although they also provide some extensions. (Note that they are *not* file-compatible with *dbm* or any variant thereof.)

In principle, *dbz* stores key-value pairs, where both key and value are arbitrary sequences of bytes, specified to the functions by values of type *datum*, typedefed in the header file to be a structure with members *dptr* (a value of type *char \** pointing to the bytes) and *dsize* (a value of type *int* indicating how long the byte sequence is).

In practice, *dbz* is more restricted than *dbm*. A *dbz* database must be an index into a base file, with the database *value*s being [*fseek*(3)](/fseek/3.md) offsets into the base file. Each such *value* must \`\`point to'' a place in the base file where the corresponding *key* sequence is found. A key can be no longer than DBZMAXKEY (a constant defined in the header file) bytes. No key can be an initial subsequence of another, which in most applications requires that keys be either bracketed or terminated in some way (see the discussion of the *fieldsep* parameter of *dbzfresh*, below, for a fine point on terminators).

*Dbminit* opens a database, an index into the base file *base*, consisting of files *base***.dir** and *base***.pag** which must already exist. (If the database is new, they should be zero-length files.) Subsequent accesses go to that database until *dbmclose* is called to close the database. The base file need not exist at the time of the *dbminit*, but it must exist before accesses are attempted.

*Fetch* searches the database for the specified *key*, returning the corresponding *value* if any. *Store* stores the *key*-*value* pair in the database. *Store* will fail unless the database files are writeable. See below for a complication arising from case mapping.

*Dbzfresh* is a variant of *dbminit* for creating a new database with more control over details. Unlike for *dbminit*, the database files need not exist: they will be created if necessary, and truncated in any case.

*Dbzfresh*'s *size* parameter specifies the size of the first hash table within the database, in key-value pairs. Performance will be best if *size* is a prime number and the number of key-value pairs stored in the database does not exceed about 2/3 of *size*. (The *dbzsize* function, given the expected number of key-value pairs, will suggest a database size that meets these criteria.) Assuming that an *fseek* offset is 4 bytes, the **.pag** file will be 4\**size* bytes (the **.dir** file is tiny and roughly constant in size) until the number of key-value pairs exceeds about 80% of *size*. (Nothing awful will happen if the database grows beyond 100% of *size*, but accesses will slow down somewhat and the **.pag** file will grow somewhat.)

*Dbzfresh*'s *fieldsep* parameter specifies the field separator in the base file. If this is not NUL (0), and the last character of a *key* argument is NUL, that NUL compares equal to either a NUL or a *fieldsep* in the base file. This permits use of NUL to terminate key strings without requiring that NULs appear in the base file. The *fieldsep* of a database created with *dbminit* is the horizontal-tab character.

For use in news systems, various forms of case mapping (e.g. uppercase to lowercase) in keys are available. The *cmap* parameter to *dbzfresh* is a single character specifying which of several mapping algorithms to use. Available algorithms are:

- **0**

  case-sensitive:  no case mapping

- **B**

  same as **0**

- **NUL**

  same as **0**

- **=**

  case-insensitive:  uppercase and lowercase equivalent

- **b**

  same as **=**

- **C**

  RFC822 message-ID rules, case-sensitive before \`@' (with certain exceptions) and case-insensitive after

- **?**

  whatever the local default is, normally **C**

Mapping algorithm **0** (no mapping) is faster than the others and is overwhelmingly the correct choice for most applications. Unless compatibility constraints interfere, it is more efficient to pre-map the keys, storing mapped keys in the base file, than to have *dbz* do the mapping on every search.

For historical reasons, *fetch* and *store* expect their *key* arguments to be pre-mapped, but expect unmapped keys in the base file. *Dbzfetch* and *dbzstore* do the same jobs but handle all case mapping internally, so the customer need not worry about it.

*Dbz* stores only the database *value*s in its files, relying on reference to the base file to confirm a hit on a key. References to the base file can be minimized, greatly speeding up searches, if a little bit of information about the keys can be stored in the *dbz* files. This is \`\`free'' if there are some unused bits in an *fseek* offset, so that the offset can be *tagged* with some information about the key. The *tagmask* parameter of *dbzfresh* allows specifying the location of unused bits. *Tagmask* should be a mask with one group of contiguous **1** bits. The bits in the mask should be unused (0) in *most* offsets. The bit immediately above the mask (the *flag* bit) should be unused (0) in *all* offsets; *(dbz)store* will reject attempts to store a key-value pair in which the *value* has the flag bit on. Apart from this restriction, tagging is invisible to the user. As a special case, a *tagmask* of 1 means \`\`no tagging'', for use with enormous base files or on systems with unusual offset representations.

A *size* of 0 given to *dbzfresh* is synonymous with the local default; the normal default is suitable for tables of 90-100,000 key-value pairs. A *cmap* of 0 (NUL) is synonymous with the character **0**, signifying no case mapping (note that the character **?** specifies the local default mapping, normally **C**). A *tagmask* of 0 is synonymous with the local default tag mask, normally 0x7f000000 (specifying the top bit in a 32-bit offset as the flag bit, and the next 7 bits as the mask, which is suitable for base files up to circa 24MB). Calling *dbminit(name)* with the database files empty is equivalent to calling *dbzfresh(name,0,'\\t','?',0)*.

When databases are regenerated periodically, as in news, it is simplest to pick the parameters for a new database based on the old one. This also permits some memory of past sizes of the old database, so that a new database size can be chosen to cover expected fluctuations. *Dbzagain* is a variant of *dbminit* for creating a new database as a new generation of an old database. The database files for *oldbase* must exist. *Dbzagain* is equivalent to calling *dbzfresh* with the same field separator, case mapping, and tag mask as the old database, and a *size* equal to the result of applying *dbzsize* to the largest number of entries in the *oldbase* database and its previous 10 generations.

When many accesses are being done by the same program, *dbz* is massively faster if its first hash table is in memory. If an internal flag is 1, an attempt is made to read the table in when the database is opened, and *dbmclose* writes it out to disk again (if it was read successfully and has been modified). *Dbzincore* sets the flag to *newvalue* (which should be 0 or 1) and returns the previous value; this does not affect the status of a database that has already been opened. The default is 0. The attempt to read the table in may fail due to memory shortage; in this case *dbz* quietly falls back on its default behavior. *Store*s to an in-memory database are not (in general) written out to the file until *dbmclose* or *dbzsync*, so if robustness in the presence of crashes or concurrent accesses is crucial, in-memory databases should probably be avoided.

*Dbzsync* causes all buffers etc. to be flushed out to the files. It is typically used as a precaution against crashes or concurrent accesses when a *dbz*-using process will be running for a long time. It is a somewhat expensive operation, especially for an in-memory database.

*Dbzcancel* cancels any pending writes from buffers. This is typically useful only for in-core databases, since writes are otherwise done immediately. Its main purpose is to let a child process, in the wake of a *fork*, do a *dbmclose* without writing its parent's data to disk.

If *dbz* has been compiled with debugging facilities available (which makes it bigger and a bit slower), *dbzdebug* alters the value (and returns the previous value) of an internal flag which (when 1; default is 0) causes verbose and cryptic debugging output on standard output.

Concurrent reading of databases is fairly safe, but there is no (inter)locking, so concurrent updating is not.

The database files include a record of the byte order of the processor creating the database, and accesses by processors with different byte order will work, although they will be slightly slower. Byte order is preserved by *dbzagain*. However, agreement on the size and internal structure of an *fseek* offset is necessary, as is consensus on the character set.

An open database occupies three *stdio* streams and their corresponding file descriptors; a fourth is needed for an in-memory database. Memory consumption is negligible (except for *stdio* buffers) except for in-memory databases.

## SEE ALSO

[dbz(1)](/dbz/1.md), [dbm(3)](/dbm/3.md)

## DIAGNOSTICS

Functions returning *int* values return 0 for success, -1 for failure. Functions returning *datum* values return a value with *dptr* set to NULL for failure. *Dbminit* attempts to have *errno* set plausibly on return, but otherwise this is not guaranteed. An *errno* of **EDOM** from *dbminit* indicates that the database did not appear to be in *dbz* format.

## HISTORY

The original *dbz* was written by Jon Zeeff (zeeff@b-tech.ann-arbor.mi.us). Later contributions by David Butler and Mark Moraes. Extensive reworking, including this documentation, by Henry Spencer (henry@zoo.toronto.edu) as part of the C News project. Hashing function by Peter Honeyman.

## BUGS

The *dptr* members of returned *datum* values point to static storage which is overwritten by later calls.

Unlike *dbm*, *dbz* will misbehave if an existing key-value pair is \`overwritten' by a new *(dbz)store* with the same key. The user is responsible for avoiding this by using *(dbz)fetch* first to check for duplicates; an internal optimization remembers the result of the first search so there is minimal overhead in this.

Waiting until after *dbminit* to bring the base file into existence will fail if [*chdir*(2)](/chdir/2.md) has been used meanwhile.

The RFC822 case mapper implements only a first approximation to the hideously-complex RFC822 case rules.

The prime finder in *dbzsize* is not particularly quick.

Should implement the *dbm* functions *delete*, *firstkey*, and *nextkey*.

On C implementations which trap integer overflow, *dbz* will refuse to *(dbz)store* an *fseek* offset equal to the greatest representable positive number, as this would cause overflow in the biased representation used.

*Dbzagain* perhaps ought to notice when many offsets in the old database were too big for tagging, and shrink the tag mask to match.

Marking *dbz*'s file descriptors close-on-*exec* would be a better approach to the problem *dbzcancel* tries to address, but that's harder to do portably.
