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

📄 16.htm

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

<p>return(-1); /* EOF for db_nextrec() */ </p>

<p>err_dump(&quot;readv error of index record&quot;); </p>

<p>} </p>

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

<p>db-&gt;ptrval = atol(asciiptr); /* offset of next key in chain */ </p>

<p>/* this is our return value; always &gt;= 0 */ </p>

<p>asciilen[IDXLEN_SZ] = 0; /* null terminate */ </p>

<p>if ( (db-&gt;idxlen = atoi(asciilen)) &lt; IDXLEN_MIN || </p>

<p>db-&gt;idxlen &gt; IDXLEN_MAX) </p>

<p>err_dump(&quot;invalid length&quot;); </p>

<p>/* Now read the actual index record. We read it into the key </p>

<p>buffer that we malloced when we opened the database. */ </p>

<p>if ( (i = read(db-&gt;idxfd, db-&gt;idxbuf, db-&gt;idxlen)) != db-&gt;idxlen) </p>

<p>err_dump(&quot;read error of indexc record&quot;); </p>

<p>if (db-&gt;idxbuf[db-&gt;idxlen-1] != '\n') </p>

<p>err_dump(&quot;missing newline&quot;); /* sanity checks */ </p>

<p>db-&gt;idxbuf[db-&gt;idxlen-1] = 0; /* replace newline with null */ </p>

<p>/* Find the separators in the index record */ </p>

<p>if ( (ptr1 = strchr(db-&gt;idxbuf, SEP)) == NULL) </p>

<p>err_dump(&quot;missing first separator&quot;); </p>

<p>*ptr1++ = 0; /* replace SEP with null */ </p>

<p>if ( (ptr2 = strchr(ptr1, SEP)) == NULL) </p>

<p>err_dump(&quot;missing second separator&quot;); </p>

<p>*ptr2++ = 0; /* replace SEP with null */ </p>

<p>if (strchr(ptr2, SEP) != NULL) </p>

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

<p>db-&gt;ptrval = atol(asciiptr); /* offset of next key in chain */ </p>

<p>/* this is our return value; always &gt;= 0 */ </p>

<p>asciilen[IDXLEN_SZ] = 0; /* null terminate */ </p>

<p>if ( (db-&gt;idxlen = atoi(asciilen)) &lt; IDXLEN_MIN || </p>

<p>db-&gt;idxlen &gt; IDXLEN_MAX) </p>

<p>err_dump(&quot;invalid length&quot;); </p>

<p>/* Now read the actual index record. We read it into the key </p>

<p>buffer that we malloced when we opened the database. */ </p>

<p>if ( (i = read(db-&gt;idxfd, db-&gt;idxbuf, db-&gt;idxlen)) != db-&gt;idxlen) </p>

<p>err_dump(&quot;read error of indexc record&quot;); </p>

<p>if (db-&gt;idxbuf[db-&gt;idxlen-1] != '\n') </p>

<p>err_dump(&quot;missing newline&quot;); /* sanity checks */ </p>

<p>db-&gt;idxbuf[db-&gt;idxlen-1] = 0; /* replace newline with null */ </p>

<p>/* Find the separators in the index record */ </p>

<p>if ( (ptr1 = strchr(db-&gt;idxbuf, SEP)) == NULL) </p>

<p>err_dump(&quot;missing first separator&quot;); </p>

<p>*ptr1++ = 0; /* replace SEP with null */ </p>

<p>if ( (ptr2 = strchr(ptr1, SEP)) == NULL) </p>

<p>err_dump(&quot;missing second separator&quot;); </p>

<p>*ptr2++ = 0; /* replace SEP with null */ </p>

<p>if (strchr(ptr2, SEP) != NULL) </p>

<p>err_dump(&quot;too many separators&quot;); </p>

<p>/* Get the starting offset and length of the data record */ </p>

<p>if ( (db-&gt;datoff = atol(ptr1)) &lt; 0) </p>

<p>err_dump(&quot;starting offset &lt; 0&quot;); </p>

<p>if ( (db-&gt;datlen = atol(ptr2)) &lt;= 0 || db-&gt;datlen &gt; DATLEN_MAX) </p>

<p>err_dump(&quot;invalid length&quot;); </p>

<p>return(db-&gt;ptrval); /* return offset of next key in chain */ </p>

<p>} </p>

<p>程序16.11 _db_readidx函数 </p>

<p>我们调用readv来读取索引记录开始处的两个固定长度的字段:指向下一条索 
</p>

<p>引记录的链指针和索引记录剩下的不定长部分的长度。然后,索引记录的剩下的部 
</p>

