1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * sdbm - ndbm work-alike hashed database library
19 * based on Per-Aake Larson's Dynamic Hashing algorithms. BIT 18 (1978).
20 * author: oz@nexus.yorku.ca
21 * status: ex-public domain.
28 #include "sdbm_tune.h"
29 #include "sdbm_pair.h"
30 #include "sdbm_private.h"
32 #include <string.h> /* for memset() */
35 #define exhash(item) sdbm_hash((item).dptr, (item).dsize)
40 static int seepair(char *, int, char *, int);
44 * +------------------------------+
45 * ino | n | keyoff | datoff | keyoff |
46 * +------------+--------+--------+
47 * | datoff | - - - ----> |
48 * +--------+---------------------+
50 * +--------------+---------------+
51 * | <---- - - - | data |
52 * +--------+-----+----+----------+
53 * | key | data | key |
54 * +--------+----------+----------+
56 * calculating the offsets for free area: if the number
57 * of entries (ino[0]) is zero, the offset to the END of
58 * the free area is the block size. Otherwise, it is the
59 * nth (ino[ino[0]]) entry's offset.
70 register short *ino = (short *) pag;
72 off = ((n = ino[0]) > 0) ? ino[n] : PBLKSIZ;
73 avail = off - (n + 1) * sizeof(short);
74 need += 2 * sizeof(short);
76 debug(("avail %d need %d\n", avail, need));
82 putpair(pag, key, val)
89 register short *ino = (short *) pag;
91 off = ((n = ino[0]) > 0) ? ino[n] : PBLKSIZ;
96 (void) memcpy(pag + off, key.dptr, key.dsize);
102 (void) memcpy(pag + off, val.dptr, val.dsize);
113 apr_sdbm_datum_t key;
117 apr_sdbm_datum_t val;
118 register short *ino = (short *) pag;
120 if ((n = ino[0]) == 0)
121 return sdbm_nullitem;
123 if ((i = seepair(pag, n, key.dptr, key.dsize)) == 0)
124 return sdbm_nullitem;
126 val.dptr = pag + ino[i + 1];
127 val.dsize = ino[i] - ino[i + 1];
134 apr_sdbm_datum_t key;
136 register short *ino = (short *) pag;
137 return ino[0] > 0 && seepair(pag, ino[0], key.dptr, key.dsize) > 0;
145 apr_sdbm_datum_t key;
147 register short *ino = (short *) pag;
150 if (ino[0] == 0 || num > ino[0])
151 return sdbm_nullitem;
153 off = (num > 1) ? ino[num - 1] : PBLKSIZ;
155 key.dptr = pag + ino[num];
156 key.dsize = off - ino[num];
164 apr_sdbm_datum_t key;
168 register short *ino = (short *) pag;
170 if ((n = ino[0]) == 0)
173 if ((i = seepair(pag, n, key.dptr, key.dsize)) == 0)
176 * found the key. if it is the last entry
177 * [i.e. i == n - 1] we just adjust the entry count.
178 * hard case: move all data down onto the deleted pair,
179 * shift offsets onto deleted offsets, and adjust them.
184 register char *dst = pag + (i == 1 ? PBLKSIZ : ino[i - 1]);
185 register char *src = pag + ino[i + 1];
186 register short zoo = (short) (dst - src);
188 debug(("free-up %d ", zoo));
190 * shift data/keys down
192 m = ino[i + 1] - ino[n];
194 #undef DUFF /* just use memmove. it should be plenty fast. */
196 #define MOVB *--dst = *--src
199 register int loop = (m + 8 - 1) >> 3;
201 switch (m & (8 - 1)) {
204 case 6: MOVB; case 5: MOVB;
205 case 4: MOVB; case 3: MOVB;
206 case 2: MOVB; case 1: MOVB;
213 memmove(dst, src, m);
217 * adjust offset index up
220 ino[i] = ino[i + 2] + zoo;
229 * search for the key in the page.
230 * return offset index in the range 0 < i < n.
231 * return 0 if not found.
234 seepair(pag, n, key, siz)
241 register int off = PBLKSIZ;
242 register short *ino = (short *) pag;
244 for (i = 1; i < n; i += 2) {
245 if (siz == off - ino[i] &&
246 memcmp(key, pag + ino[i], siz) == 0)
254 splpage(pag, new, sbit)
259 apr_sdbm_datum_t key;
260 apr_sdbm_datum_t val;
263 register int off = PBLKSIZ;
265 register short *ino = (short *) cur;
267 (void) memcpy(cur, pag, PBLKSIZ);
268 (void) memset(pag, 0, PBLKSIZ);
269 (void) memset(new, 0, PBLKSIZ);
272 for (ino++; n > 0; ino += 2) {
273 key.dptr = cur + ino[0];
274 key.dsize = off - ino[0];
275 val.dptr = cur + ino[1];
276 val.dsize = ino[0] - ino[1];
278 * select the page pointer (by looking at sbit) and insert
280 (void) putpair((exhash(key) & sbit) ? new : pag, key, val);
286 debug(("%d split %d/%d\n", ((short *) cur)[0] / 2,
287 ((short *) new)[0] / 2,
288 ((short *) pag)[0] / 2));
293 * number of entries should be something
294 * reasonable, and all offsets in the index should be in order.
295 * this could be made more rigorous.
303 register short *ino = (short *) pag;
305 if ((n = ino[0]) < 0 || n > PBLKSIZ / sizeof(short))
310 for (ino++; n > 0; ino += 2) {
311 if (ino[0] > off || ino[1] > off ||