📄 00000016.htm
字号:
DB *db; <BR> /* Use calloc, to init structure to zero */ <BR> if ( (db = calloc(1, sizeof(DB))) == NULL) <BR> err_dump("calloc error for DB"); <BR> db->idxfd = db->datfd = -1; /* descriptors */ <BR> /* Allocate room for the name. <BR> +5 for ".idx" or ".dat" plus null at end. */ <BR> if ( (db->name = malloc(namelen + 5)) == NULL) <BR> err_dump("malloc error for name"); <BR> /* Allocate an index buffer and a data buffer. <BR> +2 for newline and null at end. */ <BR> if ( (db->idxbuf = malloc(IDXLEN_MAX + 2)) == NULL) <BR> err_dump("malloc error for index buffer"); <BR> if ( (db->datbuf = malloc(DATLEN_MAX + 2)) == NULL) <BR> err_dump("malloc error for data buffer"); <BR> return(db); <BR>} <BR>程序16.4 _db_alloc函数 <BR> 索引缓冲和数据缓冲的大小在db.h中定义。我们的数据库函数库可以通过让这 <BR>些缓冲按需要动态扩张来得到加强。其方法可以是记录这两个缓冲的大小,然后在 <BR>需要更大的缓冲时调用realloc。 <BR> 在函数_db_free(程序16.5)中,这些缓冲将被释放,同时打开的文件被关闭 <BR>。db_open在打开索引文件和数据文件时如果遇到错误,则调用_db_free释放资源 <BR>。db_close(程序16.6)也调用_db_free。 <BR> 函数db_fetch(程序16.7)根据给定的主键来读取一条记录。它调用_db_fin <BR>d在数据库中查找一条索引记录,如果找到,再调用_db_readdat来读取对应的数据 <BR>记录。 <BR> <BR>#include "db.h" <BR>/* Free up a DB structure, and all the malloc'ed buffers it <BR> * may point to. Also close the file descriptors if still open. */ <BR>int <BR>_db_free(DB *db) <BR>{ <BR> if (db->idxfd >= 0 && close(db->idxfd) < 0) <BR> err_dump("index close error"); <BR> if (db->datfd >= 0 && close(db->datfd) < 0) <BR> err_dump("data close error"); <BR> db->idxfd = db->datfd = -1; <BR> if (db->idxbuf != NULL) <BR> free(db->idxbuf); <BR> if (db->datbuf != NULL) <BR> free(db->datbuf); <BR> if (db->name != NULL) <BR> free(db->name); <BR> free(db); <BR> return(0); <BR>} <BR>程序16.5 _db_free函数 <BR>#include "db.h" <BR>void <BR>db_close(DB *db) <BR>{ <BR> _db_free(db); /* closes fds, free buffers & struct */ <BR>} <BR>程序16.6 db_close函数 <BR>#include "db.h" <BR>/* Fetch a specified record. <BR> * We return a pointer to the null-terminated data. */ <BR>char * <BR>db_fetch(DB *db, const char *key) <BR>{ <BR> char *ptr; <BR> if (_db_find(db, key, 0) < 0) { <BR> ptr = NULL; /* error, record not found */ <BR> db->cnt_fetcherr++; <BR> } else { <BR> ptr = _db_readdat(db); /* return pointer to data */ <BR> db->cnt_fetchok++; <BR> } <BR> /* Unlock the hash chain that _db_find() locked */ <BR> if (un_lock(db->idxfd, db->chainoff, SEEK_SET, 1) < 0) <BR> err_dump("un_lock error"); <BR> return(ptr); <BR>} <BR>程序16.7 db_fetch函数 <BR> 函数_db_find(程序16.8)通过遍历Hash链来查找记录。db_fetch,db_dele <BR>te和db_store这几个需要根据主键找记录的函数都调用它。 <BR>#include "db.h" <BR>/* Find the specified record. <BR> * Called by db_delete(), db_fetch(), and db_store(). */ <BR>int <BR>_db_find(DB *db, const char *key, int writelock) <BR>{ <BR> off_t offset, nextoffset; <BR> /* Calculate hash value for this key, then calculate byte <BR> offset of corresponding chain ptr in hash table. <BR> This is where our search starts. */ <BR> /* calc offset in hash table for this key */ <BR> db->chainoff = (_db_hash(db, key) * PTR_SZ) + db->hashoff; <BR> db->ptroff = db->chainoff; <BR> /* Here's where we lock this hash chain. It's the <BR> caller's responsibility to unlock it when done. <BR> Note we lock and unlock only the first byte. */ <BR> if (writelock) { <BR> if (writew_lock(db->idxfd, db->chainoff, SEEK_SET, 1) < 0) <BR> err_dump("writew_lock error"); <BR> } else { <BR> if (readw_lock(db->idxfd, db->chainoff, SEEK_SET, 1) < 0) <BR> err_dump("readw_lock error"); <BR> } <BR> /* Get the offset in the index file of first record <BR> on the hash chain (can be 0) */ <BR> offset = _db_readptr(db, db->ptroff); <BR> while (offset != 0) { <BR> nextoffset = _db_readidx(db, offset); <BR> if (strcmp(db->idxbuf, key) == 0) <BR> break; /* found a match */ <BR> db->ptroff = offset; /* offset of this (unequal) record */ <BR> offset = nextoffset; /* next one to compare */ <BR> } <BR> if (offset == 0) <BR> return(-1); /* error, record not found */ <BR> /* We have a match. We're guaranteed that db->ptroff contains <BR> the offset of the chain ptr that points to this matching <BR> index record. _db_dodelete() uses this fact. (The chain <BR> ptr that points to this matching record could be in an <BR> index record or in the hash table.) */ <BR> return(0); <BR>} <BR>程序16.8 _db_find函数 <BR> _db_find的最后一个参数指明我们需要加什么样的锁,0表示读锁,1表示写锁 <BR>。我们知道,db_fetch需要加读锁,而db_delete和db_store需要加写锁。_db_fi <BR>nd在获得需要的锁之前将等待。 <BR> _db_find中的while循环遍历Hash链中的索引记录,并比较主键。函数_db_re <BR>adidx用于读取每条索引记录。 <BR> 请注意阅读_db_find中的最后一条注释。当沿着Hash链进行遍历时,必须始终 <BR>跟踪索引前一条索引记录,其中有一个指针指向当前记录。这一点在我们删除一条 <BR>记录时是很有用的,因为我们必须修改当前索引记录的前一条记录的链指针。 <BR> 让我们先来看看_db_find调用的一些比较简单的函数。_db_hash(程序16.9) <BR>根据给定的主键计算Hash值。它将主键中的每一个ASCII字符乘以这个字符在字符 <BR>串中以1开始的索引号,将这些结果加起来,除以Hash表的大小,将余数作为这个 <BR>主键的Hash值。 <BR>#include "db.h" <BR>/* Calculate the hash value for a key. */ <BR>hash_t <BR>_db_hash(DB *db, const char *key) <BR>{ <BR> hash_t hval; <BR> const char *ptr; <BR> char c; <BR> int i; <BR> hval = 0; <BR>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -