您的位置:首页 > 数据库

dbm数据库源代码分析(13):ndbm部分

2016-07-29 00:00 423 查看
提供ndbm和dbm接口是为了与标准(如POSIX或X/Open规范)兼容。至于接口后面的实现,都是用gdbm部分来完成的,因此解剖了gdbm部分后,ndbm和dbm的实现就比较简单了,一般都是直接调用gdbm中的相应函数来完成的。注意用make编译时gdbm、ndbm、dbm部分都会被编译,但make install只会安装gdbm部分,若你需要使用ndbm和dbm的兼容实现,你还需要用make install-compat来安装它们。
(1)gdbm_file_info * dbm_open(file, flags, mode)函数。打开一个数据库文件。注意与gdbm_open中的类似,这里函数实现是返回指向gdbm_file_info结构的指针变量,而在导出的头文件ndbm.h中,函数返回的是DBM型的指针变量,指向的是一个“虚设”的结构。函数用于初始化ndbm系统。file是一个指针文件名的指针变量。在标准的dbm中,数据库用.pag和.dir两个文件来存储。为了使gdbm能够兼容ndbm,我们使用同样的文件名。特别地,在调用gdbm_open时使用文件名file.pag来存储数据。如果这个文件(file.pag)为0字节大小,则会执行一个文件初始化过程,设置文件的一些初始结构。任何的出错都将导致返回-1值,没有错误则返回0。
注意另一个文件file.dir将会被忽略并且大小总是为0字节,实现把它当作一个链接指向file.pag文件。flags和mode标志与open(2)调用中的相同。本函数将会查看flags并确定以什么样的方式调用gdbm_open。如果flags==O_RDONLY,那就是GDBM_READER;如果flags==O_RDWR|O_CREAT,那就是 GDBM_WRCREAT(创建且可写); 如果flags==O_RDWR,那就是GDBM_WRITER;如果flags包含O_TRUNC,那就是GDBM_NEWDB。flags的其他所有值都将被忽略。
函数执行流程:
1)设置好正确的文件名"file.pag"和"file.dir";
2)根据flags给出的标志,以合适的方式调用gdbm_open打开数据库文件,并返回文件信息结构;
3)如果打开的文件是新文件(即大小为0字节),删除原先的file.dir,然后让file.dir链接到file.pag,这就使两个文件的时间戳变成一样;
4)如果不能获取文件的状态信息,直接让file.dir链接到file.pag。

