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

📄 16.htm

📁 UNIX环境下C编程的详细详细介绍
💻 HTM
📖 第 1 页 / 共 5 页
字号:
</p>

<p>据库的情况。第一个进程运行到调用fstat,并且在fstat返回后被核心切换。这时 
</p>

<p>第二个进程调用db_open,发现索引文件的长度为0,并初始化空闲链表和Hash链表 
</p>

<p>。第二个进程继续运行,向数据库中添加了一条记录。这时第二个进程被阻塞,第 
</p>

<p>一个进程继续运行,并发现索引文件的大小为0(因为第一个进程是在fstat返回后 
</p>

<p>才被切换),所以第一个进程重新初始化空闲链表和Hash链表,第二个进程写入的 
</p>

<p>记录就被抹去了。要避免发生这种情况的方法是进行加锁,我们使用12.3节中的r 
</p>

<p>eadw_lock,writew_lock和un_lock这三个函数。 </p>

<p>db_open调用程序16.4中定义的函数_db_alloc来为DB结构分配空间,包括一个索引 
</p>

<p>缓冲和一个数据缓冲。 </p>

<p>#include &quot;db.h&quot; </p>

<p>/* Allocate &amp; initialize a DB structure, and all the buffers it needs </p>

<p>*/ </p>

<p>DB * </p>

<p>_db_alloc(int namelen) </p>

<p>{ </p>

<p>DB *db; </p>

<p>/* Use calloc, to init structure to zero */ </p>

<p>if ( (db = calloc(1, sizeof(DB))) == NULL) </p>

<p>err_dump(&quot;calloc error for DB&quot;); </p>

<p>db-&gt;idxfd = db-&gt;datfd = -1; /* descriptors */ </p>

<p>/* Allocate room for the name. </p>

<p>+5 for &quot;.idx&quot; or &quot;.dat&quot; plus null at end. */ </p>

<p>if ( (db-&gt;name = malloc(namelen + 5)) == NULL) </p>

<p>err_dump(&quot;malloc error for name&quot;); </p>

<p>/* Allocate an index buffer and a data buffer. </p>

<p>+2 for newline and null at end. */ </p>

<p>if ( (db-&gt;idxbuf = malloc(IDXLEN_MAX + 2)) == NULL) </p>

<p>err_dump(&quot;malloc error for index buffer&quot;); </p>

<p>if ( (db-&gt;datbuf = malloc(DATLEN_MAX + 2)) == NULL) </p>

<p>err_dump(&quot;malloc error for data buffer&quot;); </p>

<p>return(db); </p>

<p>} </p>

<p>程序16.4 _db_alloc函数 </p>

<p>索引缓冲和数据缓冲的大小在db.h中定义。我们的数据库函数库可以通过让这 
</p>

<p>些缓冲按需要动态扩张来得到加强。其方法可以是记录这两个缓冲的大小,然后在 
</p>

<p>需要更大的缓冲时调用realloc。 </p>

<p>在函数_db_free(程序16.5)中,这些缓冲将被释放,同时打开的文件被关闭 
</p>

<p>。db_open在打开索引文件和数据文件时如果遇到错误,则调用_db_free释放资源 
</p>

<p>。db_close(程序16.6)也调用_db_free。 </p>

<p>函数db_fetch(程序16.7)根据给定的主键来读取一条记录。它调用_db_fin 
</p>

<p>d在数据库中查找一条索引记录,如果找到,再调用_db_readdat来读取对应的数据 
</p>

<p>记录。 </p>

<p>#include &quot;db.h&quot; </p>

<p>/* Free up a DB structure, and all the malloc'ed buffers it </p>

<p>* may point to. Also close the file descriptors if still open. */ </p>

<p>int </p>

<p>_db_free(DB *db) </p>

<p>{ </p>

<p>if (db-&gt;idxfd &gt;= 0 &amp;&amp; close(db-&gt;idxfd) &lt; 0) </p>

<p>err_dump(&quot;index close error&quot;); </p>

<p>if (db-&gt;datfd &gt;= 0 &amp;&amp; close(db-&gt;datfd) &lt; 0) </p>

<p>err_dump(&quot;data close error&quot;); </p>

<p>db-&gt;idxfd = db-&gt;datfd = -1; </p>

<p>if (db-&gt;idxbuf != NULL) </p>

<p>free(db-&gt;idxbuf); </p>

<p>if (db-&gt;datbuf != NULL) </p>

<p>free(db-&gt;datbuf); </p>

<p>if (db-&gt;name != NULL) </p>

<p>free(db-&gt;name); </p>

<p>free(db); </p>

<p>return(0); </p>

<p>} </p>

<p>程序16.5 _db_free函数 </p>

<p>#include &quot;db.h&quot; </p>

<p>void </p>

