xref: /freebsd/lib/libc/db/hash/hash.h (revision dc36d6f9bb1753f3808552f3afd30eda9a7b206a)
158f0484fSRodney W. Grimes /*-
2*8a16b7a1SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
3*8a16b7a1SPedro F. Giffuni  *
4f1e396bcSPaul Traina  * Copyright (c) 1990, 1993, 1994
558f0484fSRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
658f0484fSRodney W. Grimes  *
758f0484fSRodney W. Grimes  * This code is derived from software contributed to Berkeley by
858f0484fSRodney W. Grimes  * Margo Seltzer.
958f0484fSRodney W. Grimes  *
1058f0484fSRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
1158f0484fSRodney W. Grimes  * modification, are permitted provided that the following conditions
1258f0484fSRodney W. Grimes  * are met:
1358f0484fSRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
1458f0484fSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
1558f0484fSRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
1658f0484fSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
1758f0484fSRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
18fbbd9655SWarner Losh  * 3. Neither the name of the University nor the names of its contributors
1958f0484fSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
2058f0484fSRodney W. Grimes  *    without specific prior written permission.
2158f0484fSRodney W. Grimes  *
2258f0484fSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2358f0484fSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2458f0484fSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2558f0484fSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2658f0484fSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2758f0484fSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2858f0484fSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2958f0484fSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3058f0484fSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3158f0484fSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3258f0484fSRodney W. Grimes  * SUCH DAMAGE.
3358f0484fSRodney W. Grimes  */
3458f0484fSRodney W. Grimes 
3558f0484fSRodney W. Grimes /* Operations */
3658f0484fSRodney W. Grimes typedef enum {
3758f0484fSRodney W. Grimes 	HASH_GET, HASH_PUT, HASH_PUTNEW, HASH_DELETE, HASH_FIRST, HASH_NEXT
3858f0484fSRodney W. Grimes } ACTION;
3958f0484fSRodney W. Grimes 
4058f0484fSRodney W. Grimes /* Buffer Management structures */
4158f0484fSRodney W. Grimes typedef struct _bufhead BUFHEAD;
4258f0484fSRodney W. Grimes 
4358f0484fSRodney W. Grimes struct _bufhead {
4458f0484fSRodney W. Grimes 	BUFHEAD		*prev;		/* LRU links */
4558f0484fSRodney W. Grimes 	BUFHEAD		*next;		/* LRU links */
4658f0484fSRodney W. Grimes 	BUFHEAD		*ovfl;		/* Overflow page buffer header */
47f1e396bcSPaul Traina 	u_int32_t	 addr;		/* Address of this page */
4858f0484fSRodney W. Grimes 	char		*page;		/* Actual page data */
4958f0484fSRodney W. Grimes 	char	 	flags;
5058f0484fSRodney W. Grimes #define	BUF_MOD		0x0001
5158f0484fSRodney W. Grimes #define BUF_DISK	0x0002
5258f0484fSRodney W. Grimes #define	BUF_BUCKET	0x0004
5358f0484fSRodney W. Grimes #define	BUF_PIN		0x0008
5458f0484fSRodney W. Grimes };
5558f0484fSRodney W. Grimes 
5658f0484fSRodney W. Grimes #define IS_BUCKET(X)	((X) & BUF_BUCKET)
5758f0484fSRodney W. Grimes 
5858f0484fSRodney W. Grimes typedef BUFHEAD **SEGMENT;
5958f0484fSRodney W. Grimes 
6058f0484fSRodney W. Grimes /* Hash Table Information */
6158f0484fSRodney W. Grimes typedef struct hashhdr {		/* Disk resident portion */
62eb3144b2SXin LI 	int32_t		magic;		/* Magic NO for hash tables */
63eb3144b2SXin LI 	int32_t		version;	/* Version ID */
64f1e396bcSPaul Traina 	u_int32_t	lorder;		/* Byte Order */
65eb3144b2SXin LI 	int32_t		bsize;		/* Bucket/Page Size */
66eb3144b2SXin LI 	int32_t		bshift;		/* Bucket shift */
67eb3144b2SXin LI 	int32_t		dsize;		/* Directory Size */
68eb3144b2SXin LI 	int32_t		ssize;		/* Segment Size */
69eb3144b2SXin LI 	int32_t		sshift;		/* Segment shift */
70eb3144b2SXin LI 	int32_t		ovfl_point;	/* Where overflow pages are being
71f1e396bcSPaul Traina 					 * allocated */
72eb3144b2SXin LI 	int32_t		last_freed;	/* Last overflow page freed */
73f60486b3SXin LI 	u_int32_t	max_bucket;	/* ID of Maximum bucket in use */
74f60486b3SXin LI 	u_int32_t	high_mask;	/* Mask to modulo into entire table */
75f60486b3SXin LI 	u_int32_t	low_mask;	/* Mask to modulo into lower half of
76f1e396bcSPaul Traina 					 * table */
77f60486b3SXin LI 	u_int32_t	ffactor;	/* Fill factor */
78eb3144b2SXin LI 	int32_t		nkeys;		/* Number of keys in hash table */
79eb3144b2SXin LI 	int32_t		hdrpages;	/* Size of table header */
80eb3144b2SXin LI 	int32_t		h_charkey;	/* value of hash(CHARKEY) */
81f1e396bcSPaul Traina #define NCACHED	32			/* number of bit maps and spare
82f1e396bcSPaul Traina 					 * points */
83eb3144b2SXin LI 	int32_t		spares[NCACHED];/* spare pages for overflow */
84f1e396bcSPaul Traina 	u_int16_t	bitmaps[NCACHED];	/* address of overflow page
85f1e396bcSPaul Traina 						 * bitmaps */
8658f0484fSRodney W. Grimes } HASHHDR;
8758f0484fSRodney W. Grimes 
8858f0484fSRodney W. Grimes typedef struct htab	 {		/* Memory resident data structure */
8958f0484fSRodney W. Grimes 	HASHHDR 	hdr;		/* Header */
9058f0484fSRodney W. Grimes 	int		nsegs;		/* Number of allocated segments */
91f1e396bcSPaul Traina 	int		exsegs;		/* Number of extra allocated
92f1e396bcSPaul Traina 					 * segments */
9358f0484fSRodney W. Grimes 	u_int32_t			/* Hash function */
94c05ac53bSDavid E. O'Brien 	    (*hash)(const void *, size_t);
9558f0484fSRodney W. Grimes 	int		flags;		/* Flag values */
9658f0484fSRodney W. Grimes 	int		fp;		/* File pointer */
9758f0484fSRodney W. Grimes 	char		*tmp_buf;	/* Temporary Buffer for BIG data */
9858f0484fSRodney W. Grimes 	char		*tmp_key;	/* Temporary Buffer for BIG keys */
9958f0484fSRodney W. Grimes 	BUFHEAD 	*cpage;		/* Current page */
10058f0484fSRodney W. Grimes 	int		cbucket;	/* Current bucket */
10158f0484fSRodney W. Grimes 	int		cndx;		/* Index of next item on cpage */
102f1e396bcSPaul Traina 	int		error;		/* Error Number -- for DBM
103a3573c66SJeroen Ruigrok van der Werven 					 * compatibility */
104f1e396bcSPaul Traina 	int		new_file;	/* Indicates if fd is backing store
105f1e396bcSPaul Traina 					 * or no */
106f1e396bcSPaul Traina 	int		save_file;	/* Indicates whether we need to flush
107f1e396bcSPaul Traina 					 * file at
10858f0484fSRodney W. Grimes 					 * exit */
109f1e396bcSPaul Traina 	u_int32_t	*mapp[NCACHED];	/* Pointers to page maps */
11058f0484fSRodney W. Grimes 	int		nmaps;		/* Initial number of bitmaps */
111f1e396bcSPaul Traina 	int		nbufs;		/* Number of buffers left to
112f1e396bcSPaul Traina 					 * allocate */
11358f0484fSRodney W. Grimes 	BUFHEAD 	bufhead;	/* Header of buffer lru list */
11458f0484fSRodney W. Grimes 	SEGMENT 	*dir;		/* Hash Bucket directory */
11558f0484fSRodney W. Grimes } HTAB;
11658f0484fSRodney W. Grimes 
11758f0484fSRodney W. Grimes /*
11858f0484fSRodney W. Grimes  * Constants
11958f0484fSRodney W. Grimes  */
120f3c733e8SAndriy Gapon #define	MAX_BSIZE		32768		/* 2^15 but should be 65536 */
12158f0484fSRodney W. Grimes #define MIN_BUFFERS		6
12258f0484fSRodney W. Grimes #define MINHDRSIZE		512
12358f0484fSRodney W. Grimes #define DEF_BUFSIZE		65536		/* 64 K */
12458f0484fSRodney W. Grimes #define DEF_BUCKET_SIZE		4096
12558f0484fSRodney W. Grimes #define DEF_BUCKET_SHIFT	12		/* log2(BUCKET) */
12658f0484fSRodney W. Grimes #define DEF_SEGSIZE		256
12758f0484fSRodney W. Grimes #define DEF_SEGSIZE_SHIFT	8		/* log2(SEGSIZE)	 */
12858f0484fSRodney W. Grimes #define DEF_DIRSIZE		256
12958f0484fSRodney W. Grimes #define DEF_FFACTOR		65536
13058f0484fSRodney W. Grimes #define MIN_FFACTOR		4
13158f0484fSRodney W. Grimes #define SPLTMAX			8
13258f0484fSRodney W. Grimes #define CHARKEY			"%$sniglet^&"
13358f0484fSRodney W. Grimes #define NUMKEY			1038583
13458f0484fSRodney W. Grimes #define BYTE_SHIFT		3
13558f0484fSRodney W. Grimes #define INT_TO_BYTE		2
13658f0484fSRodney W. Grimes #define INT_BYTE_SHIFT		5
137f1e396bcSPaul Traina #define ALL_SET			((u_int32_t)0xFFFFFFFF)
13858f0484fSRodney W. Grimes #define ALL_CLEAR		0
13958f0484fSRodney W. Grimes 
14045308eecSBrooks Davis #define PTROF(X)	((BUFHEAD *)((intptr_t)(X)&~0x3))
14145308eecSBrooks Davis #define ISMOD(X)	((u_int32_t)(intptr_t)(X)&0x1)
14245308eecSBrooks Davis #define DOMOD(X)	((X) = (char *)((intptr_t)(X)|0x1))
14345308eecSBrooks Davis #define ISDISK(X)	((u_int32_t)(intptr_t)(X)&0x2)
14445308eecSBrooks Davis #define DODISK(X)	((X) = (char *)((intptr_t)(X)|0x2))
14558f0484fSRodney W. Grimes 
14658f0484fSRodney W. Grimes #define BITS_PER_MAP	32
14758f0484fSRodney W. Grimes 
14858f0484fSRodney W. Grimes /* Given the address of the beginning of a big map, clear/set the nth bit */
14958f0484fSRodney W. Grimes #define CLRBIT(A, N)	((A)[(N)/BITS_PER_MAP] &= ~(1<<((N)%BITS_PER_MAP)))
15058f0484fSRodney W. Grimes #define SETBIT(A, N)	((A)[(N)/BITS_PER_MAP] |= (1<<((N)%BITS_PER_MAP)))
15158f0484fSRodney W. Grimes #define ISSET(A, N)	((A)[(N)/BITS_PER_MAP] & (1<<((N)%BITS_PER_MAP)))
15258f0484fSRodney W. Grimes 
15358f0484fSRodney W. Grimes /* Overflow management */
15458f0484fSRodney W. Grimes /*
15558f0484fSRodney W. Grimes  * Overflow page numbers are allocated per split point.  At each doubling of
15658f0484fSRodney W. Grimes  * the table, we can allocate extra pages.  So, an overflow page number has
15758f0484fSRodney W. Grimes  * the top 5 bits indicate which split point and the lower 11 bits indicate
15858f0484fSRodney W. Grimes  * which page at that split point is indicated (pages within split points are
15958f0484fSRodney W. Grimes  * numberered starting with 1).
16058f0484fSRodney W. Grimes  */
16158f0484fSRodney W. Grimes 
16258f0484fSRodney W. Grimes #define SPLITSHIFT	11
16358f0484fSRodney W. Grimes #define SPLITMASK	0x7FF
164f1e396bcSPaul Traina #define SPLITNUM(N)	(((u_int32_t)(N)) >> SPLITSHIFT)
16558f0484fSRodney W. Grimes #define OPAGENUM(N)	((N) & SPLITMASK)
166f1e396bcSPaul Traina #define	OADDR_OF(S,O)	((u_int32_t)((u_int32_t)(S) << SPLITSHIFT) + (O))
16758f0484fSRodney W. Grimes 
16858f0484fSRodney W. Grimes #define BUCKET_TO_PAGE(B) \
16958f0484fSRodney W. Grimes 	(B) + hashp->HDRPAGES + ((B) ? hashp->SPARES[__log2((B)+1)-1] : 0)
17058f0484fSRodney W. Grimes #define OADDR_TO_PAGE(B) 	\
17158f0484fSRodney W. Grimes 	BUCKET_TO_PAGE ( (1 << SPLITNUM((B))) -1 ) + OPAGENUM((B));
17258f0484fSRodney W. Grimes 
17358f0484fSRodney W. Grimes /*
17458f0484fSRodney W. Grimes  * page.h contains a detailed description of the page format.
17558f0484fSRodney W. Grimes  *
17658f0484fSRodney W. Grimes  * Normally, keys and data are accessed from offset tables in the top of
17758f0484fSRodney W. Grimes  * each page which point to the beginning of the key and data.  There are
17858f0484fSRodney W. Grimes  * four flag values which may be stored in these offset tables which indicate
17958f0484fSRodney W. Grimes  * the following:
18058f0484fSRodney W. Grimes  *
18158f0484fSRodney W. Grimes  *
18258f0484fSRodney W. Grimes  * OVFLPAGE	Rather than a key data pair, this pair contains
18358f0484fSRodney W. Grimes  *		the address of an overflow page.  The format of
18458f0484fSRodney W. Grimes  *		the pair is:
18558f0484fSRodney W. Grimes  *		    OVERFLOW_PAGE_NUMBER OVFLPAGE
18658f0484fSRodney W. Grimes  *
18758f0484fSRodney W. Grimes  * PARTIAL_KEY	This must be the first key/data pair on a page
18858f0484fSRodney W. Grimes  *		and implies that page contains only a partial key.
18958f0484fSRodney W. Grimes  *		That is, the key is too big to fit on a single page
19058f0484fSRodney W. Grimes  *		so it starts on this page and continues on the next.
19158f0484fSRodney W. Grimes  *		The format of the page is:
19258f0484fSRodney W. Grimes  *		    KEY_OFF PARTIAL_KEY OVFL_PAGENO OVFLPAGE
19358f0484fSRodney W. Grimes  *
19458f0484fSRodney W. Grimes  *		    KEY_OFF -- offset of the beginning of the key
19558f0484fSRodney W. Grimes  *		    PARTIAL_KEY -- 1
19658f0484fSRodney W. Grimes  *		    OVFL_PAGENO - page number of the next overflow page
19758f0484fSRodney W. Grimes  *		    OVFLPAGE -- 0
19858f0484fSRodney W. Grimes  *
19958f0484fSRodney W. Grimes  * FULL_KEY	This must be the first key/data pair on the page.  It
20058f0484fSRodney W. Grimes  *		is used in two cases.
20158f0484fSRodney W. Grimes  *
20258f0484fSRodney W. Grimes  *		Case 1:
20358f0484fSRodney W. Grimes  *		    There is a complete key on the page but no data
20458f0484fSRodney W. Grimes  *		    (because it wouldn't fit).  The next page contains
20558f0484fSRodney W. Grimes  *		    the data.
20658f0484fSRodney W. Grimes  *
20758f0484fSRodney W. Grimes  *		    Page format it:
20858f0484fSRodney W. Grimes  *		    KEY_OFF FULL_KEY OVFL_PAGENO OVFL_PAGE
20958f0484fSRodney W. Grimes  *
21058f0484fSRodney W. Grimes  *		    KEY_OFF -- offset of the beginning of the key
21158f0484fSRodney W. Grimes  *		    FULL_KEY -- 2
21258f0484fSRodney W. Grimes  *		    OVFL_PAGENO - page number of the next overflow page
21358f0484fSRodney W. Grimes  *		    OVFLPAGE -- 0
21458f0484fSRodney W. Grimes  *
21558f0484fSRodney W. Grimes  *		Case 2:
21658f0484fSRodney W. Grimes  *		    This page contains no key, but part of a large
21758f0484fSRodney W. Grimes  *		    data field, which is continued on the next page.
21858f0484fSRodney W. Grimes  *
21958f0484fSRodney W. Grimes  *		    Page format it:
22058f0484fSRodney W. Grimes  *		    DATA_OFF FULL_KEY OVFL_PAGENO OVFL_PAGE
22158f0484fSRodney W. Grimes  *
22258f0484fSRodney W. Grimes  *		    KEY_OFF -- offset of the beginning of the data on
22358f0484fSRodney W. Grimes  *				this page
22458f0484fSRodney W. Grimes  *		    FULL_KEY -- 2
22558f0484fSRodney W. Grimes  *		    OVFL_PAGENO - page number of the next overflow page
22658f0484fSRodney W. Grimes  *		    OVFLPAGE -- 0
22758f0484fSRodney W. Grimes  *
22858f0484fSRodney W. Grimes  * FULL_KEY_DATA
22958f0484fSRodney W. Grimes  *		This must be the first key/data pair on the page.
23058f0484fSRodney W. Grimes  *		There are two cases:
23158f0484fSRodney W. Grimes  *
23258f0484fSRodney W. Grimes  *		Case 1:
23358f0484fSRodney W. Grimes  *		    This page contains a key and the beginning of the
23458f0484fSRodney W. Grimes  *		    data field, but the data field is continued on the
23558f0484fSRodney W. Grimes  *		    next page.
23658f0484fSRodney W. Grimes  *
23758f0484fSRodney W. Grimes  *		    Page format is:
23858f0484fSRodney W. Grimes  *		    KEY_OFF FULL_KEY_DATA OVFL_PAGENO DATA_OFF
23958f0484fSRodney W. Grimes  *
24058f0484fSRodney W. Grimes  *		    KEY_OFF -- offset of the beginning of the key
24158f0484fSRodney W. Grimes  *		    FULL_KEY_DATA -- 3
24258f0484fSRodney W. Grimes  *		    OVFL_PAGENO - page number of the next overflow page
24358f0484fSRodney W. Grimes  *		    DATA_OFF -- offset of the beginning of the data
24458f0484fSRodney W. Grimes  *
24558f0484fSRodney W. Grimes  *		Case 2:
24658f0484fSRodney W. Grimes  *		    This page contains the last page of a big data pair.
24758f0484fSRodney W. Grimes  *		    There is no key, only the  tail end of the data
24858f0484fSRodney W. Grimes  *		    on this page.
24958f0484fSRodney W. Grimes  *
25058f0484fSRodney W. Grimes  *		    Page format is:
25158f0484fSRodney W. Grimes  *		    DATA_OFF FULL_KEY_DATA <OVFL_PAGENO> <OVFLPAGE>
25258f0484fSRodney W. Grimes  *
25358f0484fSRodney W. Grimes  *		    DATA_OFF -- offset of the beginning of the data on
25458f0484fSRodney W. Grimes  *				this page
25558f0484fSRodney W. Grimes  *		    FULL_KEY_DATA -- 3
25658f0484fSRodney W. Grimes  *		    OVFL_PAGENO - page number of the next overflow page
25758f0484fSRodney W. Grimes  *		    OVFLPAGE -- 0
25858f0484fSRodney W. Grimes  *
25958f0484fSRodney W. Grimes  *		    OVFL_PAGENO and OVFLPAGE are optional (they are
26058f0484fSRodney W. Grimes  *		    not present if there is no next page).
26158f0484fSRodney W. Grimes  */
26258f0484fSRodney W. Grimes 
26358f0484fSRodney W. Grimes #define OVFLPAGE	0
26458f0484fSRodney W. Grimes #define PARTIAL_KEY	1
26558f0484fSRodney W. Grimes #define FULL_KEY	2
26658f0484fSRodney W. Grimes #define FULL_KEY_DATA	3
26758f0484fSRodney W. Grimes #define	REAL_KEY	4
26858f0484fSRodney W. Grimes 
26958f0484fSRodney W. Grimes /* Short hands for accessing structure */
27058f0484fSRodney W. Grimes #define BSIZE		hdr.bsize
27158f0484fSRodney W. Grimes #define BSHIFT		hdr.bshift
27258f0484fSRodney W. Grimes #define DSIZE		hdr.dsize
27358f0484fSRodney W. Grimes #define SGSIZE		hdr.ssize
27458f0484fSRodney W. Grimes #define SSHIFT		hdr.sshift
27558f0484fSRodney W. Grimes #define LORDER		hdr.lorder
27658f0484fSRodney W. Grimes #define OVFL_POINT	hdr.ovfl_point
27758f0484fSRodney W. Grimes #define	LAST_FREED	hdr.last_freed
27858f0484fSRodney W. Grimes #define MAX_BUCKET	hdr.max_bucket
27958f0484fSRodney W. Grimes #define FFACTOR		hdr.ffactor
28058f0484fSRodney W. Grimes #define HIGH_MASK	hdr.high_mask
28158f0484fSRodney W. Grimes #define LOW_MASK	hdr.low_mask
28258f0484fSRodney W. Grimes #define NKEYS		hdr.nkeys
28358f0484fSRodney W. Grimes #define HDRPAGES	hdr.hdrpages
28458f0484fSRodney W. Grimes #define SPARES		hdr.spares
28558f0484fSRodney W. Grimes #define BITMAPS		hdr.bitmaps
28658f0484fSRodney W. Grimes #define VERSION		hdr.version
28758f0484fSRodney W. Grimes #define MAGIC		hdr.magic
28858f0484fSRodney W. Grimes #define NEXT_FREE	hdr.next_free
28958f0484fSRodney W. Grimes #define H_CHARKEY	hdr.h_charkey
290