123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653 |
- /*
- * CDE - Common Desktop Environment
- *
- * Copyright (c) 1993-2012, The Open Group. All rights reserved.
- *
- * These libraries and programs are free software; you can
- * redistribute them and/or modify them under the terms of the GNU
- * Lesser General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * These libraries and programs are distributed in the hope that
- * they will be useful, but WITHOUT ANY WARRANTY; without even the
- * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU Lesser General Public License for more
- * details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with these libraries and programs; if not, write
- * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
- * Floor, Boston, MA 02110-1301 USA
- */
- /*%% (c) Copyright 1993, 1994 Hewlett-Packard Company */
- /*%% (c) Copyright 1993, 1994 International Business Machines Corp. */
- /*%% (c) Copyright 1993, 1994 Sun Microsystems, Inc. */
- /*%% (c) Copyright 1993, 1994 Novell, Inc. */
- /*%% $XConsortium: isamaddindex.c /main/3 1995/10/23 11:34:12 rswiston $ */
- /*
- * Copyright (c) 1988 by Sun Microsystems, Inc.
- */
- /*
- * isaddindex.c
- *
- * Description:
- * Add secondary index
- *
- *
- */
- #include "isam_impl.h"
- #include <sys/types.h>
- #include <sys/stat.h>
- extern int _iskeycmp();
- static void _readallrecords(), _attach_dups_serial();
- static Blkno _buildbtree();
- static int _duplicate_exist();
- static void checkavailfd(void);
- /*
- * _amaddindex(isfhandle, keydesc, errcode)
- *
- * _amaddindex() build a secondary index
- *
- * Input params:
- * isfhandle Handle of ISAM file
- * keydesc Key descriptor
- *
- * Output params:
- * errcode error status of the operation
- *
- */
- /*ARGSUSED*/
- int
- _amaddindex(Bytearray *isfhandle, struct keydesc *keydesc, struct errcode *errcode)
- {
- Fcb *fcb = NULL;
- Keydesc2 keydesc2;
- int err;
- _isam_entryhook();
-
- /*
- * Check if 1 UNIX file decriptor is available.
- */
- checkavailfd();
- /*
- * Get FCB corresponding to the isfhandle handle.
- */
- if ((fcb = _openfcb(isfhandle, errcode)) == NULL) {
- _isam_exithook();
- return (ISERROR);
- }
- /*
- * Check that the limit on the number of keys is not exceeded.
- */
- if (fcb->nkeys >= MAXNKEYS) {
- _amseterrcode(errcode, ETOOMANY);
- goto ERROR;
- }
- /*
- * Update information in FCB from CNTL page on the disk
- */
- (void)_isfcb_cntlpg_r(fcb);
- /*
- * Check key descriptor for validity.
- */
- if (_validate_keydesc(keydesc, fcb->minreclen) != ISOK) {
- _amseterrcode(errcode, EBADKEY);
- goto ERROR;
- }
- /*
- * Convert key descriptor to internal form.
- */
- _iskey_xtoi (&keydesc2, keydesc);
- /* Check if key already exists. */
- if (_isfcb_findkey(fcb ,&keydesc2) != (Keydesc2 *) 0) {
- _amseterrcode(errcode, EKEXISTS);
- goto ERROR;
- }
- /*
- * Open (or even create) .ind file if that is not open (created) yet.
- */
- if (_open2_indfile(fcb) != ISOK) {
- _amseterrcode(errcode, EACCES);
- goto ERROR;
- }
-
- /*
- * Create index structure.
- */
- if ((err = _create_index(fcb ,&keydesc2)) != ISOK) {
- _amseterrcode(errcode, err);
- goto ERROR;
- }
- /*
- * Add key descriptor to FCB.
- */
- if (_isfcb_altkeyadd(fcb, &keydesc2) == ISERROR) {
- _amseterrcode(errcode, ETOOMANY);
- goto ERROR;
- }
- _amseterrcode(errcode, ISOK);
- _issignals_mask();
- _isdisk_commit();
- _isdisk_sync();
- _isdisk_inval();
- /*
- * Update CNTL Page from the FCB.
- */
- (void)_isfcb_cntlpg_w(fcb);
- _issignals_unmask();
- _isam_exithook();
- return (ISOK);
- ERROR:
- _isdisk_rollback();
- _isdisk_inval();
- /*
- * Restore FCB from CNTL page.
- */
- if (fcb) (void)_isfcb_cntlpg_r(fcb);
- _isam_exithook();
- return (ISERROR);
- }
- /*
- * _amaddprimary(isfhandle, keydesc, errcode)
- *
- * _amaddprimary() build primary key
- *
- * Input params:
- * isfhandle Handle of ISAM file
- * keydesc Key descriptor
- *
- * Output params:
- * errcode error status of the operation
- *
- */
- /*ARGSUSED*/
- int
- _amaddprimary(Bytearray *isfhandle, struct keydesc *keydesc, struct errcode *errcode)
- {
- Fcb *fcb = NULL;
- Keydesc2 keydesc2;
- int err;
- _isam_entryhook();
-
- /*
- * Check if 1 UNIX file decriptor is available.
- */
- checkavailfd();
- /*
- * Get FCB corresponding to the isfhandle handle.
- */
- if ((fcb = _openfcb(isfhandle, errcode)) == NULL) {
- _isam_exithook();
- return (ISERROR);
- }
- /*
- * Check that the limit on the numbrer of keys is not exceeded.
- */
- if (fcb->nkeys >= MAXNKEYS) {
- _amseterrcode(errcode, ETOOMANY);
- goto ERROR;
- }
- /*
- * Update information in FCB from CNTL page on the disk
- */
- (void)_isfcb_cntlpg_r(fcb);
- /*
- * Check key descriptor for validity.
- */
- if (_validate_keydesc(keydesc, fcb->minreclen) != ISOK) {
- _amseterrcode(errcode, EBADKEY);
- goto ERROR;
- }
- /*
- * Convert key descriptor to internal form.
- */
- _iskey_xtoi (&keydesc2, keydesc);
- /* Check if key already exists. */
- if (_isfcb_findkey(fcb ,&keydesc2) != (Keydesc2 *) 0) {
- _amseterrcode(errcode, EKEXISTS);
- goto ERROR;
- }
- /*
- * Check that primary key does not already exist.
- */
- if (!FCB_NOPRIMARY_KEY(fcb)) {
- _amseterrcode(errcode, EKEXISTS);
- goto ERROR;
- }
- /*
- * Open (or even create) .ind file if that is not open (created) yet.
- */
- if (_open2_indfile(fcb) != ISOK) {
- _amseterrcode(errcode, EACCES);
- goto ERROR;
- }
-
- /*
- * Create index structure.
- */
- if ((err = _create_index(fcb ,&keydesc2)) != ISOK) {
- _amseterrcode(errcode, err);
- goto ERROR;
- }
- /*
- * Add key descriptor to FCB.
- */
- if (_isfcb_primkeyadd(fcb, &keydesc2) == ISERROR) {
- _amseterrcode(errcode, ETOOMANY);
- goto ERROR;
- }
- _amseterrcode(errcode, ISOK);
- _issignals_mask();
- _isdisk_commit();
- _isdisk_sync();
- _isdisk_inval();
- /*
- * Update CNTL Page from the FCB.
- */
- (void)_isfcb_cntlpg_w(fcb);
- _issignals_unmask();
- _isam_exithook();
- return (ISOK);
- ERROR:
- _isdisk_rollback();
- _isdisk_inval();
- /*
- * Restore FCB from CNTL page.
- */
- if (fcb) (void)_isfcb_cntlpg_r(fcb);
- _isam_exithook();
- return (ISERROR);
- }
- /*
- * _create_index()
- *
- * Read data file, extract key from record, sort keys, create index.
- * Check unique constraint, create duplicate serial numbers.
- */
- int _create_index(Fcb *fcb, Keydesc2 *pkeydesc2)
- {
- Issort *srt;
- int keylength = pkeydesc2->k2_len;
- /*
- * Set comparison function for sorting.
- *
- * nparts + 1 is used to compare keys that allow duplicates.
- * The (nparts + 1) comparison will never be reached on ISNODUPS key.
- */
- _iskeycmp_set(pkeydesc2, pkeydesc2->k2_nparts+1);
- /*
- * Handle empty file as a special case, to avoid nasty behavior
- * in buildbtree() arithmetics.
- */
- if (fcb->nrecords == 0L) {
- pkeydesc2->k2_rootnode = _buildbtree(fcb, pkeydesc2, (Issort *) NULL);
- return (ISOK);
- }
-
- /*
- * Create a sorter for this key descriptor.
- */
- srt = _issort_create(keylength, (int)fcb->nrecords, _iskeycmp);
- /*
- * Read sequentially all records, extract keys, and
- * insert the keys into the sorter.
- */
- _readallrecords(fcb, srt, pkeydesc2);
- _issort_sort(srt); /* Sort the keys */
- /*
- * Check for potential duplicates if the index is ISNODUPS.
- */
- if (!ALLOWS_DUPS2(pkeydesc2)) {
- if (_duplicate_exist(srt, keylength)) {
- _issort_destroy(srt);
- return (EDUPL);
- }
- }
- /*
- * Attach duplicate serial numbers to the keys that are ISDUPS.
- */
- if (ALLOWS_DUPS2(pkeydesc2)) {
- _attach_dups_serial(srt, pkeydesc2);
- }
- /*
- * Allocate and build the B-tree
- */
- pkeydesc2->k2_rootnode = _buildbtree(fcb, pkeydesc2, srt);
- _issort_destroy(srt); /* Destroy sorter */
- return (ISOK);
- }
- /*
- * _readallrecords()
- *
- * REad all records, extract keys, and insert them into sorter.
- */
- Static void
- _readallrecords(Fcb *fcb, Issort *srt, Keydesc2 *pkeydesc2)
- {
- char record [ISMAXRECLEN];
- char keybuf [MAXKEYSIZE];
- Recno recnum;
- int reclen = 0;
- int (*rec_read)() = (fcb->varflag?_vlrec_read:_flrec_read);
-
- for (recnum = 1; recnum <= fcb->lastrecno; recnum++) {
-
- if (rec_read(fcb, record, recnum, &reclen) != ISOK)
- continue; /* Skip deleted record */
-
- /*
- * Zero out the entire key buffer to allow for using
- * memcmp() as comparison function to compare whole keys.
- */
- memset(keybuf, 0, pkeydesc2->k2_len);
-
- /*
- * Extract key parts from record buffer.
- */
- _iskey_extract(pkeydesc2, record, keybuf);
-
- /*
- * Add recno to key
- */
- strecno(recnum, keybuf + KEY_RECNO_OFF);
-
- _issort_insert(srt, keybuf); /* Insert key into sorter */
-
-
- }
- }
- /*
- * _attach_dups_serial()
- *
- * Attach serial numbers to duplicate keys
- */
- Static void
- _attach_dups_serial(Issort *srt, Keydesc2 *pkeydesc2)
- {
- int netkeylength = pkeydesc2->k2_len - RECNOSIZE - DUPIDSIZE;
- char *curkey;
- char *lastkey = NULL;
- int dup_serial = 1;
- _issort_rewind(srt);
- while ((curkey = _issort_read(srt))) {
- if (lastkey && memcmp(lastkey + RECNOSIZE + DUPIDSIZE,
- curkey + RECNOSIZE + DUPIDSIZE,
- netkeylength) == 0)
- dup_serial++;
- else
- dup_serial = 1;
- /*
- * Store serial number in the key.
- */
- stdupser(dup_serial, curkey + KEY_DUPS_OFF);
-
- lastkey = curkey;
- }
- }
- /*
- * _buildbtree()
- *
- * Create B-tree.
- */
- Static Blkno
- _buildbtree(Fcb *fcb, Keydesc2 *pkeydesc2, Issort *srt)
- {
- Bufhdr *_allockpage();
- int depth;
- int nrecords = fcb->nrecords;
- int keyspernode[ISMAXBTRLEVEL];
- int one_more[ISMAXBTRLEVEL];
- char *nodebuf[ISMAXBTRLEVEL];
- Bufhdr *nodebufhd[ISMAXBTRLEVEL];
- Blkno pageblkno[ISMAXBTRLEVEL];
- int curindex[ISMAXBTRLEVEL];
- char *keyp;
- int keylength = pkeydesc2->k2_len;
- int leafcapac = getkeysperleaf(keylength);
- int nleafcapac = getkeyspernode(keylength);
- int perleaf;
- int blocks_in_this_level, blocks_in_prev_level;
- int slack = ISLEAFSLACK;
- int i;
-
- /*
- * Handle an empty B-tree as a special case.
- */
- if (fcb->nrecords == 0) {
- (void)_allockpage(fcb, leafcapac, 0, pageblkno + 0);
- return (pageblkno[0]);
- }
- /*
- * COMPRESS changes the fill factor to 100%
- */
- if ((pkeydesc2->k2_flags & COMPRESS) == COMPRESS)
- slack = 0;
- /*
- * Figure out fill factors for each level.
- */
- perleaf = ((double)leafcapac * (100.0 - (double) slack)) / 100.0;
- /*
- * Make it more robust.
- */
- if (perleaf >= leafcapac)
- perleaf = leafcapac;
- if (perleaf < leafcapac/2 + 1)
- perleaf = leafcapac/2 + 1;
- /*
- * Iterativelly determince values in keyspernode[] and one_mode[]
- */
- blocks_in_this_level = nrecords / perleaf;
- if (blocks_in_this_level * leafcapac < nrecords)
- blocks_in_this_level++;
- keyspernode[0] = nrecords / blocks_in_this_level;
- one_more[0] = nrecords % blocks_in_this_level;
-
- for (depth = 1; blocks_in_this_level > 1; depth++) {
- blocks_in_prev_level = blocks_in_this_level;
- blocks_in_this_level = (blocks_in_prev_level-1) / nleafcapac + 1;
- keyspernode[depth] = blocks_in_prev_level / blocks_in_this_level;
- one_more[depth] = blocks_in_prev_level % blocks_in_this_level;
- }
- if (depth >= ISMAXBTRLEVEL)
- _isfatal_error("Too many levels in B-tree");
- /*
- * Make sure that we start reading keys from the beginning.
- */
- _issort_rewind(srt);
- /*
- * Boot the Main loop.
- */
- for (i = 0; i < depth ; i++) {
- curindex[i] = ISPAGESIZE; /* Any big number will do */
- one_more[i]++;
- nodebuf[i] = NULL;
- nodebufhd[i] = NULL;
- }
- /*
- * Main loop.
- */
- while ((keyp = _issort_read(srt)) != (char *) NULL) {
- if (curindex[0] >= keyspernode[0] + (one_more[0] > 0)) {
- /*
- * Commit all changed buffers here to avoid buffer pool overflow.
- */
- if (nodebufhd[0]) {
- _isdisk_commit1(nodebufhd[0]);
- _isdisk_sync();
- }
- /* Allocate new leaf. */
- nodebufhd[0] = _allockpage(fcb, leafcapac, 0, pageblkno+0);
- nodebuf[0] = nodebufhd[0]->isb_buffer;
- one_more[0]--;
- curindex[0] = 0;
- }
- /* Copy key into the page. */
- memcpy( nodebuf[0] + BT_KEYS_OFF + keylength * curindex[0],keyp,
- keylength);
- stshort((short) curindex[0] + 1, nodebuf[0] + BT_NKEYS_OFF);
- if (curindex[0]++ == 0) { /* Store first key in */
- /* higher levels */
-
- for (i = 1;i < depth; i++) {
- if (curindex[i] >= keyspernode[i] + (one_more[i] > 0)) {
- /* Unfix buffer. */
- if (nodebufhd[i])
- _isdisk_commit1(nodebufhd[i]);
- nodebufhd[i] = _allockpage(fcb, nleafcapac, i, pageblkno+i);
- nodebuf[i] = nodebufhd[i]->isb_buffer;
- one_more[i]--;
- curindex[i] = 0;
- }
-
- /* Copy key into page. */
- memcpy( nodebuf[i] + BT_KEYS_OFF + keylength * curindex[i],keyp,
- keylength);
- /* Store pointer to level below. */
- stblkno(pageblkno[i-1], nodebuf[i] + ISPAGESIZE -
- (curindex[i]+1) * BLKNOSIZE);
- stshort((short) curindex[i] + 1, nodebuf[i] + BT_NKEYS_OFF);
- if (curindex[i]++ > 0) {
- break;
- }
- }
- }
-
- }
- return (pageblkno [depth - 1]); /* Return blkno of B-tree root */
- }
- /*
- * _duplicate_exist()
- *
- * Return 1 if there are duplicates in the sorted key object.
- */
- Static int _duplicate_exist(Issort *srt, int keylength)
- {
- char *curkey;
- char *lastkey = (char *) 0;
- int netkeylength = keylength - RECNOSIZE;
- _issort_rewind(srt);
- while ((curkey = _issort_read(srt))) {
- if (lastkey && memcmp(lastkey + RECNOSIZE, curkey + RECNOSIZE,
- netkeylength) == 0)
- return 1; /* Duplicate key found */
- lastkey = curkey;
- }
- return 0; /* No duplicates found */
- }
- static void
- checkavailfd(void)
- {
- Fcb *fcb;
- Bytearray *isfhandle2;
- /*
- * Check that there are UNIX file descriptors available.
- */
- while (_watchfd_check() < 1) {
- /*
- * Find victim (LRU FCB) and close it.
- */
- if((isfhandle2 = _mngfcb_victim()) == NULL)
- _isfatal_error ("_openfcb() cannot find LRU victim");
- fcb = _mngfcb_find(isfhandle2);
- (void) _watchfd_decr(_isfcb_nfds(fcb));
- _isfcb_close(fcb);
- _mngfcb_delete(isfhandle2);
- }
- }
|