<p>db_close(DB *db) </p>

<p>{ </p>

<p>_db_free(db); /* closes fds, free buffers &amp; struct */ </p>

<p>} </p>

<p>程序16.6 db_close函数 </p>

<p>#include &quot;db.h&quot; </p>

<p>/* Fetch a specified record. </p>

<p>* We return a pointer to the null-terminated data. */ </p>

<p>char * </p>

<p>db_fetch(DB *db, const char *key) </p>

<p>{ </p>

<p>char *ptr; </p>

<p>if (_db_find(db, key, 0) &lt; 0) { </p>

<p>ptr = NULL; /* error, record not found */ </p>

<p>db-&gt;cnt_fetcherr++; </p>

<p>} else { </p>

<p>ptr = _db_readdat(db); /* return pointer to data */ </p>

<p>db-&gt;cnt_fetchok++; </p>

<p>} </p>

<p>/* Unlock the hash chain that _db_find() locked */ </p>

<p>if (un_lock(db-&gt;idxfd, db-&gt;chainoff, SEEK_SET, 1) &lt; 0) </p>

<p>err_dump(&quot;un_lock error&quot;); </p>

<p>return(ptr); </p>

<p>} </p>

<p>程序16.7 db_fetch函数 </p>

<p>函数_db_find(程序16.8)通过遍历Hash链来查找记录。db_fetch,db_dele </p>

<p>te和db_store这几个需要根据主键找记录的函数都调用它。 </p>

<p>#include &quot;db.h&quot; </p>

<p>/* Find the specified record. </p>

<p>* Called by db_delete(), db_fetch(), and db_store(). */ </p>

<p>int </p>

<p>_db_find(DB *db, const char *key, int writelock) </p>

<p>{ </p>

<p>off_t offset, nextoffset; </p>

<p>/* Calculate hash value for this key, then calculate byte </p>

<p>offset of corresponding chain ptr in hash table. </p>

<p>This is where our search starts. */ </p>

<p>/* calc offset in hash table for this key */ </p>

<p>db-&gt;chainoff = (_db_hash(db, key) * PTR_SZ) + db-&gt;hashoff; </p>

<p>db-&gt;ptroff = db-&gt;chainoff; </p>

<p>/* Here's where we lock this hash chain. It's the </p>

<p>caller's responsibility to unlock it when done. </p>

<p>Note we lock and unlock only the first byte. */ </p>

<p>if (writelock) { </p>

<p>if (writew_lock(db-&gt;idxfd, db-&gt;chainoff, SEEK_SET, 1) &lt; 0) </p>

<p>err_dump(&quot;writew_lock error&quot;); </p>

<p>} else { </p>

<p>if (readw_lock(db-&gt;idxfd, db-&gt;chainoff, SEEK_SET, 1) &lt; 0) </p>

<p>err_dump(&quot;readw_lock error&quot;); </p>

<p>} </p>

<p>/* Get the offset in the index file of first record </p>

<p>on the hash chain (can be 0) */ </p>

<p>offset = _db_readptr(db, db-&gt;ptroff); </p>

<p>while (offset != 0) { </p>

<p>nextoffset = _db_readidx(db, offset); </p>

<p>if (strcmp(db-&gt;idxbuf, key) == 0) </p>

<p>break; /* found a match */ </p>

<p>db-&gt;ptroff = offset; /* offset of this (unequal) record */ </p>

<p>offset = nextoffset; /* next one to compare */ </p>

<p>} </p>

<p>if (offset == 0) </p>

<p>return(-1); /* error, record not found */ </p>

<p>/* We have a match. We're guaranteed that db-&gt;ptroff contains </p>

<p>the offset of the chain ptr that points to this matching </p>

<p>index record. _db_dodelete() uses this fact. (The chain </p>

<p>ptr that points to this matching record could be in an </p>

<p>index record or in the hash table.) */ </p>

<p>return(0); </p>

<p>} </p>

<p>程序16.8 _db_find函数 </p>

<p>_db_find的最后一个参数指明我们需要加什么样的锁,0表示读锁,1表示写锁 
</p>

<p>。我们知道,db_fetch需要加读锁,而db_delete和db_store需要加写锁。_db_fi 
</p>

<p>nd在获得需要的锁之前将等待。 </p>

<p>_db_find中的while循环遍历Hash链中的索引记录,并比较主键。函数_db_re 
</p>

<p>adidx用于读取每条索引记录。 </p>

<p>请注意阅读_db_find中的最后一条注释。当沿着Hash链进行遍历时,必须始终 
</p>

<p>跟踪索引前一条索引记录,其中有一个指针指向当前记录。这一点在我们删除一条 
</p>

<p>记录时是很有用的,因为我们必须修改当前索引记录的前一条记录的链指针。 
</p>

