📄 00000016.htm
字号:
char *idxbuf;/* malloc'ed buffer for index record */ <BR> char *datbuf;/* malloc'ed buffer for data record*/ <BR> char *name; /* name db was opened under */ <BR> off_t idxoff; /* offset in index file of index record */ <BR> /* actual key is at (idxoff + PTR_SZ + IDXLEN_SZ) */ <BR> size_t idxlen;/* length of index record */ <BR> /* excludes IDXLEN_SZ bytes at front of index record */ <BR> /* includes newline at end of index record */ <BR> off_t datoff; /* offset in data file of data record */ <BR> size_t datlen;/* length of data record */ <BR> /* includes newline at end */ <BR> off_t ptrval; /* contents of chain ptr in index record */ <BR> off_t ptroff; /* offset of chain ptr that points to this index record <BR> */ <BR> off_t chainoff;/* offset of hash chain for this index record */ <BR> off_t hashoff;/* offset in index file of hash table */ <BR> int nhash; /* current hash table size */ <BR>#define HASH_OFF PTR_SZ /* offset of hash table in index file */ <BR>typedef struct { /* our internal structure */ <BR> int idxfd; /* fd for index file */ <BR> int datfd; /* fd for data file */ <BR> int oflag; /* flags for open()/db_open(): O_xxx */ <BR> char *idxbuf;/* malloc'ed buffer for index record */ <BR> char *datbuf;/* malloc'ed buffer for data record*/ <BR> char *name; /* name db was opened under */ <BR> off_t idxoff; /* offset in index file of index record */ <BR> /* actual key is at (idxoff + PTR_SZ + IDXLEN_SZ) */ <BR> size_t idxlen;/* length of index record */ <BR> /* excludes IDXLEN_SZ bytes at front of index record */ <BR> /* includes newline at end of index record */ <BR> off_t datoff; /* offset in data file of data record */ <BR> size_t datlen;/* length of data record */ <BR> /* includes newline at end */ <BR> off_t ptrval; /* contents of chain ptr in index record */ <BR> off_t ptroff; /* offset of chain ptr that points to this index record <BR> */ <BR> off_t chainoff;/* offset of hash chain for this index record */ <BR> off_t hashoff;/* offset in index file of hash table */ <BR> int nhash; /* current hash table size */ <BR> long cnt_delok; /* delete OK */ <BR> long cnt_delerr; /* delete error */ <BR> long cnt_fetchok;/* fetch OK */ <BR> long cnt_fetcherr;/* fetch error */ <BR> long cnt_nextrec;/* nextrec */ <BR> long cnt_stor1; /* store: DB_INSERT, no empty, appended */ <BR> long cnt_stor2; /* store: DB_INSERT, found empty, reused */ <BR> long cnt_stor3; /* store: DB_REPLACE, diff data len, appended */ <BR> long cnt_stor4; /* store: DB_REPLACE, same data len, overwrote */ <BR> long cnt_storerr;/* store error */ <BR>} DB; <BR>typedef unsigned long hash_t; /* hash values */ <BR> /* user-callable functions */ <BR>DB *db_open(const char *, int, int); <BR>void db_close(DB *); <BR>char *db_fetch(DB *, const char *); <BR>int db_store(DB *, const char *, const char *, int); <BR>int db_delete(DB *, const char *); <BR>void db_rewind(DB *); <BR>char *db_nextrec(DB *, char *); <BR>void db_stats(DB *); <BR> /* internal functions */ <BR>DB *_db_alloc(int); <BR>int _db_checkfree(DB *); <BR>int _db_dodelete(DB *); <BR>int _db_emptykey(char *); <BR>int _db_find(DB *, const char *, int); <BR>int _db_findfree(DB *, int, int); <BR>int _db_free(DB *); <BR>hash_t _db_hash(DB *, const char *); <BR>char *_db_nextkey(DB *); <BR>char *_db_readdat(DB *); <BR>off_t _db_readidx(DB *, off_t); <BR>off_t _db_readptr(DB *, off_t); <BR>void _db_writedat(DB *, const char *, off_t, int); <BR>void _db_writeidx(DB *, const char *, off_t, int, off_t); <BR>void _db_writeptr(DB *, off_t, off_t); <BR>程序16.2 db.h头文件 <BR> 这里,我们定义了实现的基本限制。如果要支持更大的数据库的话,这些限制 <BR>也可以修改。其中一些我们定义为常数的值也可定义为变量,只是会使实现复杂一 <BR>些。例如,我们设定Hash表的大小为137,一个也许更好的方法是让db_open的调用 <BR>者根据数据库的大小通过参数来设定这个值,然后将这个值存在索引文件的最前面 <BR>。 <BR> 在DB结构中我们记录一个打开的数据库的所有信息。db_open函数返回一个DB <BR>结构的指针,这个指针被用于其它的所有函数。 <BR> 我们选择用db_开头来命名用户可调用的库函数,用_db_开头来命名内部函数 <BR>。 <BR> 在程序16.3中定义了函数db_open。它打开索引文件和数据文件,必要的话初 <BR>始化索引文件。通过调用_db_alloc来为DB结构分配空间,并初始化此结构。 <BR>#include "db.h" <BR>/* Open or create a database. Same arguments as open(). */ <BR>DB * <BR>db_open(const char *pathname, int oflag, int mode) <BR>{ <BR> DB *db; <BR> int i, len; <BR> char asciiptr[PTR_SZ + 1], <BR> hash[(NHASH_DEF + 1) * PTR_SZ + 2]; <BR> /* +2 for newline and null */ <BR> struct stat statbuff; <BR> /* Allocate a DB structure, and the buffers it needs */ <BR> len = strlen(pathname); <BR> if ( (db = _db_alloc(len)) == NULL) <BR> err_dump("_db_alloc error for DB"); <BR> db->oflag = oflag; /* save a copy of the open flags */ <BR> /* Open index file */ <BR> strcpy(db->name, pathname); <BR> strcat(db->name, ".idx"); <BR> if ( (db->idxfd = open(db->name, oflag, mode)) < 0) { <BR> _db_free(db); <BR> return(NULL); <BR> } <BR> /* Open data file */ <BR> strcpy(db->name + len, ".dat"); <BR> if ( (db->datfd = open(db->name, oflag, mode)) < 0) { <BR> _db_free(db); <BR> return(NULL); <BR> } <BR> /* If the database was created, we have to initialize it */ <BR> if ((oflag & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC)) { <BR> /* Write lock the entire file so that we can stat <BR> the file, check its size, and initialize it, <BR> as an atomic operation. */ <BR> if (writew_lock(db->idxfd, 0, SEEK_SET, 0) < 0) <BR> err_dump("writew_lock error"); <BR> if (fstat(db->idxfd, &statbuff) < 0) <BR> err_sys("fstat error"); <BR> if (statbuff.st_size == 0) { <BR> 如果数据库正被建立,则我们必须加锁。考虑两个进程同时试图建立同一个数 <BR>据库的情况。第一个进程运行到调用fstat,并且在fstat返回后被核心切换。这时 <BR>第二个进程调用db_open,发现索引文件的长度为0,并初始化空闲链表和Hash链表 <BR>。第二个进程继续运行,向数据库中添加了一条记录。这时第二个进程被阻塞,第 <BR>一个进程继续运行,并发现索引文件的大小为0(因为第一个进程是在fstat返回后 <BR>才被切换),所以第一个进程重新初始化空闲链表和Hash链表,第二个进程写入的 <BR>记录就被抹去了。要避免发生这种情况的方法是进行加锁,我们使用12.3节中的r <BR>eadw_lock,writew_lock和un_lock这三个函数。 <BR>db_open调用程序16.4中定义的函数_db_alloc来为DB结构分配空间,包括一个索引 <BR>缓冲和一个数据缓冲。 <BR>#include "db.h" <BR>/* Allocate & initialize a DB structure, and all the buffers it needs <BR>*/ <BR>DB * <BR>_db_alloc(int namelen) <BR>{ <BR>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -