1 /*%% (c) Copyright 1993, 1994 Hewlett-Packard Company */
2 /*%% (c) Copyright 1993, 1994 International Business Machines Corp. */
3 /*%% (c) Copyright 1993, 1994 Sun Microsystems, Inc. */
4 /*%% (c) Copyright 1993, 1994 Novell, Inc. */
5 /*%% $XConsortium: isvarrec.c /main/3 1995/10/23 11:45:36 rswiston $ */
7 static char sccsid[] = "@(#)isvarrec.c 1.8 89/07/17 Copyr 1988 Sun Micro";
10 * Copyright (c) 1988 by Sun Microsystems, Inc.
17 * Fixed length record access (VLRA) module.
20 #include "isam_impl.h"
23 long _vl_getpos(); /* Get offset in .rec file */
24 int _vl_deleted(); /* 0/1 returns 1 if record is deleted */
25 static void remove_from_chain2(); /* used by _vlrec_wrrec() */
26 long _istail_insert();
27 static void _istail_delete();
28 static _istail_read();
31 * _vlrec_write(fcb, record, recnum, reclen)
36 * FCB File Control Block
37 * record record buffer
38 * reclen record length (NOT USED)
41 * recnum record number of the new record
43 * Returns 0 if record was written succesfully, or -1 if any error.
48 _vlrec_write(fcb, record, recnum, reclen)
56 long tailoff = VL_RECNOTAIL;
57 char recnobuf [RECNOSIZE];
58 char tailoffbuf[LONGSIZE];
61 * Reuse a deleted record if one exits.
62 * Otherwise, extend .rec file by a record.
64 if (fcb->freerecno != NULL_RECNO) {
65 recnum2 = fcb->freerecno;
68 * Remove record from the chain of deleted records.
70 rec_position = _vl_getpos(fcb, recnum2); /* Offset in .rec file */
71 _cp_fromfile(fcb, fcb->datfd, recnobuf, rec_position + LONGSIZE, RECNOSIZE);
72 fcb->freerecno = ldrecno(recnobuf);
75 recnum2 = ++(fcb->lastrecno);
78 * Extend .rec file size if necessary.
80 while (_vl_getpos(fcb, recnum2 + 1) > fcb->datsize * ISPAGESIZE) {
81 fcb->datsize = _extend_file(fcb, fcb->datfd, fcb->datsize);
83 rec_position = _vl_getpos(fcb, recnum2); /* Offset in .rec file */
87 * Store variable part of record (the 'tail') in .var file.
89 tailoff = _istail_insert(fcb, record + fcb->minreclen,
90 reclen - fcb->minreclen);
93 * Copy record to the .rec file. Mark record as undeleted.
95 stlong(tailoff, tailoffbuf);
96 _cp_tofile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE);
97 _cp_tofile(fcb, fcb->datfd, record, rec_position + LONGSIZE, fcb->minreclen);
105 * _vlrec_read(fcb, record, recnum, reclen)
110 * FCB File Control Block
111 * recnum record number of the record
112 * reclen filled with the record size for compatibilty with
113 * variable length records
116 * record record buffer is filled with data
118 * Returns 0 if record was read succesfully, or error code if any error.
122 _vlrec_read(fcb, record, recnum, reclen)
130 char tailoffbuf[LONGSIZE];
133 * Check that recnum is within the range of existing record numbers.
135 if (recnum < 1 || recnum > fcb->lastrecno)
138 rec_position = _vl_getpos(fcb, recnum); /* Offset in .rec file */
141 * Check that the record is not marked as deleted.
143 _cp_fromfile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE);
144 tailoff = ldlong(tailoffbuf);
145 if (tailoff == VL_RECDELETED) {
150 * Copy record from the .at file.
152 _cp_fromfile(fcb, fcb->datfd, record, rec_position + LONGSIZE, fcb->minreclen);
154 *reclen = fcb->minreclen;
157 * Get the 'tail' of the record if any.
159 *reclen += _istail_read(fcb, tailoff, record + fcb->minreclen);
161 if (*reclen > fcb->maxreclen)
162 _isfatal_error("Corrupted file: too long variable length record");
168 * pos = _vl_getpos(fcb, recnum)
170 * Calculate the position of record in .rec file.
174 _vl_getpos(fcb, recnum)
178 return ((long)(ISCNTLSIZE + (fcb->minreclen + LONGSIZE) * (recnum -1)));
182 * _vlrec_rewrite(fcb, record, recnum, reclen)
187 * FCB File Control Block
188 * recnum record number of the record
190 * int reclen (NOT USED)
192 * Returns 0 if record was rewritten succesfully, or error code if any error.
197 _vlrec_rewrite(fcb, record, recnum, reclen)
205 char tailoffbuf[LONGSIZE];
208 * Check that recnum is within the range of existing record numbers.
210 if (recnum < 1 || recnum > fcb->lastrecno)
213 rec_position = _vl_getpos(fcb, recnum); /* Offset in .rec file */
216 * Check that the record is not marked as deleted.
218 _cp_fromfile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE);
219 tailoff = ldlong(tailoffbuf);
220 if (tailoff == VL_RECDELETED) {
225 * Store variable part of record (the 'tail') in .var file.
227 tailoff = _istail_modify(fcb, tailoff, record + fcb->minreclen,
228 reclen - fcb->minreclen);
231 * Copy new record to the .rec file.
233 stlong(tailoff, tailoffbuf);
234 _cp_tofile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE);
235 _cp_tofile(fcb, fcb->datfd, record, rec_position + LONGSIZE, fcb->minreclen);
241 * _vlrec_delete;(fcb, recnum)
246 * FCB File Control Block
247 * recnum record number of the record
249 * Returns 0 if record was rewritten succesfully, or error code if any error.
253 _vlrec_delete(fcb, recnum)
259 char tailoffbuf[LONGSIZE];
260 char recnobuf [RECNOSIZE];
263 * Check that recnum is within the range of existing record numbers.
265 if (recnum < 1 || recnum > fcb->lastrecno)
268 rec_position = _vl_getpos(fcb, recnum); /* Offset in .rec file */
271 * Check that the record is not marked as deleted.
273 _cp_fromfile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE);
274 tailoff = ldlong(tailoffbuf);
275 if (tailoff == VL_RECDELETED) {
280 * Set the delete flag to VL_RECDELETED.
282 tailoff = VL_RECDELETED;
283 stlong(tailoff, tailoffbuf);
284 _cp_tofile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE);
287 * Insert record into chain of deleted records.
289 strecno(fcb->freerecno, recnobuf);
290 _cp_tofile(fcb, fcb->datfd, recnobuf, rec_position + LONGSIZE, RECNOSIZE);
291 fcb->freerecno = recnum;
294 * Delete tail from .var file.
301 * _vlrec_wrrec(fcb, record, recnum, reclen)
303 * Write a record by record number.
306 * FCB File Control Block
307 * recnum record number of the record
308 * record record buffer
309 * int reclen (NOT USED)
311 * Returns 0 if record was written succesfully, or error code if any error.
313 * Note that _vlrec_wrrec() commits updates and syncs the FCB to avoid
314 * buffer pool overflow.
319 _vlrec_wrrec(fcb, record, recnum, reclen)
327 char tailoffbuf[LONGSIZE];
329 char recnumbuf [RECNOSIZE];
332 * Check that recnum is not negative.
337 rec_position = _vl_getpos(fcb, recnum); /* Offset in .rec file */
339 if (recnum > fcb->lastrecno) {
342 * If the recnum is bigger than the highest record number in the .rec
343 * file, extend the .rec file.
345 while (_vl_getpos(fcb, recnum + 1) > fcb->datsize * ISPAGESIZE) {
346 fcb->datsize = _extend_file(fcb, fcb->datfd, fcb->datsize);
348 /* Sync the updates to avoid buffer pool overflow. */
351 (void)_isfcb_cntlpg_w2(fcb);
355 * Mark all records in the range <fcb->lastrecno+1, recnum> as
358 tailoff = VL_RECDELETED;
359 stlong(tailoff, tailoffbuf);
360 for (recnum2 = fcb->lastrecno + 1; recnum2 <= recnum; recnum2++) {
361 _cp_tofile(fcb, fcb->datfd, tailoffbuf, _vl_getpos(fcb, recnum2), LONGSIZE);
362 strecno(fcb->freerecno, recnumbuf);
363 _cp_tofile(fcb, fcb->datfd, recnumbuf,
364 _vl_getpos(fcb, recnum2) + LONGSIZE, RECNOSIZE);
365 fcb->freerecno = recnum2;
367 /* Sync the updates to avoid buffer pool overflow. */
370 fcb->lastrecno = recnum;
371 (void)_isfcb_cntlpg_w2(fcb);
375 * Note that the disk structures are in a consistent state now,
376 * the .rec was extended by a few records marked as 'deleted'.
377 * This is important for subsequent rollbacks.
382 * If recnum specifies a record that has existed, check whether it
383 * has been deleted. _vlrec_wrrec() does not override existing record.
385 _cp_fromfile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE);
386 tailoff = ldlong(tailoffbuf);
387 if (tailoff != VL_RECDELETED) {
392 * Remove the record from the chain of deleted records.
394 remove_from_chain2(fcb, recnum);
397 * Store variable part of record (the 'tail') in .var file.
399 tailoff = _istail_insert(fcb, record + fcb->minreclen, reclen - fcb->minreclen);
402 * Copy new record to the .rec file.
404 stlong(tailoff, tailoffbuf);
405 _cp_tofile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE);
406 _cp_tofile(fcb, fcb->datfd, record, rec_position + LONGSIZE, fcb->minreclen);
412 * remove_from_chain(fcb, recnum)
414 * Remove record from the chain of deleted records.
418 remove_from_chain2(fcb, recnum)
422 char recnobuf1 [RECNOSIZE] , recnobuf2 [RECNOSIZE];
426 pos1 = _vl_getpos(fcb, recnum);
427 _cp_fromfile(fcb, fcb->datfd, recnobuf1, pos1 + LONGSIZE, RECNOSIZE);
429 if (fcb->freerecno == recnum) {
430 fcb->freerecno = ldrecno(recnobuf1);
433 recnum2 = fcb->freerecno;
435 pos2 = _vl_getpos(fcb, recnum2);
436 _cp_fromfile(fcb, fcb->datfd, recnobuf2, pos2 + LONGSIZE, RECNOSIZE);
437 recnum2 = ldrecno(recnobuf2);
438 } while (recnum2 != recnum && recnum2 != NULL_RECNO);
440 _cp_tofile(fcb, fcb->datfd, recnobuf1, pos2 + LONGSIZE, RECNOSIZE);
446 * The following are functions that manipulate the 'tails' of variable
447 * records. The tail is the actual record with the fixed part removed
448 * (fixed part starts at offset zero and its length is minimum record
449 * length. The tails are stored in the .var file.
453 /* Insert tail into .var file. Return offset in .var file */
455 long _istail_insert(fcb, tailp, taillen)
460 char frameheadbuf [2 * SHORTSIZE];
464 /* printf ("_insert called, taillen %d\n", taillen); */
467 return (VL_RECNOTAIL);
469 framelen = taillen + 2 * SHORTSIZE;
472 * Set up frame header.
474 stshort((short)taillen, frameheadbuf + VR_FRAMELEN_OFF);
475 stshort((short)taillen, frameheadbuf + VR_TAILLEN_OFF);
477 offset = fcb->varend;
480 * Extend .var file if that is necesary.
482 while (offset + framelen > fcb->varsize * ISPAGESIZE)
483 fcb->varsize = _extend_file(fcb, fcb->varfd, fcb->varsize);
486 * Copy frame head and tail to .var file.
488 _cp_tofile(fcb, fcb->varfd, frameheadbuf, offset, 2 * SHORTSIZE);
489 _cp_tofile(fcb, fcb->varfd, tailp, offset + 2 * SHORTSIZE, taillen);
491 fcb->varend += taillen + 2 * SHORTSIZE;
496 /* Remove tail from .var file */
499 Static void _istail_delete(fcb, offset)
504 * Don't do anything in NetISAM 1.0. The tails are lost, the space
505 * will be re-used after next restructuring: "copy -c file" command
510 /* Read tail from .var file */
512 Static _istail_read(fcb, offset, buffer)
517 char frameheadbuf [2 * SHORTSIZE];
520 /* printf ("_read called, offset %d\n", offset); */
522 if (offset == VL_RECNOTAIL)
528 _cp_fromfile(fcb, fcb->varfd, frameheadbuf, offset, 2 * SHORTSIZE);
529 taillen = ldshort(frameheadbuf + VR_TAILLEN_OFF);
530 _cp_fromfile(fcb, fcb->varfd, buffer, offset + 2 * SHORTSIZE, taillen);
535 /* Rewrite tail. Returns -1 if the new tail is longer than the original frame */
537 int _istail_modify(fcb, offset, tailp, taillen)
543 char frameheadbuf [2 * SHORTSIZE];
547 * Trivial case: no old frame, no new tail.
549 if (offset == VL_RECNOTAIL && taillen == 0)
552 if (offset != VL_RECNOTAIL) {
556 _cp_fromfile(fcb, fcb->varfd, frameheadbuf, offset, 2 * SHORTSIZE);
557 framelen = ldshort(frameheadbuf + VR_FRAMELEN_OFF);
562 if (taillen > framelen) {
564 * Delete the old frame if the new tail does not fit.
565 * Insert the new tail at the end of .var file.
568 _istail_delete(fcb, offset);
569 return (_istail_insert(fcb, tailp, taillen));
573 * The new tail fits in the existing frame.
575 stshort((short)taillen, frameheadbuf + VR_TAILLEN_OFF);
576 _cp_tofile(fcb, fcb->varfd, frameheadbuf, offset, 2 * SHORTSIZE);
577 _cp_tofile(fcb, fcb->varfd, tailp, offset + 2 * SHORTSIZE, taillen);