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。
(2)void dbm_close(dbf)函数。关闭dbm数据库文件。直接调用gdbm_close来完成工作。
(3)int dbm_store(dbf, key, content, flags)函数。向数据库存入一个新的关键字/数据对。直接调用gdbm_store来完成工作。
(4)datum dbm_fetch(dbf,key)函数。在数据库dbf中查找给定的关键字,返回其关联的数据。程序先调用gdbm_fetch来完成工作,然后还要把返回数据的起始地址保存在char*型全局变量_gdbm_fetch_val中。
(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; }
相关文章推荐
- SQLite剖析(10):异步IO模式、共享缓存模式和解锁通知
- dbm数据库源代码分析(10):gdbmstore.c、gdbmfetch.c和gdbmdelete.c
- dbm数据库源代码分析(14):ndbm部分(续)
- dbm数据库源代码分析(5):gdbmopen.c和gdbmclose.c
- SQLite剖析(2):编译及应用
- dbm数据库源代码分析(9):global.c、version.c和update.c
- SQLite剖析(9):动态内存分配
- SQLite剖析(6):临时文件和内存数据库
- dbm数据库源代码分析(8):hash.c和findkey.c
- Oracle官方并发教程(2)
- SQLite剖析(7):锁和并发控制
- 数据库集群技术漫谈
- dbm数据库源代码分析(4):头文件部分(续)
- SQLite剖析(1):功能特性
- dbm数据库源代码分析(1):概述
- SQLite剖析(4):数据类型
- dbm数据库源代码分析(13):ndbm部分
- dbm数据库源代码分析(10):gdbmstore.c、gdbmfetch.c和gdbmdelete.c
- dbm数据库源代码分析(5):gdbmopen.c和gdbmclose.c
- dbm数据库源代码分析(8):hash.c和findkey.c