<p>分被读入:主键、数据记录的偏移量和数据记录的长度。我们并不读数据记录,这 
</p>

<p>由调用者自己完成。例如,在db_fetch中,在_db_find按主键找到索引记录前是不 
</p>

<p>去读取数据记录的。 </p>

<p>下面我们回到db_fetch。如果_db_find找到了索引记录,我们调用_db_readd 
</p>

<p>at来读取对应的数据记录。这是一个很简单的函数(见程序16.12)。 
</p>

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

<p>/* Read the current data record into the data buffer. </p>

<p>* Return a pointer to the null-terminated data buffer. */ </p>

<p>char * </p>

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

<p>{ </p>

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

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

<p>if (read(db-&gt;datfd, db-&gt;datbuf, db-&gt;datlen) != db-&gt;datlen) </p>

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

<p>if (db-&gt;datbuf[db-&gt;datlen - 1] != '\n') /* sanity check */ </p>

<p>err_dump(&quot;missing newline&quot;); </p>

<p>db-&gt;datbuf[db-&gt;datlen - 1] = 0; /* replace newline with null */ </p>

<p>return(db-&gt;datbuf); /* return pointer to data record */ </p>

<p>} </p>

<p>程序16.12 _de_readdat函数 </p>

<p>我们从db_fetch开始,现在已经读取了索引记录和对应的数据记录。注意到, 
</p>

<p>我们只在_db_find中加了一个读锁。由于我们对这条Hash链加了读锁,所以其他进 
</p>

<p>程在这段时间内不可能对这条Hash链进行修改。 </p>

<p>下面我们来看函数db_delete(程序16.13)。它开始时和db_fetch一样,调用 
</p>

<p>_db_find来查找记录,只是这里传递给_db_find的最后一个参数为1,表示我们要 
</p>

<p>对这一条Hash链加写锁。 </p>

<p>db_delete调用_db_dodelete(程序16.14)来完成剩下的工作(在后面我们将 
</p>

<p>看到db_store也调用_db_dodelete)。_db_dodelete的大部分工作是修正空闲链以 
</p>

<p>及与主键对应的Hash链。 </p>

<p>当一条记录被删除后,我们将其主键和数据记录设为空。在本章后面我们将提 
</p>

<p>到的函数db_nextrec要用到这一点。 </p>

<p>_db_dodelete对空闲链表加写锁,这样能防止两个进程同时删除不同链表上的 
</p>

<p>记录时产生相互影响,因为我们将被删除的记录移到空闲链表上,这将改变空闲链 
</p>

<p>表,而一次只能有一个进程能这样做。 </p>

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

<p>/* Delete the specified record */ </p>

<p>int </p>

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

<p>{ </p>

<p>int rc; </p>

<p>if (_db_find(db, key, 1) == 0) { </p>

<p>rc = _db_dodelete(db); /* record found */ </p>

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

<p>} else { </p>

<p>rc = -1; /* not found */ </p>

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

<p>} </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(rc); </p>

<p>} </p>

<p>程序16.13 db_delete函数 </p>

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

<p>/* Delete the current record specified by the DB structure. </p>

<p>* This function is called by db_delete() and db_store(), </p>

<p>* after the record has been located by _db_find(). */ </p>

<p>int </p>

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

<p>{ </p>

<p>int i; </p>

<p>char *ptr; </p>

<p>off_t freeptr, saveptr; </p>

<p>/* Set data buffer to all blanks */ </p>

<p>for (ptr = db-&gt;datbuf, i = 0; i &lt; db-&gt;datlen - 1; i++) </p>

<p>*ptr++ = ' '; </p>

<p>*ptr = 0; /* null terminate for _db_writedat() */ </p>

<p>/* Set key to blanks */ </p>

<p>ptr = db-&gt;idxbuf; </p>

<p>while (*ptr) </p>

<p>*ptr++ = ' '; </p>

<p>/* We have to lock the free list */ </p>

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

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

<p>/* Write the data record with all blanks */ </p>

<p>_db_writedat(db, db-&gt;datbuf, db-&gt;datoff, SEEK_SET); </p>

<p>/* Read the free list pointer. Its value becomes the </p>

<p>chain ptr field of the deleted index record. This means </p>

<p>the deleted record becomes the head of the free list. */ </p>

<p>freeptr = _db_readptr(db, FREE_OFF); </p>

<p>/* Save the contents of index record chain ptr, </p>

<p>before it's rewritten by _db_writeidx(). */ </p>

<p>saveptr = db-&gt;ptrval; </p>

<p>/* Rewrite the index record. This also rewrites the length </p>

<p>of the index record, the data offset, and the data length, </p>

<p>none of which has changed, but that's OK. */ </p>

<p>_db_writeidx(db, db-&gt;idxbuf, db-&gt;idxoff, SEEK_SET, freeptr); </p>

<p>/* Write the new free list pointer */ </p>

<p>_db_writeptr(db, FREE_OFF, db-&gt;idxoff); </p>

<p>/* Rewrite the chain ptr that pointed to this record </p>

<p>being deleted. Recall that _db_find() sets db-&gt;ptroff </p>

<p>to point to this chain ptr. We set this chain ptr </p>

<p>to the contents of the deleted record's chain ptr, </p>

<p>saveptr, which can be either zero or nonzero. */ </p>

<p>_db_writeptr(db, db-&gt;ptroff, saveptr); </p>

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

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

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

<p>} </p>