/* dbmopen.c - 为dbm操作打开一个文件,这是一个ndbm接口 */
/* 首先包含 */
#include "autoconf.h"
#include "gdbmdefs.h"
#include "gdbmerrno.h"
#include "extern.h"
/* 初始化ndbm系统。file是一个指针文件名的指针变量。在标准的dbm中,数据库用.pag和.dir两个文件
来存储。为了使gdbm能够兼容使用了dbminit调用的dbm,我们使用同样的文件名。特别地,dbminit在
调用gdbm_open时使用文件名file.pag。如果这个文件(file.pag)为0字节大小,则会执行一个文件
初始化过程,设置文件的一些初始结构。任何的出错都将导致返回-1值,没有错误则返回0。
注意:file.dir将会被忽略并且大小总是为0字节。flags和mode标志与open(2)调用中的相同。
本函数将会查看flags并确定以什么样的方式调用gdbm_open。对flags==O_RDONLY,那就是GDBM_READER;
如果flags==O_RDWR|O_CREAT,那就是 GDBM_WRCREAT(创建且可写); 如果flags==O_RDWR,那
就是GDBM_WRITER;如果flags包含O_TRUNC,那就是GDBM_NEWDB。flags的其他所有值都将被忽略 */
gdbm_file_info *
dbm_open (file, flags, mode)
char *file;
int flags;
int mode;
{
char* pag_file;	    /* 用来构建"file.pag" */
char* dir_file;	    /* 用来构建"file.dir" */
struct stat dir_stat;	    /* 文件"file.dir"的状态信息 */
gdbm_file_info *temp_dbf;  /* 文件信息结构的指针 */

/* 准备正确的文件名"file.pag"和"file.dir" */
pag_file = (char *) malloc (strlen (file)+5);
dir_file = (char *) malloc (strlen (file)+5);
if ((pag_file == NULL) || (dir_file == NULL))
{
gdbm_errno = GDBM_MALLOC_ERROR;
return NULL;
}
strcpy (pag_file, file);
strcat (pag_file, ".pag");
strcpy (dir_file, file);
strcat (dir_file, ".dir");

/* 调用实际的例程,并保存返回的文件信息结构 */
flags &= O_RDONLY | O_RDWR | O_CREAT | O_TRUNC;
if (flags == O_RDONLY)
{
temp_dbf = gdbm_open (pag_file, 0, GDBM_READER, 0, NULL);
}
else if (flags == (O_RDWR | O_CREAT))
{
temp_dbf = gdbm_open (pag_file, 0, GDBM_WRCREAT, mode, NULL);
}
else if ( (flags & O_TRUNC) == O_TRUNC)
{
temp_dbf = gdbm_open (pag_file, 0, GDBM_NEWDB, mode, NULL);
}
else
{
temp_dbf = gdbm_open (pag_file, 0, GDBM_WRITER, 0, NULL);
}
/* 如果没有成功地打开文件 */
if (temp_dbf == NULL)
{
gdbm_errno = GDBM_FILE_OPEN_ERROR;
goto done;
}
/* 如果打开的文件是新文件,让file.dir链接到file.pag,这就使两个文件的时间戳变成一样的 */
if (stat (dir_file, &dir_stat) == 0) /* 获取文件的状态信息 */
{
if (dir_stat.st_size == 0)
/* 删除原先的file.dir,然后让file.dir链接到file.pag */
if (unlink (dir_file) != 0 || link (pag_file, dir_file) != 0)
{
gdbm_errno = GDBM_FILE_OPEN_ERROR;
gdbm_close (temp_dbf);
temp_dbf = NULL;
goto done;
}
}
else  /* 否则不能获取到文件的状态信息,直接让file.dir链接到file.pag */
{
if (link (pag_file, dir_file) != 0)
{
gdbm_errno = GDBM_FILE_OPEN_ERROR;
gdbm_close (temp_dbf);
temp_dbf = NULL;
goto done;
}
}
/* 链接没有创建成功时,转到这里 */
done:
free (pag_file);
free (dir_file);
return temp_dbf;
}


(2)void dbm_close(dbf)函数。关闭dbm数据库文件。直接调用gdbm_close来完成工作。

/* dbmclose.c - 关闭dbm文件,这是一个ndbm接口 */
#include "autoconf.h"
#include "gdbmdefs.h"
/* 关闭dbf文件 */
void
dbm_close (dbf)
gdbm_file_info *dbf;
{
gdbm_close (dbf);
}


(3)int dbm_store(dbf, key, content, flags)函数。向数据库存入一个新的关键字/数据对。直接调用gdbm_store来完成工作。

/* dbmstore.c - 添加一个新的关键字/数据到数据库中 */
/* 首先包含系统配置方面的头文件 */
#include "autoconf.h"
#include "gdbmdefs.h"
#include "extern.h"
/* 添加一个新的关键字/数据到数据库中。key是关键字,content是其关联的数据。在从本过程
返回前,磁盘上的文件会被更新以反映新数据库的结构 */
int
dbm_store (dbf, key, content, flags)
gdbm_file_info *dbf;
datum key;
datum content;
int flags;
{
return gdbm_store (dbf, key, content, flags);
}


(4)datum dbm_fetch(dbf,key)函数。在数据库dbf中查找给定的关键字,返回其关联的数据。程序先调用gdbm_fetch来完成工作,然后还要把返回数据的起始地址保存在char*型全局变量_gdbm_fetch_val中。

/* dbmfetch.c - 查找给定的关键字,返回其关联的数据  */
#include "autoconf.h"
#include "gdbmdefs.h"
#include "extern.h"
/* 查找给定的关键字,返回其关联数据的datum结构,结构中的数据指针指向一个动态分配的内存,而不是数据在磁盘文件中的偏移地址 */
datum
dbm_fetch (dbf, key)
gdbm_file_info *dbf;
datum key;
{
datum  ret_val;		/* 返回值 */
/* 释放先前的动态内存,调用实际的函数,然后保存指针指向新的内存 */
ret_val = gdbm_fetch (dbf, key);
/* char*型全局变量_gdbm_fetch_val在extern.h中声明,在global.c中定义,用来指向返回的数据的起始地址 */
if (_gdbm_fetch_val != NULL) free (_gdbm_fetch_val);
_gdbm_fetch_val = ret_val.dptr;
/* 返回新的值 */
return ret_val;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: