您的位置:首页 > 数据库

dbm数据库源代码分析(5):gdbmopen.c和gdbmclose.c

2016-07-29 00:00 447 查看
现在解剖gdbmopen.c和gdbmclose.c的源码。
gdbmopen.c包含打开数据库的函数gdbm_oepen和初始化桶缓存的函数_gdbm_init_cache。注意其中的函数签名格式,函数参数列表中没给出类型,类型信息在圆括号和语句开始的左花括号之间。这种风格的函数签名是为了兼容老式的非标准的C编译器,gcc也支持这种风格的函数签名。

(1)gdbm_file_info* gdbm_oepen(name,block_size,flags,mode,fatal_func)函数。name是指向文件名指针。注意这个函数返回一个指向gdbm_file_info结构的指针变量(称为文件句柄),而在导出的头文件中(参看gdbm.proto),此函数声明返回的是GDBM_FILE型变量,也是一个指针变量。由于都是指针型变量,即都是int型,存放的是一个地址值,因此是一致的。至于这个指针具体指向什么类型的结构,对用户来说无关紧要,他只需使用这个句柄来操作文件,并不需要知道结构中的具体内容。因此为了隐藏实现,在导出的用户接口中我们通常让这个返回的指针变量指向一个“虚设”的无实际用途的结构,这样用户就不会知道gdbm_file_info结构的具体内容,但同时又不要影响他对接口的使用。这就是为什么gdbm.proto中要定义一个GDBM_FILE型的指针变量指向一个“虚设”的结构。在其他导出的用户接口中,这个打开的文件句柄dbf也被声明为GDBM_FILE类型的指针变量,在具体的函数实现时,dbf实际上是指向打开的gdbm_file_info结构的。