<p>程序16.14 _db_dodelete函数 </p>

<p>_db_dodelete通过调用函数_db_writedat(程序16.15)清空数据记录。这时 </p>

<p>_db_writedat并不对数据文件加写锁,这是因为db_delete对这条记录索引的Hash 
</p>

<p>链加了写锁,这已经保证不会有其它进程能够读写这条记录。本章后面讲述db_st 
</p>

<p>ore时,我们将看到在另一种情况下,_db_writedat将数据添加到文件的末尾,并 
</p>

<p>将加锁。 </p>

<p>_db_writedat调用writev来写数据记录及回车符。我们不能够假设调用者传递 
</p>

<p>进来的字符缓冲有空间让我们在其后面再添加一个回车符。回忆12。7节,在那里 
</p>

<p>我们曾讨论过一个writev要比两个write快。 </p>

<p>接着_db_dodelete修改索引记录。让这条记录的链指针指向空闲链表的第一条 
</p>

<p>记录(如果空闲链表为空,则这个链指针置为0),空闲链表指针也被修改,指向 
</p>

<p>当前删除的这条记录,这样就将这条删除的记录移到了空闲链表首。我们看到空闲 
</p>

<p>链表实际上很象一个先进先出的堆栈。 </p>

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

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

<p>/* Write a data record. Called by _db_dodelete() (to write </p>

<p>the record with blanks) and db_store(). */ </p>

<p>void </p>

<p>_db_writedat(DB *db, const char *data, off_t offset, int whence) </p>

<p>{ </p>

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

<p>static char newline = '\n'; </p>

<p>/* If we're appending, we have to lock before doing the lseek() </p>

<p>and write() to make the two an atomic operation. If we're </p>

<p>overwriting an existing record, we don't have to lock. */ </p>

<p>if (whence == SEEK_END) /* we're appending, lock entire file */ </p>

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

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

<p>if ( (db-&gt;datoff = lseek(db-&gt;datfd, offset, whence)) == -1) </p>

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

<p>db-&gt;datlen = strlen(data) + 1; /* datlen includes newline */ </p>

<p>iov[0].iov_base = (char *) data; </p>

<p>iov[0].iov_len = db-&gt;datlen - 1; </p>

<p>iov[1].iov_base = &amp;newline; </p>

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

<p>if (writev(db-&gt;datfd, &amp;iov[0], 2) != db-&gt;datlen) </p>

<p>err_dump(&quot;writev error of data record&quot;); </p>

<p>if (whence == SEEK_END) </p>

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

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

<p>} </p>

<p>程序16.15 _db_writedat函数 </p>

<p>我们并没有为索引文件和数据文件的空闲记录设置各自的空闲链表。这是因为 
</p>

<p>当一条记录被删除时,对应的索引记录被加入了空闲链表,而这条索引记录中有指 
</p>

<p>向数据文件中数据记录的指针。有其它很多更好的处理记录删除的方法,只是它们 
</p>

<p>会更复杂一些。 </p>

<p>程序16.16列出了函数_db_writeidx,_db_dodelete调用此函数来写一条索引 </p>

<p>记录。和_db_writedat一样,这一函数也只有在添加新索引记录时才需要加锁。_ 
</p>

<p>db_dodelete调用这条函数是为了重写一条索引记录,我们知道在这种情况下调用 
</p>

<p>者已经在Hash链上加了写锁,所以不再需要加另外的锁了。 </p>

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

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

<p>/* Write an index record. </p>

<p>* _db_writedat() is called before this function, to set the fields </p>

<p>* datoff and datlen in the DB structure, which we need to write </p>

<p>* the index record. */ </p>

<p>void </p>

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

⌨️ 快捷键说明

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