<p>让我们先来看看_db_find调用的一些比较简单的函数。_db_hash(程序16.9) 
</p>

<p>根据给定的主键计算Hash值。它将主键中的每一个ASCII字符乘以这个字符在字符 
</p>

<p>串中以1开始的索引号,将这些结果加起来,除以Hash表的大小,将余数作为这个 
</p>

<p>主键的Hash值。 </p>

<p>#include &quot;db.h&quot; </p>

<p>/* Calculate the hash value for a key. */ </p>

<p>hash_t </p>

<p>_db_hash(DB *db, const char *key) </p>

<p>{ </p>

<p>hash_t hval; </p>

<p>const char *ptr; </p>

<p>char c; </p>

<p>int i; </p>

<p>hval = 0; </p>

<p>for (ptr = key, i = 1; c = *ptr++; i++) </p>

<p>hval += c * i; /* ascii char times its 1-based index */ </p>

<p>return(hval % db-&gt;nhash); </p>

<p>} </p>

<p>程序16.9 _db_hash函数 </p>

<p>_db_find调用的下一个函数是_db_readptr(程序16.10)。这个函数能够读取 
</p>

<p>以下三种不同的链指针中的任意一种:(1)索引文件最开始的空闲链表指针。( 
</p>

<p>2)Hash表中指向Hash链的第一条索引记录的指针。(3)每条索引记录头的指向下 
</p>

<p>一条记录的指针(这里的索引记录既可以处于一条Hash链表中,也可以处于空闲链 
</p>

<p>表中)。这个函数的调用者应做好必要的加锁,此函数不进行任何加锁。 
</p>

<p>#include &quot;db.h&quot; </p>

<p>/* Read a chain ptr field from anywhere in the index file: </p>

<p>* the free list pointer, a hash table chain ptr, or an </p>

<p>* index record chain ptr. */ </p>

<p>off_t </p>

<p>_db_readptr(DB *db, off_t offset) </p>

<p>{ </p>

<p>char asciiptr[PTR_SZ + 1]; </p>

<p>if (lseek(db-&gt;idxfd, offset, SEEK_SET) == -1) </p>

<p>err_dump(&quot;lseek error to ptr field&quot;); </p>

<p>if (read(db-&gt;idxfd, asciiptr, PTR_SZ) != PTR_SZ) </p>

<p>err_dump(&quot;read error of ptr field&quot;); </p>

<p>asciiptr[PTR_SZ] = 0; /* null terminate */ </p>

<p>return(atol(asciiptr)); </p>

<p>} </p>

<p>程序16.10 _db_readptr函数 </p>

<p>_db_find中的while循环通过调用_db_readidx来读取各条索引记录。_db_rea </p>

<p>didx(程序16.11)是一个较长的函数,这个函数读取索引记录,并将索引记录的 
</p>

<p>信息存储到适当的字段中。 </p>

<p>#include &quot;db.h&quot; </p>

<p>#include &lt;sys/uio.h&gt; /* struct iovec */ </p>

<p>/* Read the next index record. We start at the specified offset in </p>

<p>* the index file. We read the index record into db-&gt;idxbuf and </p>

<p>* replace the separators with null bytes. If all is OK we set </p>

<p>* db-&gt;datoff and db-&gt;datlen to the offset and length of the </p>

<p>* corresponding data record in the data file. */ </p>

<p>off_t </p>

<p>_db_readidx(DB *db, off_t offset) </p>

<p>{ </p>

<p>int i; </p>

<p>char *ptr1, *ptr2; </p>

<p>char asciiptr[PTR_SZ + 1], asciilen[IDXLEN_SZ + 1]; </p>

<p>struct iovec iov[2]; </p>

<p>/* Position index file and record the offset. db_nextrec() </p>

<p>calls us with offset==0, meaning read from current offset. </p>

<p>We still need to call lseek() to record the current offset. */ </p>

<p>if ( (db-&gt;idxoff = lseek(db-&gt;idxfd, offset, </p>

<p>offset == 0 ? SEEK_CUR : SEEK_SET)) == -1) </p>

<p>err_dump(&quot;lseek error&quot;); </p>

<p>/* Read the ascii chain ptr and the ascii length at </p>

<p>the front of the index record. This tells us the </p>

<p>remaining size of the index record. */ </p>

<p>iov[0].iov_base = asciiptr; </p>

<p>iov[0].iov_len = PTR_SZ; </p>

<p>iov[1].iov_base = asciilen; </p>

<p>iov[1].iov_len = IDXLEN_SZ; </p>

<p>if ( (i = readv(db-&gt;idxfd, &amp;iov[0], 2)) != PTR_SZ + IDXLEN_SZ) { </p>

<p>if (i == 0 &amp;&amp; offset == 0) </p>

⌨️ 快捷键说明

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