Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/lib/libc/db/hash/hash.c
39507 views
1
/*-
2
* SPDX-License-Identifier: BSD-3-Clause
3
*
4
* Copyright (c) 1990, 1993, 1994
5
* The Regents of the University of California. All rights reserved.
6
*
7
* This code is derived from software contributed to Berkeley by
8
* Margo Seltzer.
9
*
10
* Redistribution and use in source and binary forms, with or without
11
* modification, are permitted provided that the following conditions
12
* are met:
13
* 1. Redistributions of source code must retain the above copyright
14
* notice, this list of conditions and the following disclaimer.
15
* 2. Redistributions in binary form must reproduce the above copyright
16
* notice, this list of conditions and the following disclaimer in the
17
* documentation and/or other materials provided with the distribution.
18
* 3. Neither the name of the University nor the names of its contributors
19
* may be used to endorse or promote products derived from this software
20
* without specific prior written permission.
21
*
22
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32
* SUCH DAMAGE.
33
*/
34
35
#include "namespace.h"
36
#include <sys/param.h>
37
#include <sys/stat.h>
38
39
#include <errno.h>
40
#include <fcntl.h>
41
#include <stdio.h>
42
#include <stdlib.h>
43
#include <string.h>
44
#include <unistd.h>
45
#ifdef DEBUG
46
#include <assert.h>
47
#endif
48
#include "un-namespace.h"
49
50
#include <db.h>
51
#include "hash.h"
52
#include "page.h"
53
#include "extern.h"
54
55
static int alloc_segs(HTAB *, int);
56
static int flush_meta(HTAB *);
57
static int hash_access(HTAB *, ACTION, DBT *, DBT *);
58
static int hash_close(DB *);
59
static int hash_delete(const DB *, const DBT *, u_int32_t);
60
static int hash_fd(const DB *);
61
static int hash_get(const DB *, const DBT *, DBT *, u_int32_t);
62
static int hash_put(const DB *, DBT *, const DBT *, u_int32_t);
63
static void *hash_realloc(SEGMENT **, int, int);
64
static int hash_seq(const DB *, DBT *, DBT *, u_int32_t);
65
static int hash_sync(const DB *, u_int32_t);
66
static int hdestroy(HTAB *);
67
static HTAB *init_hash(HTAB *, const char *, const HASHINFO *);
68
static int init_htab(HTAB *, int);
69
#if BYTE_ORDER == LITTLE_ENDIAN
70
static void swap_header(HTAB *);
71
static void swap_header_copy(HASHHDR *, HASHHDR *);
72
#endif
73
74
/* Fast arithmetic, relying on powers of 2, */
75
#define MOD(x, y) ((x) & ((y) - 1))
76
77
#define RETURN_ERROR(ERR, LOC) { save_errno = ERR; goto LOC; }
78
79
/* Return values */
80
#define SUCCESS (0)
81
#define ERROR (-1)
82
#define ABNORMAL (1)
83
84
#ifdef HASH_STATISTICS
85
int hash_accesses, hash_collisions, hash_expansions, hash_overflows;
86
#endif
87
88
/************************** INTERFACE ROUTINES ***************************/
89
/* OPEN/CLOSE */
90
91
/* ARGSUSED */
92
DB *
93
__hash_open(const char *file, int flags, int mode,
94
const HASHINFO *info, /* Special directives for create */
95
int dflags)
96
{
97
HTAB *hashp;
98
struct stat statbuf;
99
DB *dbp;
100
int bpages, hdrsize, new_table, nsegs, save_errno;
101
102
if (!(hashp = (HTAB *)calloc(1, sizeof(HTAB))))
103
return (NULL);
104
hashp->fp = -1;
105
106
/*
107
* Even if user wants write only, we need to be able to read
108
* the actual file, so we need to open it read/write. But, the
109
* field in the hashp structure needs to be accurate so that
110
* we can check accesses.
111
*/
112
hashp->flags = flags;
113
if ((flags & O_ACCMODE) == O_WRONLY) {
114
flags &= ~O_WRONLY;
115
flags |= O_RDWR;
116
}
117
118
if (file) {
119
if ((hashp->fp = _open(file, flags | O_CLOEXEC, mode)) == -1)
120
RETURN_ERROR(errno, error0);
121
new_table = _fstat(hashp->fp, &statbuf) == 0 &&
122
statbuf.st_size == 0 &&
123
((flags & O_ACCMODE) != O_RDONLY || (flags & O_CREAT) != 0);
124
} else
125
new_table = 1;
126
127
if (new_table) {
128
if (!(hashp = init_hash(hashp, file, info)))
129
RETURN_ERROR(errno, error1);
130
} else {
131
/* Table already exists */
132
if (info && info->hash)
133
hashp->hash = info->hash;
134
else
135
hashp->hash = __default_hash;
136
137
hdrsize = _read(hashp->fp, &hashp->hdr, sizeof(HASHHDR));
138
#if BYTE_ORDER == LITTLE_ENDIAN
139
swap_header(hashp);
140
#endif
141
if (hdrsize == -1)
142
RETURN_ERROR(errno, error1);
143
if (hdrsize != sizeof(HASHHDR))
144
RETURN_ERROR(EFTYPE, error1);
145
/* Verify file type, versions and hash function */
146
if (hashp->MAGIC != HASHMAGIC)
147
RETURN_ERROR(EFTYPE, error1);
148
#define OLDHASHVERSION 1
149
if (hashp->VERSION != HASHVERSION &&
150
hashp->VERSION != OLDHASHVERSION)
151
RETURN_ERROR(EFTYPE, error1);
152
if ((int32_t)hashp->hash(CHARKEY, sizeof(CHARKEY)) != hashp->H_CHARKEY)
153
RETURN_ERROR(EFTYPE, error1);
154
/*
155
* Figure out how many segments we need. Max_Bucket is the
156
* maximum bucket number, so the number of buckets is
157
* max_bucket + 1.
158
*/
159
nsegs = howmany(hashp->MAX_BUCKET + 1, hashp->SGSIZE);
160
if (alloc_segs(hashp, nsegs))
161
/*
162
* If alloc_segs fails, table will have been destroyed
163
* and errno will have been set.
164
*/
165
return (NULL);
166
/* Read in bitmaps */
167
bpages = (hashp->SPARES[hashp->OVFL_POINT] +
168
(hashp->BSIZE << BYTE_SHIFT) - 1) >>
169
(hashp->BSHIFT + BYTE_SHIFT);
170
171
hashp->nmaps = bpages;
172
(void)memset(&hashp->mapp[0], 0, bpages * sizeof(u_int32_t *));
173
}
174
175
/* Initialize Buffer Manager */
176
if (info && info->cachesize)
177
__buf_init(hashp, info->cachesize);
178
else
179
__buf_init(hashp, DEF_BUFSIZE);
180
181
hashp->new_file = new_table;
182
hashp->save_file = file && (flags & O_RDWR);
183
hashp->cbucket = -1;
184
if (!(dbp = (DB *)malloc(sizeof(DB)))) {
185
save_errno = errno;
186
hdestroy(hashp);
187
errno = save_errno;
188
return (NULL);
189
}
190
dbp->internal = hashp;
191
dbp->close = hash_close;
192
dbp->del = hash_delete;
193
dbp->fd = hash_fd;
194
dbp->get = hash_get;
195
dbp->put = hash_put;
196
dbp->seq = hash_seq;
197
dbp->sync = hash_sync;
198
dbp->type = DB_HASH;
199
200
#ifdef DEBUG
201
(void)fprintf(stderr,
202
"%s\n%s%p\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%x\n%s%x\n%s%d\n%s%d\n",
203
"init_htab:",
204
"TABLE POINTER ", hashp,
205
"BUCKET SIZE ", hashp->BSIZE,
206
"BUCKET SHIFT ", hashp->BSHIFT,
207
"DIRECTORY SIZE ", hashp->DSIZE,
208
"SEGMENT SIZE ", hashp->SGSIZE,
209
"SEGMENT SHIFT ", hashp->SSHIFT,
210
"FILL FACTOR ", hashp->FFACTOR,
211
"MAX BUCKET ", hashp->MAX_BUCKET,
212
"OVFL POINT ", hashp->OVFL_POINT,
213
"LAST FREED ", hashp->LAST_FREED,
214
"HIGH MASK ", hashp->HIGH_MASK,
215
"LOW MASK ", hashp->LOW_MASK,
216
"NSEGS ", hashp->nsegs,
217
"NKEYS ", hashp->NKEYS);
218
#endif
219
#ifdef HASH_STATISTICS
220
hash_overflows = hash_accesses = hash_collisions = hash_expansions = 0;
221
#endif
222
return (dbp);
223
224
error1:
225
if (hashp != NULL)
226
(void)_close(hashp->fp);
227
228
error0:
229
free(hashp);
230
errno = save_errno;
231
return (NULL);
232
}
233
234
static int
235
hash_close(DB *dbp)
236
{
237
HTAB *hashp;
238
int retval;
239
240
if (!dbp)
241
return (ERROR);
242
243
hashp = (HTAB *)dbp->internal;
244
retval = hdestroy(hashp);
245
free(dbp);
246
return (retval);
247
}
248
249
static int
250
hash_fd(const DB *dbp)
251
{
252
HTAB *hashp;
253
254
if (!dbp)
255
return (ERROR);
256
257
hashp = (HTAB *)dbp->internal;
258
if (hashp->fp == -1) {
259
errno = ENOENT;
260
return (-1);
261
}
262
return (hashp->fp);
263
}
264
265
/************************** LOCAL CREATION ROUTINES **********************/
266
static HTAB *
267
init_hash(HTAB *hashp, const char *file, const HASHINFO *info)
268
{
269
struct stat statbuf;
270
int nelem;
271
272
nelem = 1;
273
hashp->NKEYS = 0;
274
hashp->LORDER = BYTE_ORDER;
275
hashp->BSIZE = DEF_BUCKET_SIZE;
276
hashp->BSHIFT = DEF_BUCKET_SHIFT;
277
hashp->SGSIZE = DEF_SEGSIZE;
278
hashp->SSHIFT = DEF_SEGSIZE_SHIFT;
279
hashp->DSIZE = DEF_DIRSIZE;
280
hashp->FFACTOR = DEF_FFACTOR;
281
hashp->hash = __default_hash;
282
memset(hashp->SPARES, 0, sizeof(hashp->SPARES));
283
memset(hashp->BITMAPS, 0, sizeof (hashp->BITMAPS));
284
285
/* Fix bucket size to be optimal for file system */
286
if (file != NULL) {
287
if (stat(file, &statbuf))
288
return (NULL);
289
hashp->BSIZE = statbuf.st_blksize;
290
if (hashp->BSIZE > MAX_BSIZE)
291
hashp->BSIZE = MAX_BSIZE;
292
hashp->BSHIFT = __log2(hashp->BSIZE);
293
}
294
295
if (info) {
296
if (info->bsize) {
297
/* Round pagesize up to power of 2 */
298
hashp->BSHIFT = __log2(info->bsize);
299
hashp->BSIZE = 1 << hashp->BSHIFT;
300
if (hashp->BSIZE > MAX_BSIZE) {
301
errno = EINVAL;
302
return (NULL);
303
}
304
}
305
if (info->ffactor)
306
hashp->FFACTOR = info->ffactor;
307
if (info->hash)
308
hashp->hash = info->hash;
309
if (info->nelem)
310
nelem = info->nelem;
311
if (info->lorder) {
312
if (info->lorder != BIG_ENDIAN &&
313
info->lorder != LITTLE_ENDIAN) {
314
errno = EINVAL;
315
return (NULL);
316
}
317
hashp->LORDER = info->lorder;
318
}
319
}
320
/* init_htab should destroy the table and set errno if it fails */
321
if (init_htab(hashp, nelem))
322
return (NULL);
323
else
324
return (hashp);
325
}
326
/*
327
* This calls alloc_segs which may run out of memory. Alloc_segs will destroy
328
* the table and set errno, so we just pass the error information along.
329
*
330
* Returns 0 on No Error
331
*/
332
static int
333
init_htab(HTAB *hashp, int nelem)
334
{
335
int nbuckets, nsegs, l2;
336
337
/*
338
* Divide number of elements by the fill factor and determine a
339
* desired number of buckets. Allocate space for the next greater
340
* power of two number of buckets.
341
*/
342
nelem = (nelem - 1) / hashp->FFACTOR + 1;
343
344
l2 = __log2(MAX(nelem, 2));
345
nbuckets = 1 << l2;
346
347
hashp->SPARES[l2] = l2 + 1;
348
hashp->SPARES[l2 + 1] = l2 + 1;
349
hashp->OVFL_POINT = l2;
350
hashp->LAST_FREED = 2;
351
352
/* First bitmap page is at: splitpoint l2 page offset 1 */
353
if (__ibitmap(hashp, OADDR_OF(l2, 1), l2 + 1, 0))
354
return (-1);
355
356
hashp->MAX_BUCKET = hashp->LOW_MASK = nbuckets - 1;
357
hashp->HIGH_MASK = (nbuckets << 1) - 1;
358
hashp->HDRPAGES = ((MAX(sizeof(HASHHDR), MINHDRSIZE) - 1) >>
359
hashp->BSHIFT) + 1;
360
361
nsegs = (nbuckets - 1) / hashp->SGSIZE + 1;
362
nsegs = 1 << __log2(nsegs);
363
364
if (nsegs > hashp->DSIZE)
365
hashp->DSIZE = nsegs;
366
return (alloc_segs(hashp, nsegs));
367
}
368
369
/********************** DESTROY/CLOSE ROUTINES ************************/
370
371
/*
372
* Flushes any changes to the file if necessary and destroys the hashp
373
* structure, freeing all allocated space.
374
*/
375
static int
376
hdestroy(HTAB *hashp)
377
{
378
int i, save_errno;
379
380
save_errno = 0;
381
382
#ifdef HASH_STATISTICS
383
(void)fprintf(stderr, "hdestroy: accesses %ld collisions %ld\n",
384
hash_accesses, hash_collisions);
385
(void)fprintf(stderr, "hdestroy: expansions %ld\n",
386
hash_expansions);
387
(void)fprintf(stderr, "hdestroy: overflows %ld\n",
388
hash_overflows);
389
(void)fprintf(stderr, "keys %ld maxp %d segmentcount %d\n",
390
hashp->NKEYS, hashp->MAX_BUCKET, hashp->nsegs);
391
392
for (i = 0; i < NCACHED; i++)
393
(void)fprintf(stderr,
394
"spares[%d] = %d\n", i, hashp->SPARES[i]);
395
#endif
396
/*
397
* Call on buffer manager to free buffers, and if required,
398
* write them to disk.
399
*/
400
if (__buf_free(hashp, 1, hashp->save_file))
401
save_errno = errno;
402
if (hashp->dir) {
403
free(*hashp->dir); /* Free initial segments */
404
/* Free extra segments */
405
while (hashp->exsegs--)
406
free(hashp->dir[--hashp->nsegs]);
407
free(hashp->dir);
408
}
409
if (flush_meta(hashp) && !save_errno)
410
save_errno = errno;
411
/* Free Bigmaps */
412
for (i = 0; i < hashp->nmaps; i++)
413
if (hashp->mapp[i])
414
free(hashp->mapp[i]);
415
if (hashp->tmp_key)
416
free(hashp->tmp_key);
417
if (hashp->tmp_buf)
418
free(hashp->tmp_buf);
419
420
if (hashp->fp != -1) {
421
if (hashp->save_file)
422
(void)_fsync(hashp->fp);
423
(void)_close(hashp->fp);
424
}
425
426
free(hashp);
427
428
if (save_errno) {
429
errno = save_errno;
430
return (ERROR);
431
}
432
return (SUCCESS);
433
}
434
/*
435
* Write modified pages to disk
436
*
437
* Returns:
438
* 0 == OK
439
* -1 ERROR
440
*/
441
static int
442
hash_sync(const DB *dbp, u_int32_t flags)
443
{
444
HTAB *hashp;
445
446
if (flags != 0) {
447
errno = EINVAL;
448
return (ERROR);
449
}
450
451
if (!dbp)
452
return (ERROR);
453
454
hashp = (HTAB *)dbp->internal;
455
if (!hashp->save_file)
456
return (0);
457
if (__buf_free(hashp, 0, 1) || flush_meta(hashp))
458
return (ERROR);
459
if (hashp->fp != -1 && _fsync(hashp->fp) != 0)
460
return (ERROR);
461
hashp->new_file = 0;
462
return (0);
463
}
464
465
/*
466
* Returns:
467
* 0 == OK
468
* -1 indicates that errno should be set
469
*/
470
static int
471
flush_meta(HTAB *hashp)
472
{
473
HASHHDR *whdrp;
474
#if BYTE_ORDER == LITTLE_ENDIAN
475
HASHHDR whdr;
476
#endif
477
int fp, i, wsize;
478
479
if (!hashp->save_file)
480
return (0);
481
hashp->MAGIC = HASHMAGIC;
482
hashp->VERSION = HASHVERSION;
483
hashp->H_CHARKEY = hashp->hash(CHARKEY, sizeof(CHARKEY));
484
485
fp = hashp->fp;
486
whdrp = &hashp->hdr;
487
#if BYTE_ORDER == LITTLE_ENDIAN
488
whdrp = &whdr;
489
swap_header_copy(&hashp->hdr, whdrp);
490
#endif
491
if ((wsize = pwrite(fp, whdrp, sizeof(HASHHDR), (off_t)0)) == -1)
492
return (-1);
493
else
494
if (wsize != sizeof(HASHHDR)) {
495
errno = EFTYPE;
496
hashp->error = errno;
497
return (-1);
498
}
499
for (i = 0; i < NCACHED; i++)
500
if (hashp->mapp[i])
501
if (__put_page(hashp, (char *)hashp->mapp[i],
502
hashp->BITMAPS[i], 0, 1))
503
return (-1);
504
return (0);
505
}
506
507
/*******************************SEARCH ROUTINES *****************************/
508
/*
509
* All the access routines return
510
*
511
* Returns:
512
* 0 on SUCCESS
513
* 1 to indicate an external ERROR (i.e. key not found, etc)
514
* -1 to indicate an internal ERROR (i.e. out of memory, etc)
515
*/
516
static int
517
hash_get(const DB *dbp, const DBT *key, DBT *data, u_int32_t flag)
518
{
519
HTAB *hashp;
520
521
hashp = (HTAB *)dbp->internal;
522
if (flag) {
523
hashp->error = errno = EINVAL;
524
return (ERROR);
525
}
526
if ((hashp->flags & O_ACCMODE) == O_WRONLY) {
527
hashp->error = errno = EPERM;
528
return (ERROR);
529
}
530
return (hash_access(hashp, HASH_GET, (DBT *)key, data));
531
}
532
533
static int
534
hash_put(const DB *dbp, DBT *key, const DBT *data, u_int32_t flag)
535
{
536
HTAB *hashp;
537
538
hashp = (HTAB *)dbp->internal;
539
if (flag && flag != R_NOOVERWRITE) {
540
hashp->error = errno = EINVAL;
541
return (ERROR);
542
}
543
if ((hashp->flags & O_ACCMODE) == O_RDONLY) {
544
hashp->error = errno = EPERM;
545
return (ERROR);
546
}
547
return (hash_access(hashp, flag == R_NOOVERWRITE ?
548
HASH_PUTNEW : HASH_PUT, (DBT *)key, (DBT *)data));
549
}
550
551
static int
552
hash_delete(const DB *dbp, const DBT *key,
553
u_int32_t flag) /* Ignored */
554
{
555
HTAB *hashp;
556
557
hashp = (HTAB *)dbp->internal;
558
if (flag && flag != R_CURSOR) {
559
hashp->error = errno = EINVAL;
560
return (ERROR);
561
}
562
if ((hashp->flags & O_ACCMODE) == O_RDONLY) {
563
hashp->error = errno = EPERM;
564
return (ERROR);
565
}
566
return (hash_access(hashp, HASH_DELETE, (DBT *)key, NULL));
567
}
568
569
/*
570
* Assume that hashp has been set in wrapper routine.
571
*/
572
static int
573
hash_access(HTAB *hashp, ACTION action, DBT *key, DBT *val)
574
{
575
BUFHEAD *rbufp;
576
BUFHEAD *bufp, *save_bufp;
577
u_int16_t *bp;
578
int n, ndx, off, size;
579
char *kp;
580
u_int16_t pageno;
581
582
#ifdef HASH_STATISTICS
583
hash_accesses++;
584
#endif
585
586
off = hashp->BSIZE;
587
size = key->size;
588
kp = (char *)key->data;
589
rbufp = __get_buf(hashp, __call_hash(hashp, kp, size), NULL, 0);
590
if (!rbufp)
591
return (ERROR);
592
save_bufp = rbufp;
593
594
/* Pin the bucket chain */
595
rbufp->flags |= BUF_PIN;
596
for (bp = (u_int16_t *)rbufp->page, n = *bp++, ndx = 1; ndx < n;)
597
if (bp[1] >= REAL_KEY) {
598
/* Real key/data pair */
599
if (size == off - *bp &&
600
memcmp(kp, rbufp->page + *bp, size) == 0)
601
goto found;
602
off = bp[1];
603
#ifdef HASH_STATISTICS
604
hash_collisions++;
605
#endif
606
bp += 2;
607
ndx += 2;
608
} else if (bp[1] == OVFLPAGE) {
609
rbufp = __get_buf(hashp, *bp, rbufp, 0);
610
if (!rbufp) {
611
save_bufp->flags &= ~BUF_PIN;
612
return (ERROR);
613
}
614
/* FOR LOOP INIT */
615
bp = (u_int16_t *)rbufp->page;
616
n = *bp++;
617
ndx = 1;
618
off = hashp->BSIZE;
619
} else if (bp[1] < REAL_KEY) {
620
if ((ndx =
621
__find_bigpair(hashp, rbufp, ndx, kp, size)) > 0)
622
goto found;
623
if (ndx == -2) {
624
bufp = rbufp;
625
if (!(pageno =
626
__find_last_page(hashp, &bufp))) {
627
ndx = 0;
628
rbufp = bufp;
629
break; /* FOR */
630
}
631
rbufp = __get_buf(hashp, pageno, bufp, 0);
632
if (!rbufp) {
633
save_bufp->flags &= ~BUF_PIN;
634
return (ERROR);
635
}
636
/* FOR LOOP INIT */
637
bp = (u_int16_t *)rbufp->page;
638
n = *bp++;
639
ndx = 1;
640
off = hashp->BSIZE;
641
} else {
642
save_bufp->flags &= ~BUF_PIN;
643
return (ERROR);
644
}
645
}
646
647
/* Not found */
648
switch (action) {
649
case HASH_PUT:
650
case HASH_PUTNEW:
651
if (__addel(hashp, rbufp, key, val)) {
652
save_bufp->flags &= ~BUF_PIN;
653
return (ERROR);
654
} else {
655
save_bufp->flags &= ~BUF_PIN;
656
return (SUCCESS);
657
}
658
case HASH_GET:
659
case HASH_DELETE:
660
default:
661
save_bufp->flags &= ~BUF_PIN;
662
return (ABNORMAL);
663
}
664
665
found:
666
switch (action) {
667
case HASH_PUTNEW:
668
save_bufp->flags &= ~BUF_PIN;
669
return (ABNORMAL);
670
case HASH_GET:
671
bp = (u_int16_t *)rbufp->page;
672
if (bp[ndx + 1] < REAL_KEY) {
673
if (__big_return(hashp, rbufp, ndx, val, 0))
674
return (ERROR);
675
} else {
676
val->data = (u_char *)rbufp->page + (int)bp[ndx + 1];
677
val->size = bp[ndx] - bp[ndx + 1];
678
}
679
break;
680
case HASH_PUT:
681
if ((__delpair(hashp, rbufp, ndx)) ||
682
(__addel(hashp, rbufp, key, val))) {
683
save_bufp->flags &= ~BUF_PIN;
684
return (ERROR);
685
}
686
break;
687
case HASH_DELETE:
688
if (__delpair(hashp, rbufp, ndx))
689
return (ERROR);
690
break;
691
default:
692
abort();
693
}
694
save_bufp->flags &= ~BUF_PIN;
695
return (SUCCESS);
696
}
697
698
static int
699
hash_seq(const DB *dbp, DBT *key, DBT *data, u_int32_t flag)
700
{
701
u_int32_t bucket;
702
BUFHEAD *bufp;
703
HTAB *hashp;
704
u_int16_t *bp, ndx;
705
706
hashp = (HTAB *)dbp->internal;
707
if (flag != R_FIRST && flag != R_NEXT) {
708
hashp->error = errno = EINVAL;
709
return (ERROR);
710
}
711
#ifdef HASH_STATISTICS
712
hash_accesses++;
713
#endif
714
if (flag == R_FIRST) {
715
hashp->cbucket = 0;
716
hashp->cndx = 1;
717
hashp->cpage = NULL;
718
} else if (hashp->cbucket < 0) { /* R_NEXT */
719
return (ABNORMAL);
720
}
721
next_bucket:
722
for (bp = NULL; !bp || !bp[0]; ) {
723
if (!(bufp = hashp->cpage)) {
724
for (bucket = hashp->cbucket;
725
bucket <= hashp->MAX_BUCKET;
726
bucket++, hashp->cndx = 1) {
727
bufp = __get_buf(hashp, bucket, NULL, 0);
728
if (!bufp)
729
return (ERROR);
730
hashp->cpage = bufp;
731
bp = (u_int16_t *)bufp->page;
732
if (bp[0])
733
break;
734
}
735
hashp->cbucket = bucket;
736
if ((u_int32_t)hashp->cbucket > hashp->MAX_BUCKET) {
737
hashp->cbucket = -1;
738
return (ABNORMAL);
739
}
740
} else {
741
bp = (u_int16_t *)hashp->cpage->page;
742
if (flag == R_NEXT || flag == 0) {
743
hashp->cndx += 2;
744
if (hashp->cndx > bp[0]) {
745
hashp->cpage = NULL;
746
hashp->cbucket++;
747
hashp->cndx = 1;
748
goto next_bucket;
749
}
750
}
751
}
752
753
#ifdef DEBUG
754
assert(bp);
755
assert(bufp);
756
#endif
757
while (bp[hashp->cndx + 1] == OVFLPAGE) {
758
bufp = hashp->cpage =
759
__get_buf(hashp, bp[hashp->cndx], bufp, 0);
760
if (!bufp)
761
return (ERROR);
762
bp = (u_int16_t *)(bufp->page);
763
hashp->cndx = 1;
764
}
765
if (!bp[0]) {
766
hashp->cpage = NULL;
767
++hashp->cbucket;
768
}
769
}
770
ndx = hashp->cndx;
771
if (bp[ndx + 1] < REAL_KEY) {
772
if (__big_keydata(hashp, bufp, key, data, 1))
773
return (ERROR);
774
} else {
775
if (hashp->cpage == NULL)
776
return (ERROR);
777
key->data = (u_char *)hashp->cpage->page + bp[ndx];
778
key->size = (ndx > 1 ? bp[ndx - 1] : hashp->BSIZE) - bp[ndx];
779
data->data = (u_char *)hashp->cpage->page + bp[ndx + 1];
780
data->size = bp[ndx] - bp[ndx + 1];
781
}
782
return (SUCCESS);
783
}
784
785
/********************************* UTILITIES ************************/
786
787
/*
788
* Returns:
789
* 0 ==> OK
790
* -1 ==> Error
791
*/
792
int
793
__expand_table(HTAB *hashp)
794
{
795
u_int32_t old_bucket, new_bucket;
796
int dirsize, new_segnum, spare_ndx;
797
798
#ifdef HASH_STATISTICS
799
hash_expansions++;
800
#endif
801
new_bucket = ++hashp->MAX_BUCKET;
802
old_bucket = (hashp->MAX_BUCKET & hashp->LOW_MASK);
803
804
new_segnum = new_bucket >> hashp->SSHIFT;
805
806
/* Check if we need a new segment */
807
if (new_segnum >= hashp->nsegs) {
808
/* Check if we need to expand directory */
809
if (new_segnum >= hashp->DSIZE) {
810
/* Reallocate directory */
811
dirsize = hashp->DSIZE * sizeof(SEGMENT *);
812
if (!hash_realloc(&hashp->dir, dirsize, dirsize << 1))
813
return (-1);
814
hashp->DSIZE = dirsize << 1;
815
}
816
if ((hashp->dir[new_segnum] =
817
calloc(hashp->SGSIZE, sizeof(SEGMENT))) == NULL)
818
return (-1);
819
hashp->exsegs++;
820
hashp->nsegs++;
821
}
822
/*
823
* If the split point is increasing (MAX_BUCKET's log base 2
824
* * increases), we need to copy the current contents of the spare
825
* split bucket to the next bucket.
826
*/
827
spare_ndx = __log2(hashp->MAX_BUCKET + 1);
828
if (spare_ndx > hashp->OVFL_POINT) {
829
hashp->SPARES[spare_ndx] = hashp->SPARES[hashp->OVFL_POINT];
830
hashp->OVFL_POINT = spare_ndx;
831
}
832
833
if (new_bucket > hashp->HIGH_MASK) {
834
/* Starting a new doubling */
835
hashp->LOW_MASK = hashp->HIGH_MASK;
836
hashp->HIGH_MASK = new_bucket | hashp->LOW_MASK;
837
}
838
/* Relocate records to the new bucket */
839
return (__split_page(hashp, old_bucket, new_bucket));
840
}
841
842
/*
843
* If realloc guarantees that the pointer is not destroyed if the realloc
844
* fails, then this routine can go away.
845
*/
846
static void *
847
hash_realloc(SEGMENT **p_ptr, int oldsize, int newsize)
848
{
849
void *p;
850
851
if ( (p = malloc(newsize)) ) {
852
memmove(p, *p_ptr, oldsize);
853
memset((char *)p + oldsize, 0, newsize - oldsize);
854
free(*p_ptr);
855
*p_ptr = p;
856
}
857
return (p);
858
}
859
860
u_int32_t
861
__call_hash(HTAB *hashp, char *k, int len)
862
{
863
unsigned int n, bucket;
864
865
n = hashp->hash(k, len);
866
bucket = n & hashp->HIGH_MASK;
867
if (bucket > hashp->MAX_BUCKET)
868
bucket = bucket & hashp->LOW_MASK;
869
return (bucket);
870
}
871
872
/*
873
* Allocate segment table. On error, destroy the table and set errno.
874
*
875
* Returns 0 on success
876
*/
877
static int
878
alloc_segs(HTAB *hashp, int nsegs)
879
{
880
int i;
881
SEGMENT store;
882
883
int save_errno;
884
885
if ((hashp->dir =
886
calloc(hashp->DSIZE, sizeof(SEGMENT *))) == NULL) {
887
save_errno = errno;
888
(void)hdestroy(hashp);
889
errno = save_errno;
890
return (-1);
891
}
892
hashp->nsegs = nsegs;
893
if (nsegs == 0)
894
return (0);
895
/* Allocate segments */
896
if ((store = calloc(nsegs << hashp->SSHIFT, sizeof(SEGMENT))) == NULL) {
897
save_errno = errno;
898
(void)hdestroy(hashp);
899
errno = save_errno;
900
return (-1);
901
}
902
for (i = 0; i < nsegs; i++)
903
hashp->dir[i] = &store[i << hashp->SSHIFT];
904
return (0);
905
}
906
907
#if BYTE_ORDER == LITTLE_ENDIAN
908
/*
909
* Hashp->hdr needs to be byteswapped.
910
*/
911
static void
912
swap_header_copy(HASHHDR *srcp, HASHHDR *destp)
913
{
914
int i;
915
916
P_32_COPY(srcp->magic, destp->magic);
917
P_32_COPY(srcp->version, destp->version);
918
P_32_COPY(srcp->lorder, destp->lorder);
919
P_32_COPY(srcp->bsize, destp->bsize);
920
P_32_COPY(srcp->bshift, destp->bshift);
921
P_32_COPY(srcp->dsize, destp->dsize);
922
P_32_COPY(srcp->ssize, destp->ssize);
923
P_32_COPY(srcp->sshift, destp->sshift);
924
P_32_COPY(srcp->ovfl_point, destp->ovfl_point);
925
P_32_COPY(srcp->last_freed, destp->last_freed);
926
P_32_COPY(srcp->max_bucket, destp->max_bucket);
927
P_32_COPY(srcp->high_mask, destp->high_mask);
928
P_32_COPY(srcp->low_mask, destp->low_mask);
929
P_32_COPY(srcp->ffactor, destp->ffactor);
930
P_32_COPY(srcp->nkeys, destp->nkeys);
931
P_32_COPY(srcp->hdrpages, destp->hdrpages);
932
P_32_COPY(srcp->h_charkey, destp->h_charkey);
933
for (i = 0; i < NCACHED; i++) {
934
P_32_COPY(srcp->spares[i], destp->spares[i]);
935
P_16_COPY(srcp->bitmaps[i], destp->bitmaps[i]);
936
}
937
}
938
939
static void
940
swap_header(HTAB *hashp)
941
{
942
HASHHDR *hdrp;
943
int i;
944
945
hdrp = &hashp->hdr;
946
947
M_32_SWAP(hdrp->magic);
948
M_32_SWAP(hdrp->version);
949
M_32_SWAP(hdrp->lorder);
950
M_32_SWAP(hdrp->bsize);
951
M_32_SWAP(hdrp->bshift);
952
M_32_SWAP(hdrp->dsize);
953
M_32_SWAP(hdrp->ssize);
954
M_32_SWAP(hdrp->sshift);
955
M_32_SWAP(hdrp->ovfl_point);
956
M_32_SWAP(hdrp->last_freed);
957
M_32_SWAP(hdrp->max_bucket);
958
M_32_SWAP(hdrp->high_mask);
959
M_32_SWAP(hdrp->low_mask);
960
M_32_SWAP(hdrp->ffactor);
961
M_32_SWAP(hdrp->nkeys);
962
M_32_SWAP(hdrp->hdrpages);
963
M_32_SWAP(hdrp->h_charkey);
964
for (i = 0; i < NCACHED; i++) {
965
M_32_SWAP(hdrp->spares[i]);
966
M_16_SWAP(hdrp->bitmaps[i]);
967
}
968
}
969
#endif
970
971