Initial import of the CDE 2.1.30 sources from the Open Group.
This commit is contained in:
581
cde/lib/tt/mini_isam/isvarrec.c
Normal file
581
cde/lib/tt/mini_isam/isvarrec.c
Normal file
@@ -0,0 +1,581 @@
|
||||
/*%% (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: isvarrec.c /main/3 1995/10/23 11:45:36 rswiston $ */
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)isvarrec.c 1.8 89/07/17 Copyr 1988 Sun Micro";
|
||||
#endif
|
||||
/*
|
||||
* Copyright (c) 1988 by Sun Microsystems, Inc.
|
||||
*/
|
||||
|
||||
/*
|
||||
* isvarrec.c
|
||||
*
|
||||
* Description:
|
||||
* Fixed length record access (VLRA) module.
|
||||
*/
|
||||
|
||||
#include "isam_impl.h"
|
||||
|
||||
/* Local functions */
|
||||
long _vl_getpos(); /* Get offset in .rec file */
|
||||
int _vl_deleted(); /* 0/1 returns 1 if record is deleted */
|
||||
static void remove_from_chain2(); /* used by _vlrec_wrrec() */
|
||||
long _istail_insert();
|
||||
static void _istail_delete();
|
||||
static _istail_read();
|
||||
|
||||
/*
|
||||
* _vlrec_write(fcb, record, recnum, reclen)
|
||||
*
|
||||
* Write a record.
|
||||
*
|
||||
* Input params:
|
||||
* FCB File Control Block
|
||||
* record record buffer
|
||||
* reclen record length (NOT USED)
|
||||
*
|
||||
* Output params:
|
||||
* recnum record number of the new record
|
||||
*
|
||||
* Returns 0 if record was written succesfully, or -1 if any error.
|
||||
*/
|
||||
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
_vlrec_write(fcb, record, recnum, reclen)
|
||||
register Fcb *fcb;
|
||||
char *record;
|
||||
Recno *recnum;
|
||||
int reclen;
|
||||
{
|
||||
Recno recnum2;
|
||||
long rec_position;
|
||||
long tailoff = VL_RECNOTAIL;
|
||||
char recnobuf [RECNOSIZE];
|
||||
char tailoffbuf[LONGSIZE];
|
||||
|
||||
/*
|
||||
* Reuse a deleted record if one exits.
|
||||
* Otherwise, extend .rec file by a record.
|
||||
*/
|
||||
if (fcb->freerecno != NULL_RECNO) {
|
||||
recnum2 = fcb->freerecno;
|
||||
|
||||
/*
|
||||
* Remove record from the chain of deleted records.
|
||||
*/
|
||||
rec_position = _vl_getpos(fcb, recnum2); /* Offset in .rec file */
|
||||
_cp_fromfile(fcb, fcb->datfd, recnobuf, rec_position + LONGSIZE, RECNOSIZE);
|
||||
fcb->freerecno = ldrecno(recnobuf);
|
||||
}
|
||||
else {
|
||||
recnum2 = ++(fcb->lastrecno);
|
||||
|
||||
/*
|
||||
* Extend .rec file size if necessary.
|
||||
*/
|
||||
while (_vl_getpos(fcb, recnum2 + 1) > fcb->datsize * ISPAGESIZE) {
|
||||
fcb->datsize = _extend_file(fcb, fcb->datfd, fcb->datsize);
|
||||
}
|
||||
rec_position = _vl_getpos(fcb, recnum2); /* Offset in .rec file */
|
||||
}
|
||||
|
||||
/*
|
||||
* Store variable part of record (the 'tail') in .var file.
|
||||
*/
|
||||
tailoff = _istail_insert(fcb, record + fcb->minreclen,
|
||||
reclen - fcb->minreclen);
|
||||
|
||||
/*
|
||||
* Copy record to the .rec file. Mark record as undeleted.
|
||||
*/
|
||||
stlong(tailoff, tailoffbuf);
|
||||
_cp_tofile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE);
|
||||
_cp_tofile(fcb, fcb->datfd, record, rec_position + LONGSIZE, fcb->minreclen);
|
||||
|
||||
*recnum = recnum2;
|
||||
|
||||
return (ISOK);
|
||||
}
|
||||
|
||||
/*
|
||||
* _vlrec_read(fcb, record, recnum, reclen)
|
||||
*
|
||||
* Read a record.
|
||||
*
|
||||
* Input params:
|
||||
* FCB File Control Block
|
||||
* recnum record number of the record
|
||||
* reclen filled with the record size for compatibilty with
|
||||
* variable length records
|
||||
*
|
||||
* Output params:
|
||||
* record record buffer is filled with data
|
||||
*
|
||||
* Returns 0 if record was read succesfully, or error code if any error.
|
||||
*/
|
||||
|
||||
int
|
||||
_vlrec_read(fcb, record, recnum, reclen)
|
||||
register Fcb *fcb;
|
||||
char *record;
|
||||
Recno recnum;
|
||||
int *reclen;
|
||||
{
|
||||
long rec_position;
|
||||
long tailoff;
|
||||
char tailoffbuf[LONGSIZE];
|
||||
|
||||
/*
|
||||
* Check that recnum is within the range of existing record numbers.
|
||||
*/
|
||||
if (recnum < 1 || recnum > fcb->lastrecno)
|
||||
return (EENDFILE);
|
||||
|
||||
rec_position = _vl_getpos(fcb, recnum); /* Offset in .rec file */
|
||||
|
||||
/*
|
||||
* Check that the record is not marked as deleted.
|
||||
*/
|
||||
_cp_fromfile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE);
|
||||
tailoff = ldlong(tailoffbuf);
|
||||
if (tailoff == VL_RECDELETED) {
|
||||
return (ENOREC);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy record from the .at file.
|
||||
*/
|
||||
_cp_fromfile(fcb, fcb->datfd, record, rec_position + LONGSIZE, fcb->minreclen);
|
||||
|
||||
*reclen = fcb->minreclen;
|
||||
|
||||
/*
|
||||
* Get the 'tail' of the record if any.
|
||||
*/
|
||||
*reclen += _istail_read(fcb, tailoff, record + fcb->minreclen);
|
||||
|
||||
if (*reclen > fcb->maxreclen)
|
||||
_isfatal_error("Corrupted file: too long variable length record");
|
||||
|
||||
return (ISOK);
|
||||
}
|
||||
|
||||
/*
|
||||
* pos = _vl_getpos(fcb, recnum)
|
||||
*
|
||||
* Calculate the position of record in .rec file.
|
||||
*/
|
||||
|
||||
long
|
||||
_vl_getpos(fcb, recnum)
|
||||
Fcb *fcb;
|
||||
Recno recnum;
|
||||
{
|
||||
return ((long)(ISCNTLSIZE + (fcb->minreclen + LONGSIZE) * (recnum -1)));
|
||||
}
|
||||
|
||||
/*
|
||||
* _vlrec_rewrite(fcb, record, recnum, reclen)
|
||||
*
|
||||
* Rewrite a record.
|
||||
*
|
||||
* Input params:
|
||||
* FCB File Control Block
|
||||
* recnum record number of the record
|
||||
* record new record
|
||||
* int reclen (NOT USED)
|
||||
*
|
||||
* Returns 0 if record was rewritten succesfully, or error code if any error.
|
||||
*/
|
||||
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
_vlrec_rewrite(fcb, record, recnum, reclen)
|
||||
register Fcb *fcb;
|
||||
char *record;
|
||||
Recno recnum;
|
||||
int reclen;
|
||||
{
|
||||
long rec_position;
|
||||
long tailoff;
|
||||
char tailoffbuf[LONGSIZE];
|
||||
|
||||
/*
|
||||
* Check that recnum is within the range of existing record numbers.
|
||||
*/
|
||||
if (recnum < 1 || recnum > fcb->lastrecno)
|
||||
return (EENDFILE);
|
||||
|
||||
rec_position = _vl_getpos(fcb, recnum); /* Offset in .rec file */
|
||||
|
||||
/*
|
||||
* Check that the record is not marked as deleted.
|
||||
*/
|
||||
_cp_fromfile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE);
|
||||
tailoff = ldlong(tailoffbuf);
|
||||
if (tailoff == VL_RECDELETED) {
|
||||
return (ENOREC);
|
||||
}
|
||||
|
||||
/*
|
||||
* Store variable part of record (the 'tail') in .var file.
|
||||
*/
|
||||
tailoff = _istail_modify(fcb, tailoff, record + fcb->minreclen,
|
||||
reclen - fcb->minreclen);
|
||||
|
||||
/*
|
||||
* Copy new record to the .rec file.
|
||||
*/
|
||||
stlong(tailoff, tailoffbuf);
|
||||
_cp_tofile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE);
|
||||
_cp_tofile(fcb, fcb->datfd, record, rec_position + LONGSIZE, fcb->minreclen);
|
||||
|
||||
return (ISOK);
|
||||
}
|
||||
|
||||
/*
|
||||
* _vlrec_delete;(fcb, recnum)
|
||||
*
|
||||
* Rewrite a record.
|
||||
*
|
||||
* Input params:
|
||||
* FCB File Control Block
|
||||
* recnum record number of the record
|
||||
*
|
||||
* Returns 0 if record was rewritten succesfully, or error code if any error.
|
||||
*/
|
||||
|
||||
int
|
||||
_vlrec_delete(fcb, recnum)
|
||||
register Fcb *fcb;
|
||||
Recno recnum;
|
||||
{
|
||||
long rec_position;
|
||||
long tailoff;
|
||||
char tailoffbuf[LONGSIZE];
|
||||
char recnobuf [RECNOSIZE];
|
||||
|
||||
/*
|
||||
* Check that recnum is within the range of existing record numbers.
|
||||
*/
|
||||
if (recnum < 1 || recnum > fcb->lastrecno)
|
||||
return (EENDFILE);
|
||||
|
||||
rec_position = _vl_getpos(fcb, recnum); /* Offset in .rec file */
|
||||
|
||||
/*
|
||||
* Check that the record is not marked as deleted.
|
||||
*/
|
||||
_cp_fromfile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE);
|
||||
tailoff = ldlong(tailoffbuf);
|
||||
if (tailoff == VL_RECDELETED) {
|
||||
return (ENOREC);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the delete flag to VL_RECDELETED.
|
||||
*/
|
||||
tailoff = VL_RECDELETED;
|
||||
stlong(tailoff, tailoffbuf);
|
||||
_cp_tofile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE);
|
||||
|
||||
/*
|
||||
* Insert record into chain of deleted records.
|
||||
*/
|
||||
strecno(fcb->freerecno, recnobuf);
|
||||
_cp_tofile(fcb, fcb->datfd, recnobuf, rec_position + LONGSIZE, RECNOSIZE);
|
||||
fcb->freerecno = recnum;
|
||||
|
||||
/*
|
||||
* Delete tail from .var file.
|
||||
*/
|
||||
|
||||
return (ISOK);
|
||||
}
|
||||
|
||||
/*
|
||||
* _vlrec_wrrec(fcb, record, recnum, reclen)
|
||||
*
|
||||
* Write a record by record number.
|
||||
*
|
||||
* Input params:
|
||||
* FCB File Control Block
|
||||
* recnum record number of the record
|
||||
* record record buffer
|
||||
* int reclen (NOT USED)
|
||||
*
|
||||
* Returns 0 if record was written succesfully, or error code if any error.
|
||||
*
|
||||
* Note that _vlrec_wrrec() commits updates and syncs the FCB to avoid
|
||||
* buffer pool overflow.
|
||||
*/
|
||||
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
_vlrec_wrrec(fcb, record, recnum, reclen)
|
||||
register Fcb *fcb;
|
||||
char *record;
|
||||
Recno recnum;
|
||||
int reclen;
|
||||
{
|
||||
long rec_position;
|
||||
long tailoff;
|
||||
char tailoffbuf[LONGSIZE];
|
||||
Recno recnum2;
|
||||
char recnumbuf [RECNOSIZE];
|
||||
|
||||
/*
|
||||
* Check that recnum is not negative.
|
||||
*/
|
||||
if (recnum < 1)
|
||||
return (EBADARG);
|
||||
|
||||
rec_position = _vl_getpos(fcb, recnum); /* Offset in .rec file */
|
||||
|
||||
if (recnum > fcb->lastrecno) {
|
||||
|
||||
/*
|
||||
* If the recnum is bigger than the highest record number in the .rec
|
||||
* file, extend the .rec file.
|
||||
*/
|
||||
while (_vl_getpos(fcb, recnum + 1) > fcb->datsize * ISPAGESIZE) {
|
||||
fcb->datsize = _extend_file(fcb, fcb->datfd, fcb->datsize);
|
||||
|
||||
/* Sync the updates to avoid buffer pool overflow. */
|
||||
_isdisk_commit();
|
||||
_isdisk_sync();
|
||||
(void)_isfcb_cntlpg_w2(fcb);
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark all records in the range <fcb->lastrecno+1, recnum> as
|
||||
* deleted.
|
||||
*/
|
||||
tailoff = VL_RECDELETED;
|
||||
stlong(tailoff, tailoffbuf);
|
||||
for (recnum2 = fcb->lastrecno + 1; recnum2 <= recnum; recnum2++) {
|
||||
_cp_tofile(fcb, fcb->datfd, tailoffbuf, _vl_getpos(fcb, recnum2), LONGSIZE);
|
||||
strecno(fcb->freerecno, recnumbuf);
|
||||
_cp_tofile(fcb, fcb->datfd, recnumbuf,
|
||||
_vl_getpos(fcb, recnum2) + LONGSIZE, RECNOSIZE);
|
||||
fcb->freerecno = recnum2;
|
||||
|
||||
/* Sync the updates to avoid buffer pool overflow. */
|
||||
_isdisk_commit();
|
||||
_isdisk_sync();
|
||||
fcb->lastrecno = recnum;
|
||||
(void)_isfcb_cntlpg_w2(fcb);
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that the disk structures are in a consistent state now,
|
||||
* the .rec was extended by a few records marked as 'deleted'.
|
||||
* This is important for subsequent rollbacks.
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* If recnum specifies a record that has existed, check whether it
|
||||
* has been deleted. _vlrec_wrrec() does not override existing record.
|
||||
*/
|
||||
_cp_fromfile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE);
|
||||
tailoff = ldlong(tailoffbuf);
|
||||
if (tailoff != VL_RECDELETED) {
|
||||
return (EDUPL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove the record from the chain of deleted records.
|
||||
*/
|
||||
remove_from_chain2(fcb, recnum);
|
||||
|
||||
/*
|
||||
* Store variable part of record (the 'tail') in .var file.
|
||||
*/
|
||||
tailoff = _istail_insert(fcb, record + fcb->minreclen, reclen - fcb->minreclen);
|
||||
|
||||
/*
|
||||
* Copy new record to the .rec file.
|
||||
*/
|
||||
stlong(tailoff, tailoffbuf);
|
||||
_cp_tofile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE);
|
||||
_cp_tofile(fcb, fcb->datfd, record, rec_position + LONGSIZE, fcb->minreclen);
|
||||
|
||||
return (ISOK);
|
||||
}
|
||||
|
||||
/*
|
||||
* remove_from_chain(fcb, recnum)
|
||||
*
|
||||
* Remove record from the chain of deleted records.
|
||||
*/
|
||||
|
||||
static void
|
||||
remove_from_chain2(fcb, recnum)
|
||||
Fcb *fcb;
|
||||
Recno recnum;
|
||||
{
|
||||
char recnobuf1 [RECNOSIZE] , recnobuf2 [RECNOSIZE];
|
||||
long pos1, pos2;
|
||||
Recno recnum2;
|
||||
|
||||
pos1 = _vl_getpos(fcb, recnum);
|
||||
_cp_fromfile(fcb, fcb->datfd, recnobuf1, pos1 + LONGSIZE, RECNOSIZE);
|
||||
|
||||
if (fcb->freerecno == recnum) {
|
||||
fcb->freerecno = ldrecno(recnobuf1);
|
||||
}
|
||||
else {
|
||||
recnum2 = fcb->freerecno;
|
||||
do {
|
||||
pos2 = _vl_getpos(fcb, recnum2);
|
||||
_cp_fromfile(fcb, fcb->datfd, recnobuf2, pos2 + LONGSIZE, RECNOSIZE);
|
||||
recnum2 = ldrecno(recnobuf2);
|
||||
} while (recnum2 != recnum && recnum2 != NULL_RECNO);
|
||||
|
||||
_cp_tofile(fcb, fcb->datfd, recnobuf1, pos2 + LONGSIZE, RECNOSIZE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The following are functions that manipulate the 'tails' of variable
|
||||
* records. The tail is the actual record with the fixed part removed
|
||||
* (fixed part starts at offset zero and its length is minimum record
|
||||
* length. The tails are stored in the .var file.
|
||||
*/
|
||||
|
||||
|
||||
/* Insert tail into .var file. Return offset in .var file */
|
||||
|
||||
long _istail_insert(fcb, tailp, taillen)
|
||||
Fcb *fcb;
|
||||
char *tailp;
|
||||
int taillen;
|
||||
{
|
||||
char frameheadbuf [2 * SHORTSIZE];
|
||||
int framelen;
|
||||
long offset;
|
||||
|
||||
/* printf ("_insert called, taillen %d\n", taillen); */
|
||||
|
||||
if (taillen == 0)
|
||||
return (VL_RECNOTAIL);
|
||||
|
||||
framelen = taillen + 2 * SHORTSIZE;
|
||||
|
||||
/*
|
||||
* Set up frame header.
|
||||
*/
|
||||
stshort((short)taillen, frameheadbuf + VR_FRAMELEN_OFF);
|
||||
stshort((short)taillen, frameheadbuf + VR_TAILLEN_OFF);
|
||||
|
||||
offset = fcb->varend;
|
||||
|
||||
/*
|
||||
* Extend .var file if that is necesary.
|
||||
*/
|
||||
while (offset + framelen > fcb->varsize * ISPAGESIZE)
|
||||
fcb->varsize = _extend_file(fcb, fcb->varfd, fcb->varsize);
|
||||
|
||||
/*
|
||||
* Copy frame head and tail to .var file.
|
||||
*/
|
||||
_cp_tofile(fcb, fcb->varfd, frameheadbuf, offset, 2 * SHORTSIZE);
|
||||
_cp_tofile(fcb, fcb->varfd, tailp, offset + 2 * SHORTSIZE, taillen);
|
||||
|
||||
fcb->varend += taillen + 2 * SHORTSIZE;
|
||||
|
||||
return (offset);
|
||||
}
|
||||
|
||||
/* Remove tail from .var file */
|
||||
|
||||
/* ARGSUSED */
|
||||
Static void _istail_delete(fcb, offset)
|
||||
Fcb *fcb;
|
||||
long offset;
|
||||
{
|
||||
/*
|
||||
* Don't do anything in NetISAM 1.0. The tails are lost, the space
|
||||
* will be re-used after next restructuring: "copy -c file" command
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
/* Read tail from .var file */
|
||||
|
||||
Static _istail_read(fcb, offset, buffer)
|
||||
Fcb *fcb;
|
||||
long offset;
|
||||
char *buffer;
|
||||
{
|
||||
char frameheadbuf [2 * SHORTSIZE];
|
||||
int taillen;
|
||||
|
||||
/* printf ("_read called, offset %d\n", offset); */
|
||||
|
||||
if (offset == VL_RECNOTAIL)
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* Read frame header.
|
||||
*/
|
||||
_cp_fromfile(fcb, fcb->varfd, frameheadbuf, offset, 2 * SHORTSIZE);
|
||||
taillen = ldshort(frameheadbuf + VR_TAILLEN_OFF);
|
||||
_cp_fromfile(fcb, fcb->varfd, buffer, offset + 2 * SHORTSIZE, taillen);
|
||||
|
||||
return (taillen);
|
||||
}
|
||||
|
||||
/* Rewrite tail. Returns -1 if the new tail is longer than the original frame */
|
||||
|
||||
int _istail_modify(fcb, offset, tailp, taillen)
|
||||
Fcb *fcb;
|
||||
long offset;
|
||||
int taillen;
|
||||
char *tailp;
|
||||
{
|
||||
char frameheadbuf [2 * SHORTSIZE];
|
||||
int framelen;
|
||||
|
||||
/*
|
||||
* Trivial case: no old frame, no new tail.
|
||||
*/
|
||||
if (offset == VL_RECNOTAIL && taillen == 0)
|
||||
return (offset);
|
||||
|
||||
if (offset != VL_RECNOTAIL) {
|
||||
/*
|
||||
* Read frame header.
|
||||
*/
|
||||
_cp_fromfile(fcb, fcb->varfd, frameheadbuf, offset, 2 * SHORTSIZE);
|
||||
framelen = ldshort(frameheadbuf + VR_FRAMELEN_OFF);
|
||||
}
|
||||
else
|
||||
framelen = 0;
|
||||
|
||||
if (taillen > framelen) {
|
||||
/*
|
||||
* Delete the old frame if the new tail does not fit.
|
||||
* Insert the new tail at the end of .var file.
|
||||
*/
|
||||
|
||||
_istail_delete(fcb, offset);
|
||||
return (_istail_insert(fcb, tailp, taillen));
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* The new tail fits in the existing frame.
|
||||
*/
|
||||
stshort((short)taillen, frameheadbuf + VR_TAILLEN_OFF);
|
||||
_cp_tofile(fcb, fcb->varfd, frameheadbuf, offset, 2 * SHORTSIZE);
|
||||
_cp_tofile(fcb, fcb->varfd, tailp, offset + 2 * SHORTSIZE, taillen);
|
||||
|
||||
return (offset);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user