/* Delete a record. */ int gdbm_delete(GDBM_FILE dbf, datum key){ assert(dbf); if(!key.dptr || key.dsize < 0){ gdbm_errno = GDBM_ILLEGAL_DATA; return -1; } if(dbf->depot){ if(!dpwritable(dbf->depot)){ gdbm_errno = GDBM_READER_CANT_DELETE; return -1; } if(!dpout(dbf->depot, key.dptr, key.dsize)){ gdbm_errno = gdbm_geterrno(dpecode); return -1; } if(dbf->syncmode && !dpsync(dbf->depot)){ gdbm_errno = gdbm_geterrno(dpecode); return -1; } } else { if(!crwritable(dbf->curia)){ gdbm_errno = GDBM_READER_CANT_DELETE; return -1; } if(!crout(dbf->curia, key.dptr, key.dsize)){ gdbm_errno = gdbm_geterrno(dpecode); return -1; } if(dbf->syncmode && !crsync(dbf->curia)){ gdbm_errno = gdbm_geterrno(dpecode); return -1; } } return 0; }
/* * free file table entry: * -- puts it into free list head, O(1); * -- sets references to 0; */ void fput(struct fl *fp) { struct ind *in; if (--fp->rc) /* other fd's remain */ return; /* no fd's remain */ /* -> free list head */ crin(); fp->nxt = ftb.fhd; ftb.fhd = fp; crout(); /* determine type */ switch(fp->t) { /* normally faster then if */ case FPP: rmpp(fp); break; case FIND: in = fp->in; ilck(in); /* close device if needed */ if (in->t == FCHR) devtb[in->mj].close(in->mn); iput(in); /* unlck */ break; default: kpanic("fput: fp->t == ?\n"); } }
/* release buffer */ void brelse(struct bf *b) { crin(); /* add to free list tail (MRU) */ b->fprv = bch.ftl; b->fnxt = 0; if (bch.ftl) bch.ftl->fnxt = b; else bch.fhd = b; bch.ftl = b; /* unlock */ b->flg &= ~LCKB; /* wake waiting for this/any buffer */ wakeup(b); wakeup(&bch); crout(); }
/* * get block, 4 scenarios: * -- buf is in cache & busy -- sleep until released, * then goto start (to avoid 2 processes with same block get it); * -- buf is in cache & free -- remove from free list, return buf; * -- buf isn't in cache & free list is empty -- sleep until first * buf released, then goto start (to avoid 2 processes with same * block make 2 buffers for one block); * -- buf isn't in cache & free buf available -- get it, remove * from free list, move from old to new hash queue, return buf; */ static struct bf *getblk(unsigned blk) { register struct bf *b, **hq; hq = &bch.ht[blk % NBFHT]; /* calc once */ lp: /* is in cache? */ crin(); for (b = *hq; b; b = b->hnxt) if (b->blk == blk) { if (b->flg & LCKB) { /* scenario 0 */ crout(); sleep(b); goto lp; } /* scenario 1 */ /* rm from free list */ if (b->fprv) b->fprv->fnxt = b->fnxt; else bch.fhd = b->fnxt; if (b->fnxt) b->fnxt->fprv = b->fprv; else bch.ftl = b->fprv; /* lock */ b->flg |= LCKB; crout(); return b; } /* not in cache, try alloc free buf from head */ b = bch.fhd; if (!b) { /* scenario 2 */ crout(); sleep(&bch); goto lp; } /* scenario 3 */ /* rm from free list head (LRU) */ if (b->fnxt) b->fnxt->fprv = 0; else bch.ftl = 0; bch.fhd = b->fnxt; /* * move between queues; I don't check if it's needed: * -- for most cases it's needed; * -- when no, buf will move to head according MRU; */ /* rm from old */ if (b->hprv) b->hprv->hnxt = b->hnxt; else bch.ht[b->blk % NBFHT] = b->hnxt; if (b->hnxt) b->hnxt->hprv = b->hprv; /* add to head of new */ b->hprv = 0; b->hnxt = *hq; if (*hq) (*hq)->hprv = b; *hq = b; /* lock */ b->blk = blk; b->flg |= LCKB; b->flg &= ~(DRTB | VLDB); crout(); return b; }