函数执行时,如果文件大小为0字节,则执行一个文件初始化过程,设置文件中的一些初始结构。block_size用来在初始化过程中确定各个结构的大小,如果它的值小于512,则使用文件系统的默认值,否则就使用这个传进来的block_size值。如果文件事先已经初始化过了,则忽略block_size值。如果flags设置为GDBM_READER,用户以只读方式访问数据库,则任何对dbm_store或dbm_delete的调用都将会失败。多个用户可同时访问一个数据库(使用文件锁)。如果flag设置为GDBM_WRITER,说明用户以可读写方式访问数据库,这需要一个排它锁。如果flags是GDBM_WRCREAT,则用户以可读写的的方式访问数据库,且当数据库不存在时,创建一个新的数据库(也是可读写的)。整个过程中任何的操作出错都将导致返回NULL,并且把错误码设置到全局变量gdbm_errno中。如果没有错误发生,将返回一个指向gdbm文件结构的指针。
gdbm_open的执行流程:
1)创建文件结构dbf并分配空间,然后一些指针域被初始化为空;
2)为文件名的字符串存储分配空间,然后保存文件名;
3)初始化错误处理函数及一些访问标志;
4)根据flags确定是否设置快速写模式;
5)根据flags用open函数打开文件,获得其文件描述符;
6)获取文件的状态信息,然后以适当的方式(共享锁或排它锁)锁定文件;
7)根据状态信息确定打开的是新文件还是已经存在的数据库文件;
8)若是新文件(即文件大小为0字节),则
a)设置传递块的大小;
b)为文件头分配空间,设置其魔数和传递块大小;
c)创建要跟踪的散列桶目录表,并分配空间;
d)创建文件头要跟踪的散列桶,先计算桶中元素个数,然后分配空间;
f)调用_gdbm_new_bucket初始化这个新桶并设置其中的一些标志,然后初始化每个目录项;
g)将所有这些初始化信息写入文件,开始是文件头和活动的可用块,接着是目录表,最后是桶。
9)若是一个已经存在的数据库文件,则
a)读取文件中的文件头,并用魔数对其进行校验;
b)为我们的文件头分配空间,并设置为所读取的文件头信息;
c)为我们的散列表目录分配空间,并设置为所读取的散列表目录。
10)完成文件的操作后,将dbf中其他的指针域(如桶缓存)初始化为空,并完成记帐信息的初始化;
11)返回最终的文件信息结构指针dbf。
注意我们要获取的文件的各项信息,如文件头、散列桶目录表、第一个散列桶等,被读入到了内存(若是新文件则直接在内存中创建),并且在dbf中都有指针指向它。
我们知道,数据库文件中只包含gdbm_file_header(其中包含avail_block及avail_elem)、dir[dir_size/4]、hash_bucket(其中包含bucket_element)。在初始化新文件时,会先截断文件,表示文件将从位置0处开始初始化。gdbm_file_header本身只有52个字节,但初始化时它要占blocksize个字节(此参数由用户指定,但不能小于512,小于512时会重设为文件系统的默认值,目前Linux上一般为1024),空出来的部分用来存放avail_elem元素列表(指明可用存储块的实际位置和大小)。文件头中的block_size域、dir_size域都会被初始化为blocksize,dir_bits为其所占的二进制位数。可见散列桶目录表中有blocksize/4个目录项(每个目录项为off_t类型,即long,占4个字节),且整个散列桶目录表共占blocksize个字节。目录表跟在文件头之后,因此文件头中的指向目录表起始地址的dir域恰好初始化为blocksize。
一个hash_bucket本身只有80个字节,但初始化时它也要占blocksize个字节,因此文件头的中bucket_size域也被初始化为blocksize。后面空出的部分用来存放以后分裂出来的bucket_element[]列表(即可扩展散列表),能存放的桶元素个数为(blocksize-sizeof(hash_bucket))/sizeof(bucket_element)+1 = (blocksize-80)/20+1,加1是因为hash_bucket中那个活动的bucket_element也要算进去。这个值会设置到文件头的bucket_elems域中去。这样bucket_elems记录了一个blocksize个字节的hash_bucket总共能存放的bucket_element个数。在用_gdbm_new_bucket初始化这个hash_bucket时,bucket_bits标识域和count域设为0,每个桶元素的哈希值hash_val初始化为-1。然后可用块个数av_count设为1,表示桶对应了1个分配的可用存储块(目前一个hash_bucket最多只能对应6个可用存储块),用bucket_avail[0](avail_elem结构)指明这个可用块。这个可用块紧跟在hash_bucket之后,因此它的地址av_adr为3*blocksize,可用块的大小av_size也设置为blocksize。
之后,对目录表中的每个目录项以及文件头中的活动的可用块进行初始化。由于初始时只有一个hash_bucket,因此dir[0...dir_size/4-1]中的每个目录项初始时都指向这个hash_bucket。文件头中的avail(avail_block类型)的size域表示文件头空间中能存储的avail_elem元素个数,它的值为(blocksize-sizeof(gdbm_file_header))/sizeof(avail_elem)+1 = (blocksize-52)/8+1,加1是因为avail中的那个活动的avail_elem也要算进去。这样avail.size记录了一个blocksize个字节的文件头总共能存放的avail_elem个数。avail的count和next_block(下一个可用块的偏移地址)均初始化为0。文件头的next_block指针表示下一个未分配可用块地址,因此要初始化为4*blocksize。所有工作做完后,把这些数据按顺序写入到文件中。
可见,数据库文件上的排布为:文件头、目录表、散列桶,每一部分都占blocksize个字节。后面接着的就是存放关键字/数据的可用块,每个可用块也占blocksize个字节。散列桶可以对可用块及块中的关键字/数据(这是我们需要的)进行定位、查找、存取等。
(2)int _gdbm_init_cache(dbf,size)函数。用于初始化桶缓存数组。dbf为文件信息结构,size为桶缓存中缓存项的个数,默认为DEFAULT_CACHESIZE,在gdbmconst.h中定义,为100。桶缓存为一个数组,每个元素为一个缓存项(cache_elem),缓存项不仅包含了实际的桶指针,还包含了数据缓存块及一些标志。数据缓存块包含包含哈希值、数据长度、关键字长度、指向数据起点的指针、偏移位置值等字段。
函数执行流程如下:
1)根据size参数为桶楥存数组分配空间;
2)初始化每个缓存项持有的桶,并分配空间;
3)初始化每个缓存项的的数据缓存块;
4)设置文件信息结构中的当前桶和当前缓存项指针;
5)成功,返回0。
dbf中的cache_size域是缓存项的个数,初始化为size;bucket域初始化为指向第一个缓存项持有的桶;cache_entry域初始化为指向第一个缓存项。每个缓存项的桶偏移地址ca_adr初始化为0,其数据缓存元素的hash_val和elem_loc初始化为-1,数据起点指针dptr初始化NULL。

