⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 db.c

📁 unix环境高级编程第二版配套源代码 unix环境高级编程第二版配套源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
intdb_delete(DBHANDLE h, const char *key){	DB		*db = h;	int		rc = 0;			/* assume record will be found */	if (_db_find_and_lock(db, key, 1) == 0) {		_db_dodelete(db);		db->cnt_delok++;	} else {		rc = -1;			/* not found */		db->cnt_delerr++;	}	if (un_lock(db->idxfd, db->chainoff, SEEK_SET, 1) < 0)		err_dump("db_delete: un_lock error");	return(rc);}/* * Delete the current record specified by the DB structure. * This function is called by db_delete and db_store, after * the record has been located by _db_find_and_lock. */static void_db_dodelete(DB *db){	int		i;	char	*ptr;	off_t	freeptr, saveptr;	/*	 * Set data buffer and key to all blanks.	 */	for (ptr = db->datbuf, i = 0; i < db->datlen - 1; i++)		*ptr++ = SPACE;	*ptr = 0;	/* null terminate for _db_writedat */	ptr = db->idxbuf;	while (*ptr)		*ptr++ = SPACE;	/*	 * We have to lock the free list.	 */	if (writew_lock(db->idxfd, FREE_OFF, SEEK_SET, 1) < 0)		err_dump("_db_dodelete: writew_lock error");	/*	 * Write the data record with all blanks.	 */	_db_writedat(db, db->datbuf, db->datoff, SEEK_SET);	/*	 * Read the free list pointer.  Its value becomes the	 * chain ptr field of the deleted index record.  This means	 * the deleted record becomes the head of the free list.	 */	freeptr = _db_readptr(db, FREE_OFF);	/*	 * Save the contents of index record chain ptr,	 * before it's rewritten by _db_writeidx.	 */	saveptr = db->ptrval;	/*	 * Rewrite the index record.  This also rewrites the length	 * of the index record, the data offset, and the data length,	 * none of which has changed, but that's OK.	 */	_db_writeidx(db, db->idxbuf, db->idxoff, SEEK_SET, freeptr);	/*	 * Write the new free list pointer.	 */	_db_writeptr(db, FREE_OFF, db->idxoff);	/*	 * Rewrite the chain ptr that pointed to this record being	 * deleted.  Recall that _db_find_and_lock sets db->ptroff to	 * point to this chain ptr.  We set this chain ptr to the	 * contents of the deleted record's chain ptr, saveptr.	 */	_db_writeptr(db, db->ptroff, saveptr);	if (un_lock(db->idxfd, FREE_OFF, SEEK_SET, 1) < 0)		err_dump("_db_dodelete: un_lock error");}/* * Write a data record.  Called by _db_dodelete (to write * the record with blanks) and db_store. */static void_db_writedat(DB *db, const char *data, off_t offset, int whence){	struct iovec	iov[2];	static char		newline = NEWLINE;	/*	 * If we're appending, we have to lock before doing the lseek	 * and write to make the two an atomic operation.  If we're	 * overwriting an existing record, we don't have to lock.	 */	if (whence == SEEK_END) /* we're appending, lock entire file */		if (writew_lock(db->datfd, 0, SEEK_SET, 0) < 0)			err_dump("_db_writedat: writew_lock error");	if ((db->datoff = lseek(db->datfd, offset, whence)) == -1)		err_dump("_db_writedat: lseek error");	db->datlen = strlen(data) + 1;	/* datlen includes newline */	iov[0].iov_base = (char *) data;	iov[0].iov_len  = db->datlen - 1;	iov[1].iov_base = &newline;	iov[1].iov_len  = 1;	if (writev(db->datfd, &iov[0], 2) != db->datlen)		err_dump("_db_writedat: writev error of data record");	if (whence == SEEK_END)		if (un_lock(db->datfd, 0, SEEK_SET, 0) < 0)			err_dump("_db_writedat: un_lock error");}/* * Write an index record.  _db_writedat is called before * this function to set the datoff and datlen fields in the * DB structure, which we need to write the index record. */static void_db_writeidx(DB *db, const char *key,             off_t offset, int whence, off_t ptrval){	struct iovec	iov[2];	char			asciiptrlen[PTR_SZ + IDXLEN_SZ +1];	int				len;	char			*fmt;	if ((db->ptrval = ptrval) < 0 || ptrval > PTR_MAX)		err_quit("_db_writeidx: invalid ptr: %d", ptrval);	if (sizeof(off_t) == sizeof(long long))		fmt = "%s%c%lld%c%d\n";	else		fmt = "%s%c%ld%c%d\n";	sprintf(db->idxbuf, fmt, key, SEP, db->datoff, SEP, db->datlen);	if ((len = strlen(db->idxbuf)) < IDXLEN_MIN || len > IDXLEN_MAX)		err_dump("_db_writeidx: invalid length");	sprintf(asciiptrlen, "%*ld%*d", PTR_SZ, ptrval, IDXLEN_SZ, len);	/*	 * If we're appending, we have to lock before doing the lseek	 * and write to make the two an atomic operation.  If we're	 * overwriting an existing record, we don't have to lock.	 */	if (whence == SEEK_END)		/* we're appending */		if (writew_lock(db->idxfd, ((db->nhash+1)*PTR_SZ)+1,		  SEEK_SET, 0) < 0)			err_dump("_db_writeidx: writew_lock error");	/*	 * Position the index file and record the offset.	 */	if ((db->idxoff = lseek(db->idxfd, offset, whence)) == -1)		err_dump("_db_writeidx: lseek error");	iov[0].iov_base = asciiptrlen;	iov[0].iov_len  = PTR_SZ + IDXLEN_SZ;	iov[1].iov_base = db->idxbuf;	iov[1].iov_len  = len;	if (writev(db->idxfd, &iov[0], 2) != PTR_SZ + IDXLEN_SZ + len)		err_dump("_db_writeidx: writev error of index record");	if (whence == SEEK_END)		if (un_lock(db->idxfd, ((db->nhash+1)*PTR_SZ)+1,		  SEEK_SET, 0) < 0)			err_dump("_db_writeidx: un_lock error");}/* * Write a chain ptr field somewhere in the index file: * the free list, the hash table, or in an index record. */static void_db_writeptr(DB *db, off_t offset, off_t ptrval){	char	asciiptr[PTR_SZ + 1];	if (ptrval < 0 || ptrval > PTR_MAX)		err_quit("_db_writeptr: invalid ptr: %d", ptrval);	sprintf(asciiptr, "%*ld", PTR_SZ, ptrval);	if (lseek(db->idxfd, offset, SEEK_SET) == -1)		err_dump("_db_writeptr: lseek error to ptr field");	if (write(db->idxfd, asciiptr, PTR_SZ) != PTR_SZ)		err_dump("_db_writeptr: write error of ptr field");}/* * Store a record in the database.  Return 0 if OK, 1 if record * exists and DB_INSERT specified, -1 on error. */intdb_store(DBHANDLE h, const char *key, const char *data, int flag){	DB		*db = h;	int		rc, keylen, datlen;	off_t	ptrval;	if (flag != DB_INSERT && flag != DB_REPLACE &&	  flag != DB_STORE) {		errno = EINVAL;		return(-1);	}	keylen = strlen(key);	datlen = strlen(data) + 1;		/* +1 for newline at end */	if (datlen < DATLEN_MIN || datlen > DATLEN_MAX)		err_dump("db_store: invalid data length");	/*	 * _db_find_and_lock calculates which hash table this new record	 * goes into (db->chainoff), regardless of whether it already	 * exists or not. The following calls to _db_writeptr change the	 * hash table entry for this chain to point to the new record.	 * The new record is added to the front of the hash chain.	 */	if (_db_find_and_lock(db, key, 1) < 0) { /* record not found */		if (flag == DB_REPLACE) {			rc = -1;			db->cnt_storerr++;			errno = ENOENT;		/* error, record does not exist */			goto doreturn;		}		/*		 * _db_find_and_lock locked the hash chain for us; read		 * the chain ptr to the first index record on hash chain.		 */		ptrval = _db_readptr(db, db->chainoff);		if (_db_findfree(db, keylen, datlen) < 0) {			/*			 * Can't find an empty record big enough. Append the			 * new record to the ends of the index and data files.			 */			_db_writedat(db, data, 0, SEEK_END);			_db_writeidx(db, key, 0, SEEK_END, ptrval);			/*			 * db->idxoff was set by _db_writeidx.  The new			 * record goes to the front of the hash chain.			 */			_db_writeptr(db, db->chainoff, db->idxoff);			db->cnt_stor1++;		} else {			/*			 * Reuse an empty record. _db_findfree removed it from			 * the free list and set both db->datoff and db->idxoff.			 * Reused record goes to the front of the hash chain.			 */			_db_writedat(db, data, db->datoff, SEEK_SET);			_db_writeidx(db, key, db->idxoff, SEEK_SET, ptrval);			_db_writeptr(db, db->chainoff, db->idxoff);			db->cnt_stor2++;		}	} else {						/* record found */		if (flag == DB_INSERT) {			rc = 1;		/* error, record already in db */			db->cnt_storerr++;			goto doreturn;		}		/*		 * We are replacing an existing record.  We know the new		 * key equals the existing key, but we need to check if		 * the data records are the same size.		 */		if (datlen != db->datlen) {			_db_dodelete(db);	/* delete the existing record */			/*			 * Reread the chain ptr in the hash table			 * (it may change with the deletion).			 */			ptrval = _db_readptr(db, db->chainoff);			/*			 * Append new index and data records to end of files.			 */			_db_writedat(db, data, 0, SEEK_END);			_db_writeidx(db, key, 0, SEEK_END, ptrval);			/*			 * New record goes to the front of the hash chain.			 */			_db_writeptr(db, db->chainoff, db->idxoff);			db->cnt_stor3++;		} else {			/*			 * Same size data, just replace data record.			 */			_db_writedat(db, data, db->datoff, SEEK_SET);			db->cnt_stor4++;		}	}	rc = 0;		/* OK */doreturn:	/* unlock hash chain locked by _db_find_and_lock */	if (un_lock(db->idxfd, db->chainoff, SEEK_SET, 1) < 0)		err_dump("db_store: un_lock error");	return(rc);}/* * Try to find a free index record and accompanying data record * of the correct sizes.  We're only called by db_store. */static int_db_findfree(DB *db, int keylen, int datlen){	int		rc;	off_t	offset, nextoffset, saveoffset;	/*	 * Lock the free list.	 */	if (writew_lock(db->idxfd, FREE_OFF, SEEK_SET, 1) < 0)		err_dump("_db_findfree: writew_lock error");	/*	 * Read the free list pointer.	 */	saveoffset = FREE_OFF;	offset = _db_readptr(db, saveoffset);	while (offset != 0) {		nextoffset = _db_readidx(db, offset);		if (strlen(db->idxbuf) == keylen && db->datlen == datlen)			break;		/* found a match */		saveoffset = offset;		offset = nextoffset;	}	if (offset == 0) {		rc = -1;	/* no match found */	} else {		/*		 * Found a free record with matching sizes.		 * The index record was read in by _db_readidx above,		 * which sets db->ptrval.  Also, saveoffset points to		 * the chain ptr that pointed to this empty record on		 * the free list.  We set this chain ptr to db->ptrval,		 * which removes the empty record from the free list.		 */		_db_writeptr(db, saveoffset, db->ptrval);		rc = 0;		/*		 * Notice also that _db_readidx set both db->idxoff		 * and db->datoff.  This is used by the caller, db_store,		 * to write the new index record and data record.		 */	}	/*	 * Unlock the free list.	 */	if (un_lock(db->idxfd, FREE_OFF, SEEK_SET, 1) < 0)		err_dump("_db_findfree: un_lock error");	return(rc);}/* * Rewind the index file for db_nextrec. * Automatically called by db_open. * Must be called before first db_nextrec. */voiddb_rewind(DBHANDLE h){	DB		*db = h;	off_t	offset;	offset = (db->nhash + 1) * PTR_SZ;	/* +1 for free list ptr */	/*	 * We're just setting the file offset for this process	 * to the start of the index records; no need to lock.	 * +1 below for newline at end of hash table.	 */	if ((db->idxoff = lseek(db->idxfd, offset+1, SEEK_SET)) == -1)		err_dump("db_rewind: lseek error");}/* * Return the next sequential record. * We just step our way through the index file, ignoring deleted * records.  db_rewind must be called before this function is * called the first time. */char *db_nextrec(DBHANDLE h, char *key){	DB		*db = h;	char	c;	char	*ptr;	/*	 * We read lock the free list so that we don't read	 * a record in the middle of its being deleted.	 */	if (readw_lock(db->idxfd, FREE_OFF, SEEK_SET, 1) < 0)		err_dump("db_nextrec: readw_lock error");	do {		/*		 * Read next sequential index record.		 */		if (_db_readidx(db, 0) < 0) {			ptr = NULL;		/* end of index file, EOF */			goto doreturn;		}		/*		 * Check if key is all blank (empty record).		 */		ptr = db->idxbuf;		while ((c = *ptr++) != 0  &&  c == SPACE)			;	/* skip until null byte or nonblank */	} while (c == 0);	/* loop until a nonblank key is found */	if (key != NULL)		strcpy(key, db->idxbuf);	/* return key */	ptr = _db_readdat(db);	/* return pointer to data buffer */	db->cnt_nextrec++;doreturn:	if (un_lock(db->idxfd, FREE_OFF, SEEK_SET, 1) < 0)		err_dump("db_nextrec: un_lock error");	return(ptr);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -