📄 ridxio.c
字号:
err = fmpCheckDiskError(ri->ofcb, fsinfo); if ( err < E_OK ) { goto err_ret; } blktp = 0; while ( total < end ) { /* Obtain the location and size of the data block from the record index. */ err = fmpGetDataBlkAdr(ri, lblk); if ( err < E_OK ) { goto err_ret; } blktp = total; total += (UW)(lblk->cnt * fsinfo->sblk); } return (WER)(end - blktp);err_ret: ri->err = err; DEBUG_PRINT(("fmpFindLastDataBlkAdr err = %d\n", err)); return err;}/* ------------------------------------------------------------------------ *//* * Down the range between top and end by one level. * The indirect index at the location of end is abandoned. * The indirect index at the location of top is cleared to 0. * Return the record count included in the moved indirect index. */LOCAL W shiftDownIIdx( DfIndirectIndex *base, W top, W end, FsInfo *fsinfo ){ W i; W n = 0; for ( i = end - 1; i >= top; --i ) { base[i + 1] = base[i]; n += (W)fmpConvEndianW(base[i].nrec, fsinfo); } memset(&base[top], 0, (size_t)sizeof(DfIndirectIndex)); return n;}/* * Up the range between top and end by one level. * The indirect index at the location of top is abandoned. * The indirect index at the location of end is cleared to 0. * Return the record count included in the moved indirect index. */LOCAL W shiftUpIIdx( DfIndirectIndex *base, W top, W end, FsInfo *fsinfo ){ W i; W n = 0; for ( i = top + 1; i <= end; ++i ) { base[i - 1] = base[i]; n += (W)fmpConvEndianW(base[i].nrec, fsinfo); } memset(&base[end], 0, (size_t)sizeof(DfIndirectIndex)); return n;}/* * Down the range between top and end by one level. * The record index at the location of end is abandoned. * The record index at the location of top is cleared to 0. * Return the numbers of normal indexes and link indexes * in the moved record index. */LOCAL W shiftDownRIdx( DfRecordIndex *base, W top, W end ){ W i; W n = 0; for ( i = end - 1; i >= top; --i ) { base[i + 1] = base[i]; if ( (base[i].type[0] == 0) && (base[i].type[1] != 0) ) { n++; } } memset(&base[top], 0, (size_t)sizeof(DfRecordIndex)); return n;}/* * Up the range between top and end by one level. * The record index at the location of top is abandoned. * The record index at the location of end is cleared to 0. * Return the numbers of normal indexes and link indexes * in the moved record index. */LOCAL W shiftUpRIdx( DfRecordIndex *base, W top, W end ){ W i; W n = 0; for ( i = top + 1; i <= end; ++i ) { base[i - 1] = base[i]; if ( (base[i].type[0] == 0) && (base[i].type[1] != 0) ) { n++; } } memset(&base[end], 0, (size_t)sizeof(DfRecordIndex)); return n;}/* * Obtain a free entry from the indirect index block. * Find a free entry in the indirect index block of index level lv that includes * the indirect index at the location of *dadr, and locate it just after *dadr. * If needed, move the entry in the indirect index block to reserve a free entry. * If the location of *dadr is moved, *dadr is updated to indicate the location * after the movement. * Return the record count included in the moved entry to *nrec. * When the entry before *dadr is moved, *nrec < 0. * When the entry after *dadr is moved, *nrec >= 0. * Return the address of the obtained free entry being mapped to the return value. * When *mid == E_LIMIT, it is shown that no free entry was found. * When no free entry was found, return the record count after *dadr to *nrec. * */LOCAL DfIndirectIndex* getFreeIIdx( DskAdr *dadr, W lv, OFCB *ofcb, ID_ERR *mid, W *nrec ){ FsInfo *fsinfo = ofcb->fsinfo; LogAdr ladr; DfIndirectIndex *baseIIdx; W cur, top, end, i; W arec; ER err; ladr = fmpDAdrToLAdr(*dadr, fsinfo); cur = (W)(ladr.offset / sizeof(DfIndirectIndex)); top = (W)TopIIdx(lv, ofcb); end = (W)(fsinfo->sblk / sizeof(DfIndirectIndex)); /* Map the indirect index block. */ baseIIdx = fmpMapLogBlk(ladr.blk, ofcb, mid, fsinfo); if ( baseIIdx == NULL ) { err = (ER)*mid; goto err_ret; } arec = 0; /* Record count after *dadr */ /* Find a free indirect index from after cur. */ for ( i = cur + 1; i < end; ++i ) { if ( baseIIdx[i].blk == 0U ) { /* Move index to make a space just after cur. */ *nrec = shiftDownIIdx(baseIIdx, cur + 1, i, fsinfo); return &baseIIdx[cur + 1]; } arec += (W)fmpConvEndianW(baseIIdx[i].nrec, fsinfo); } /* Find a free indirect index from before cur. */ for ( i = cur - 1; i >= top; --i ) { if ( baseIIdx[i].blk == 0U ) { /* Move index to make a space just after cur. */ *nrec = - shiftUpIIdx(baseIIdx, i, cur, fsinfo); /* Since the location of cur was moved, move *dadr too */ dadr->offset = (VP)((VB*)dadr->offset - sizeof(DfIndirectIndex)); return &baseIIdx[cur]; } } fmpUnmapDisk(*mid, MD_RDONLY); /* No space found. */ *nrec = arec; *mid = E_LIMIT; return NULL;err_ret: DEBUG_PRINT(("getFreeIIdx err = %d\n", err)); *mid = err; return NULL;}/* * Extend the index level by one level. */LOCAL ER expandIndexLevel( RIdx *ri ){ UW oldblk, newblk; DfFileHeaderBlock *old, *new; DfIndirectIndex *iidx; DfFileID *fidt, f; W size; ID oldmid, newmid, mid; OFCB *ofcb = ri->ofcb; FsInfo *fsinfo = ofcb->fsinfo; ER err; if ( ofcb->idxlv >= MaxIndexLevel ) { /* Unable to extend any more. */ err = E_LIMIT; goto err_ret1; } /* Map the current file header. */ oldblk = fmpDAdrToLBlk(ofcb->fhead, fsinfo); old = fmpMapLogBlk(oldblk, ofcb, &oldmid, fsinfo); if ( old == NULL ) { err = (ER)oldmid; goto err_ret1; } /* Reserve new block. */ err = fmpAllocateOneBlock(oldblk, ofcb, fsinfo); if ( err < E_OK ) { goto err_ret2; } newblk = (UW)err; /* Use the new block as new file header. */ new = fmpMapAndClearLogBlk(newblk, ofcb, &newmid, fsinfo); if ( new == NULL ) { err = (ER)newmid; goto err_ret2; } /* Move the file header to the new block. Move the file header excluding the record index/indirect index, and the fragment table to the new block. */ size = (W)ofcb->ridxofs; memcpy(new, old, (size_t)size); memset(old, 0, (size_t)size); /* The old block is cleared to 0 as an unused index. */ /* Register the index block of the new block in the indirect index as old header block. */ iidx = (DfIndirectIndex*)((VB*)new + ofcb->ridxofs); iidx->blk = fmpConvEndianW(oldblk, fsinfo); iidx->nrec = fmpConvEndianW((UW)ofcb->nrec, fsinfo); /* Update the index level. */ ofcb->idxlv++; new->head.idxlv = (H)fmpConvEndianH((UH)ofcb->idxlv, fsinfo); fmpUnmapDisk(newmid, MD_WRITE); fmpUnmapDisk(oldmid, MD_WRITE); /* Register the new header block in the file ID table. */ fidt = fmpMapFileID(ofcb->fid, &mid, fsinfo); if ( fidt == NULL ) { err = (ER)mid; goto err_ret1; } f = fmpConvEndianFileID(*fidt, fsinfo); f.s.blkadr = newblk; *fidt = fmpConvEndianFileID(f, fsinfo); ofcb->fhead = fmpLBlkToDAdr(newblk, fsinfo); fmpUnmapDisk(mid, MD_WRITE); err = fmpCheckDiskError(ofcb, fsinfo); if ( err < E_OK ) { goto err_ret1; } /* Extend the index level of RCB. */ fmpExpandIndexLevelRCB(ofcb); /* Extend the index level of ri. */ fmpExpandIdxAdr(&ri->adr, FHeadIdxDAdr(ofcb)); return E_OK;err_ret2: fmpUnmapDisk(oldmid, MD_RDONLY);err_ret1: DEBUG_PRINT(("expandIndexLevel err = %d\n", err)); return err;}/* * Adjust the indirect index. * When moving the record index of nrec from the record index block of *curidx * to the record index block of *nxtidx, adjust the record count included * in indirect indexes of *curidx and *nxtidx. */LOCAL ER tuneIIdx( IdxAdr *curidx, IdxAdr *nxtidx, W lv, W nrec, OFCB *ofcb ){ FsInfo *fsinfo = ofcb->fsinfo; DfIndirectIndex *cur, *nxt; ID curmid, nxtmid; UW n; W i; ER err; for ( i = 0; i < lv; ++i ) { if ( (curidx->iidx[i].offset == nxtidx->iidx[i].offset) && (curidx->iidx[i].lblk == nxtidx->iidx[i].lblk) ) { continue; } /* Map the indirect indexe of each. */ cur = fmpMapDskAdr(curidx->iidx[i], sizeof(DfIndirectIndex), ofcb, &curmid, fsinfo); if ( cur == NULL ) { err = (ER)curmid; goto err_ret1; } nxt = fmpMapDskAdr(nxtidx->iidx[i], sizeof(DfIndirectIndex), ofcb, &nxtmid, fsinfo); if ( nxt == NULL ) { err = (ER)nxtmid; goto err_ret2; } /* Adjust the record count */ n = fmpConvEndianW(cur->nrec, fsinfo) - (UW)nrec; cur->nrec = fmpConvEndianW(n, fsinfo); n = fmpConvEndianW(nxt->nrec, fsinfo) + (UW)nrec; nxt->nrec = fmpConvEndianW(n, fsinfo); fmpUnmapDisk(curmid, MD_WRITE); fmpUnmapDisk(nxtmid, MD_WRITE); } err = fmpCheckDiskError(ofcb, fsinfo); if ( err < E_OK ) { goto err_ret1; } return E_OK;err_ret2: fmpUnmapDisk(curmid, MD_RDONLY);err_ret1: DEBUG_PRINT(("tuneIIdx err = %d\n", err)); return err;}/* * Divide the indirect index. * Divide the indirect index that includes the current location ri->adr.iidx[lv] * at the current location, and move to the new block blk. * *next is updated so that it indicates the next entry to the current * location ri->adr.iidx[lv]. Map the indirect index that the updated *next indicates, * and return the address. * When lv == ofcb->idxlv, the record index is added and the indirect index * is not divided. Map the whole record index, * and return the address. * Return the number of records that moved to *nrec. * The new block is used after it is cleared to 0. */LOCAL DfIndirectIndex* divideIIdxBlock( RIdx *ri, IdxAdr *next, W lv, UW blk, W *nrec, ID_ERR *mid ){ DfIndirectIndex *nxtbase, *curbase, *nxt, *cur, *end; LogAdr curblk; ID curmid; W nr; OFCB *ofcb = ri->ofcb; FsInfo *fsinfo = ofcb->fsinfo; ER err; /* Map the new block (0 clear) */ nxtbase = fmpMapAndClearLogBlk(blk, ofcb, mid, fsinfo); if ( nxtbase == NULL ) { err = (ER)*mid; goto err_ret1; } /* When the record index is added, the division is not made. */ if ( lv == ofcb->idxlv ) { *nrec = 0; return nxtbase; } /* Map the indirect index block at the current location. */ curblk = fmpDAdrToLAdr(ri->adr.iidx[lv], fsinfo); curbase = fmpMapLogBlk(curblk.blk, ofcb, &curmid, fsinfo); if ( curbase == NULL ) { err = (ER)curmid; goto err_ret2; } /* Divide Move */ cur = (DfIndirectIndex*)((VB*)curbase + curblk.offset); end = (DfIndirectIndex*)((VB*)curbase + fsinfo->sblk); nxt = nxtbase; nr = 0; while ( ++cur < end ) { nr += (W)fmpConvEndianW(cur->nrec, fsinfo); *(nxt++) = *cur; memset(cur, 0, (size_t)sizeof(DfIndirectIndex)); /* The old block is cleared to 0. */ } /* Obtain the location of the indirect index entry next to the current location. */ nxt = (DfIndirectIndex*)((VB*)curbase + curblk.offset) + 1; if ( nxt < end ) { fmpUnmapDisk(*mid, MD_WRITE); *mid = curmid; *next = ri->adr; next->iidx[lv].offset = (VP)((DfIndirectIndex*)next->iidx[lv].offset + 1); } else { fmpUnmapDisk(curmid, MD_WRITE); nxt = nxtbase; next->iidx[lv] = fmpLBlkToDAdr(blk, fsinfo); } err = fmpCheckDiskError(ofcb, fsinfo); if ( err < E_OK ) { goto err_ret2; } /* Adjust the indirect index. */ err = tuneIIdx(&ri->adr, next, lv, nr, ofcb); if ( err < E_OK ) { goto err_ret2; } *nrec = nr; return nxt;err_ret2: fmpUnmapDisk(*mid, MD_WRITE);err_ret1: DEBUG_PRINT(("divideIIdxBlock err = %d\n", err)); *mid = err; return NULL;}/* * Add the record index block. * Add new record index block just after the index block that contains the current * location of ri. The added index block is cleared to 0. * The current location of ri does not change. * rcb must indicate the record at current location of ri. * Set arec to the record count after the current location included * in the index block including the current location of ri. * Return the number of records moved between the index blocks to the return value. */LOCAL WER appendRIdxBlock( RIdx *ri, RCB *rcb, W arec ){ DfIndirectIndex *iidx; W blk; W i, j; W nrec, ar, n; ID mid; IdxAdr next; OFCB *ofcb = ri->ofcb; FsInfo *fsinfo = ofcb->fsinfo; ER err; ar = arec; for ( i = ofcb->idxlv - 1; i >= 0; --i ) { /* Obtain a free entry of the indirect index. */ iidx = getFreeIIdx(&ri->adr.iidx[i], i, ofcb, &mid, &nrec); if ( iidx == NULL ) { err = (ER)mid; if ( err != E_LIMIT ) { goto err_ret1; } /* Since no free entry is found, move to the indirect index of one level higher. */ ar += nrec; continue; } /* Reflect the movement made to create the free entry to RCB. */ if ( nrec >= 0 ) { fmpShiftIdxAdrRCB(rcb, i, ar + 1, ar + nrec, 1); } else { fmpShiftIdxAdrRCB(rcb, i, ar + nrec + 1, ar, TSD_SIA_RC5_M1); } /* Add the index block. */ blk = (W)fmpDAdrToLBlk(ri->adr.iidx[i], fsinfo); next = ri->adr; next.iidx[i].offset = (VP)((DfIndirectIndex*)next.iidx[i].offset + 1); nrec = 0; for ( j = i + 1; j <= ofcb->idxlv; ++j ) { /* Obtain new block. */ blk = fmpAllocateOneBlock((UW)blk, ofcb, fsinfo); if ( blk < E_OK ) { err = (ER)blk; goto err_ret2; } /* Connect to the indirect index. */ iidx->blk = fmpConvEndianW((UW)blk, fsinfo); fmpUnmapDisk(mid, MD_WRITE); /* Divide the index block at the current location, and move it to new block. */ iidx = divideIIdxBlock(ri, &next, j, (UW)blk, &n, &mid); if ( iidx == NULL ) { err = (ER)mid; goto err_ret1; } nrec += n; } fmpUnmapDisk(mid, MD_WRITE); err = fmpCheckDiskError(ofcb, fsinfo); if ( err < E_OK ) { goto err_ret1; } return nrec; } /* Extend the index level */ err = expandIndexLevel(ri); if ( err < E_OK ) { goto err_ret1; } /* Add the index block. */ err = appendRIdxBlock(ri, rcb, arec); if ( err < E_OK ) { goto err_ret1; } return err;err_ret2: fmpUnmapDisk(mid, MD_WRITE);err_ret1: DEBUG_PRINT(("appendRIdxBlock err = %d\n", err)); return err;}/* * Divide the record index block. * Divide the current record index block of ri into the part before * the div th record index and the part after div th record index, * and move the later to the next record index block. * The next record index block must be free. * The current location of ri does not change. * Return the number of records moved between blocks to the return value. */LOCAL WER divideRIdxBlock( RIdx *ri, W div ){ UW nxtblk; IdxAdr nxtidx, curidx; DfRecordIndex *nxt, *cur, *end; W nrec; OFCB *ofcb = ri->ofcb; FsInfo *fsinfo = ofcb->fsinfo; ID nxtmid; ER err; nxtidx = curidx = fmpGetIdxAdr(ri); /* Next record index block */ err = getNextRIdxBlk(&nxtidx, ofcb); if ( err < E_OK ) { goto err_ret; } nxtblk = fmpDAdrToLBlk(nxtidx.ridx, fsinfo); /* Map the next record index block */ nxt = fmpMapLogBlk(nxtblk, ofcb, &nxtmid, fsinfo); if ( nxt == NULL ) { err = (ER)nxtmid; goto err_ret; } /* Divide Move */ cur = &ri->mapbase[div]; end = (DfRecordIndex*)((VB*)ri->mapbase + fsinfo->sblk);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -