OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [gnu-src/] [newlib-1.18.0/] [newlib/] [libc/] [search/] [hash.c] - Blame information for rev 307

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.