/* gdbmopen.c - 打开dbm文件,并且初始化要使用的数据结构 */
/* 先包含系统相关配置 */
#include "autoconf.h"  /* 包含平台相关头文件和函数的常量标志 */
#include "gdbmdefs.h"   /* 包含桶、缓存项、数据库文件结构的定义
所有平台相关的头文件和函数声明、gdbm的所有函数声明和要用到的常量也在这里 */
#include "gdbmerrno.h"  /* 包含所有的错误码列表 */
/* 打开数据库文件,不存在时则创建新的数据库文件,并执行一个文件初始化过程 */
gdbm_file_info *
gdbm_open (file, block_size, flags, mode, fatal_func)
char *file;              /* 要打开的文件名 */
int  block_size;         /* 设置内存与磁盘IO传递数据的单位,最小为512字节 */
int  flags;              /* 文件打开标志,可以是gdbmconst.h中定义的标志GDMB_READER、
GDMB_WRITER */
int  mode;               /* 文件创建模式,与open(2)函数相同 */
void (*fatal_func) ();   /* 错误处理函数 */
{
gdbm_file_info *dbf;		/* 要返回的文件结构记录 */
struct stat file_stat;	/* 封装文件信息stat结构 */
int         len;		/* 文件名的长度 */
int         num_bytes;	/* 在读和写的过程中使用 */
off_t       file_pos;		/* 文件读写位置 */
int	      lock_val;         /* Returned by the flock call. */
int	      file_block_size;	/* 传递的数据块大小(用于新文件) */
int 	      index;		/* 作为循环索引 */
char        need_trunc;	/* 是否需要截断处理,在使用GDBM_NEWDB和锁时需要截断,以避免在只读
的方式下截断文件 */

gdbm_errno = GDBM_NO_ERROR; /* 初始化变量gdbm_errno */
/* 为一个新的文件结构分配空间 */
dbf = (gdbm_file_info *) malloc (sizeof (gdbm_file_info));
if (dbf == NULL)
{
gdbm_errno = GDBM_MALLOC_ERROR; /* 设置内存分配错误码 */
return NULL;
}
/* 先初始化一些域为空,这样如果在分配这些结构前gdbm_close被调用,则也能正常工作 */
dbf->dir  = NULL;
dbf->bucket = NULL;
dbf->header = NULL;
dbf->bucket_cache = NULL;
dbf->cache_size = 0;

/* 保存文件名 */
len = strlen (file);
dbf->name = (char *) malloc (len + 1); /* 为文件名分配内存空间 */
if (dbf->name == NULL) /* 若分配未成功,则释放已分配的文件结构,直接返回 */
{
free (dbf);
gdbm_errno = GDBM_MALLOC_ERROR;
return NULL;
}
strcpy (dbf->name, file); /* 保存好文件名 */
/* 初始化错误处理函数 */
dbf->fatal_err = fatal_func;
dbf->fast_write = TRUE;	/* 默认为快速写模式 */
dbf->file_locking = TRUE;	/* 默认需要文件锁 */
dbf->central_free = FALSE;	/* 默认不使用central_free */
dbf->coalesce_blocks = FALSE; /* 默认不合并空闲块 */
/* GDBM_FAST用来确定是否设置快速写模式 */
if (flags & GDBM_SYNC)
{
/* 如果GDBM_SYNC被设置,则不做快速写 */
dbf->fast_write = FALSE;
}
if (flags & GDBM_NOLOCK) /* 如果设置了无需文件锁标志 */
{
dbf->file_locking = FALSE;
}
/* 打开文件 */
need_trunc = FALSE;
switch (flags & GDBM_OPENMASK) /* 掩码可以掩掉除尾三位的所有其他位 */
{
case GDBM_READER: /* 只读方式打开 */
dbf->desc = open (dbf->name, O_RDONLY, 0);
break;
case GDBM_WRITER: /* 可写方式打开 */
dbf->desc = open (dbf->name, O_RDWR, 0);
break;
case GDBM_NEWDB: /* 要创建新文件(O_CREATE标志),则要使用mode参数 */
dbf->desc = open (dbf->name, O_RDWR|O_CREAT, mode);
need_trunc = TRUE;
break;
default:
dbf->desc = open (dbf->name, O_RDWR|O_CREAT, mode);
break;
bucket_cache
}
if (dbf->desc < 0)
{
free (dbf->name);
free (dbf);
gdbm_errno = GDBM_FILE_OPEN_ERROR; /* 设置打开文件错误 */
return NULL;
}
/* 获取文件的状态信息 */
fstat (dbf->desc, &file_stat);
/* 以适当的方式锁定文件 */
if ((flags & GDBM_OPENMASK) == GDBM_READER) /* 只读时的锁写 */
{
if (file_stat.st_size == 0) /* 文件大小为0,即读的是一个空文件 */
{
close (dbf->desc);
free (dbf->name);
free (dbf);
gdbm_errno = GDBM_EMPTY_DATABASE; /* 设置读取空数据库错误 */
return NULL;
}
if (dbf->file_locking)
{
/* 只读方式锁定文件(共享锁),成功则会设置lock_val为0,参看system.h */
READLOCK_FILE(dbf);
}
}
else if (dbf->file_locking) /* 否则加可写锁 */
{
/* 可写方式锁定文件(排它锁),成功则会设置lock_val为0,参看system.h */
WRITELOCK_FILE(dbf);
}
if (dbf->file_locking && (lock_val != 0)) /* 锁定未成功 */
{
close (dbf->desc);
free (dbf->name);
free (dbf);
if ((flags & GDBM_OPENMASK) == GDBM_READER)
gdbm_errno = GDBM_CANT_BE_READER; /* 设置为不能加共享锁 */
else
gdbm_errno = GDBM_CANT_BE_WRITER; /* 设置为不能加排它锁 */
return NULL;
}
/* 设置读写标志 */
dbf->read_write = (flags & GDBM_OPENMASK);
/* 若我们有一个排它锁,且打开标志为GDBM_NEWDB,则要截断文件,即把文件长度设为0,丢弃已有内容 */
if (need_trunc && file_stat.st_size != 0)
{
TRUNCATE (dbf); /* 截断文件,参看system.h */
fstat (dbf->desc, &file_stat); /* 重新获得文件的状态信息 */
}
/* 确定它是新文件还是旧文件 */
if (file_stat.st_size == 0) /* 是一个新文件,创建一个新数据库  */
{
/* 先设置内存和磁盘间传递块的大小,不能小于512字节 */
if (block_size < 512)
file_block_size = STATBLKSIZE; /* 参看system.h */
else
file_block_size = block_size;
/* 为文件头分配空间 */
dbf->header = (gdbm_file_header *) malloc (file_block_size);
if (dbf->header == NULL)
{
gdbm_close (dbf);
gdbm_errno = GDBM_MALLOC_ERROR;
return NULL;
}
/* 设置文件头的魔数和传递块的大小 */
dbf->header->header_magic = 0x13579ace;
dbf->header->block_size = file_block_size;

/* 创建初始的散列桶目录表  */
dbf->header->dir_size = 8 * sizeof (off_t); /* 初始的目录表大小 */
dbf->header->dir_bits = 3; /* 初始时目录地址占用的比特数为3位 */
while (dbf->header->dir_size < dbf->header->block_size) /* 使得目录表大小与传递块的大小相等 */
{
dbf->header->dir_size <<= 1;
dbf->header->dir_bits += 1;
} /* 最后dir_size=block_size=2^dir_bits */
/* 检查目录项的正确性 */
if (dbf->header->dir_size != dbf->header->block_size)
{
gdbm_close (dbf);
gdbm_errno = GDBM_BLOCK_SIZE_ERROR; /* 传递块大小错误 */
return NULL;
}
/* 为散列桶目录表分配空间 */
dbf->dir = (off_t *) malloc (dbf->header->dir_size);
if (dbf->dir == NULL)
{
gdbm_close (dbf);
gdbm_errno = GDBM_MALLOC_ERROR;
return NULL;
}
dbf->header->dir = dbf->header->block_size; /* 指向目录表起始地址 */
/* 创建首个也是唯一的散列桶 */
dbf->header->bucket_elems =
(dbf->header->block_size - sizeof (hash_bucket))
/ sizeof (bucket_element) + 1; /* 计算桶中元素的个数 */
dbf->header->bucket_size  = dbf->header->block_size; /* 桶的大小为传递块的大小 */
dbf->bucket = (hash_bucket *) malloc (dbf->header->bucket_size); /* 为桶分配内存空间 */
if (dbf->bucket == NULL)
{
gdbm_close (dbf);
gdbm_errno = GDBM_MALLOC_ERROR;
return NULL;
}
_gdbm_new_bucket (dbf, dbf->bucket, 0); /* 初始化这个新桶 */
dbf->bucket->av_count = 1; /* 设置桶对应可用块的个数 */
dbf->bucket->bucket_avail[0].av_adr = 3*dbf->header->block_size;
dbf->bucket->bucket_avail[0].av_size = dbf->header->block_size;
/* 目录表中的每个目录项指向一个散列桶 */
for (index = 0; index < dbf->header->dir_size / sizeof (off_t); index++)
dbf->dir[index] = 2*dbf->header->block_size;
/* 初始化活动的可用块 */
dbf->header->avail.size
= ( (dbf->header->block_size - sizeof (gdbm_file_header))
/ sizeof (avail_elem)) + 1; /* 可用块中可用块元素的个数 */
dbf->header->avail.count = 0;
dbf->header->avail.next_block = 0; /* 下一个可用块的偏移地址 */
dbf->header->next_block  = 4*dbf->header->block_size;
/* 将初始化配置信息写入文件 */
/* 块0是文件头和活动的可用块 */
num_bytes = write (dbf->desc, dbf->header, dbf->header->block_size); /* block_size一般为1024 */
if (num_bytes != dbf->header->block_size) /* 实际必须要写入block_size个字节,否则出错 */
{
gdbm_close (dbf);
gdbm_errno = GDBM_FILE_WRITE_ERROR; /* 文件写入错误 */
return NULL;
}
/* 块1是初始的散列桶目录表 */
num_bytes = write (dbf->desc, dbf->dir, dbf->header->dir_size);
if (num_bytes != dbf->header->dir_size)
{
gdbm_close (dbf);
gdbm_errno = GDBM_FILE_WRITE_ERROR;
return NULL;
}
/* 块2是这个唯一的桶 */
num_bytes = write (dbf->desc, dbf->bucket, dbf->header->bucket_size);
if (num_bytes != dbf->header->bucket_size)
{
gdbm_close (dbf);
gdbm_errno = GDBM_FILE_WRITE_ERROR;
return NULL;
}
/* 等待初始化配置信息被写入磁盘 */
fsync (dbf->desc);
free (dbf->bucket);
}
else /* 否则是一个已经存在的数据,从其文件头中读取信息,然后初始化散列目录 */
{
gdbm_file_header partial_header;  /* 第1部分 */
/* 读取文件头部分 */
num_bytes = read (dbf->desc, &partial_header, sizeof (gdbm_file_header));
if (num_bytes != sizeof (gdbm_file_header))
{
gdbm_close (dbf);
gdbm_errno = GDBM_FILE_READ_ERROR; /* 读取文件错误 */
return NULL;
}
/* 用魔数来校验文件的头是否完好 */
if (partial_header.header_magic != 0x13579ace)
{
gdbm_close (dbf);
gdbm_errno = GDBM_BAD_MAGIC_NUMBER; /* 文件头校验出错 */
return NULL;
}
/* 是一个完好的数据,则读取整个文件头 */
dbf->header = (gdbm_file_header *) malloc (partial_header.block_size);
if (dbf->header == NULL)
{
gdbm_close (dbf);
gdbm_errno = GDBM_MALLOC_ERROR;
return NULL;
}
bcopy (&partial_header, dbf->header, sizeof (gdbm_file_header));
num_bytes = read (dbf->desc, &dbf->header->avail.av_table[1],
dbf->header->block_size-sizeof (gdbm_file_header));
if (num_bytes != dbf->header->block_size-sizeof (gdbm_file_header))
{
gdbm_close (dbf);
gdbm_errno = GDBM_FILE_READ_ERROR;
return NULL;
}

/* 为散列表目录分配空间  */
dbf->dir = (off_t *) malloc (dbf->header->dir_size);
if (dbf->dir == NULL)
{
gdbm_close (dbf);
gdbm_errno = GDBM_MALLOC_ERROR;
return NULL;
}
/* 读取散列表目录 */
file_pos = lseek (dbf->desc, dbf->header->dir, L_SET); /* L_SET表示一个绝对位置 */
if (file_pos != dbf->header->dir)
{
gdbm_close (dbf);
gdbm_errno = GDBM_FILE_SEEK_ERROR;
return NULL;
}
num_bytes = read (dbf->desc, dbf->dir, dbf->header->dir_size);
if (num_bytes != dbf->header->dir_size)
{
gdbm_close (dbf);
gdbm_errno = GDBM_FILE_READ_ERROR;
return NULL;
}
}
/* 完成dbf的初始化 */
dbf->last_read = -1;
dbf->bucket = NULL;
dbf->bucket_dir = 0;
dbf->cache_entry = NULL;
dbf->header_changed = FALSE;
dbf->directory_changed = FALSE;
dbf->bucket_changed = FALSE;
dbf->second_changed = FALSE;

/* 大功告成,返回文件信息结构的指针  */
return dbf;
}
/* 桶缓存的初始化工作:为缓存分配空间,初始化每个缓存项,初始化缓存项持有的桶和数据缓存元素,
设置文件的桶缓存指针、缓存大小、当前桶及当前缓存项等 */
int
_gdbm_init_cache(dbf, size)
gdbm_file_info *dbf;    /* 数据库文件结构的指针 */
int size;               /* 缓存的大小(即缓存项的个数) */
{
register int index;
if (dbf->bucket_cache == NULL)
{ /* 为缓存分配内存空间 */
dbf->bucket_cache = (cache_elem *) malloc(sizeof(cache_elem) * size);
if(dbf->bucket_cache == NULL)
{
gdbm_errno = GDBM_MALLOC_ERROR; /* 设置内存分配错误标志 */
return(-1);
}
dbf->cache_size = size; /* 设置缓存项的个数 */
for(index = 0; index < size; index++) /* 初始化每个缓存项及其中的数据缓存元素 */
{
(dbf->bucket_cache[index]).ca_bucket
= (hash_bucket *) malloc (dbf->header->bucket_size); /* 为桶分配内存空间 */
if ((dbf->bucket_cache[index]).ca_bucket == NULL)
{
gdbm_errno = GDBM_MALLOC_ERROR;  /* 设置内存分配错误标志 */
return(-1);
}
(dbf->bucket_cache[index]).ca_adr = 0; /* 缓存项的偏移地址初始化为0 */
(dbf->bucket_cache[index]).ca_changed = FALSE; /* 更改标志初始为FALSE */
(dbf->bucket_cache[index]).ca_data.hash_val = -1; /* 数据缓存元素的哈希值初始化为-1 */
(dbf->bucket_cache[index]).ca_data.elem_loc = -1; /* 数据缓存元素的位置偏移初始化为-1 */
(dbf->bucket_cache[index]).ca_data.dptr = NULL;   /* 数据缓存元素的数据起点初始化NULL */
}
dbf->bucket = dbf->bucket_cache[0].ca_bucket;  /* 文件的当前桶设为缓存中的第一个实际桶 */
dbf->cache_entry = &dbf->bucket_cache[0]; /* 文件的当前缓存项设为第一个缓存项 */
}
return(0);
}


(3)gdbm_close.c中的唯一一个函数void gdbm_close(dbf)。dbf为事先打开的数据库文件句柄。

执行流程如下:

1)确保未写入的数据全部写入到磁盘;

2)若加了锁,则对文件解锁;

3)关闭文件,释放文件名和散列目录表;

4)对每个缓存项,释放其持有的桶、其数据缓存元素中的数据;

5)释放整个桶缓存(即所有的缓存项);

6)最后释放文件头和文件信息结构。

/* gdbmclose.c - 关闭一个事先打开的dbm文件 */
#include "autoconf.h"   /* 包含平台相关头文件和函数的常量标志 */
#include "gdbmdefs.h"   /* 包含桶、缓存项、数据库文件结构的定义
所有平台相关的头文件和函数声明、gdbm的所有函数声明和要用到的常量也在这里 */
/* 关闭dbm文件,并释放与dbf关联的所有内存。在释放dbf的成员之前,要检查并确保它们被分配了空间 */
void
gdbm_close (dbf)
gdbm_file_info *dbf;
{
register int index;	/* 用来释放桶缓存的索引 */
/* 确保数据库已经全部写入了磁盘 */
if (dbf->read_write != GDBM_READER)
fsync (dbf->desc); /* 将未写入的数据全部写入磁盘 */
/* 关闭文件并且释放所有的被分配的内存 */
if (dbf->file_locking)
{
UNLOCK_FILE(dbf); /* 对文件解锁 */
}
close (dbf->desc); /* 关闭文件 */
free (dbf->name);  /* 释放文件名 */
if (dbf->dir != NULL) free (dbf->dir); /* 释放散列目录表 */
if (dbf->bucket_cache != NULL) {
for (index = 0; index < dbf->cache_size; index++) { /* 释放每个缓存项中的相应域 */
if (dbf->bucket_cache[index].ca_bucket != NULL)
free (dbf->bucket_cache[index].ca_bucket);   /* 释放缓存项所持有的桶 */
if (dbf->bucket_cache[index].ca_data.dptr != NULL)
free (dbf->bucket_cache[index].ca_data.dptr); /* 释放缓存项中数据缓存元素的数据 */
}
free (dbf->bucket_cache); /* 释放整个桶缓存 */
}
if ( dbf->header != NULL ) free (dbf->header); /* 释放文件头 */
free (dbf); /* 最后释放文件信息结构 */
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: