摘要:
本文深入源码分析了Coffee文件删除文件cfs_remove技术细节,包括remove_by_page、COFFEE_EXTENDED_WEAR_LEVELLING。
一、cfs_remove
Coffee文件系统删除文件cfs_remove,删除成功返回0,否则返回-1。cfs_remove首先找到name对应的文件file指针(find_file函数),而后调用remove_by_page删除文件,源码如下:
- int cfs_remove(const char *name)
-
{
-
struct file *file;
-
-
file = find_file(name);
-
if(file == NULL)
-
{
-
return - 1;
-
}
-
-
return remove_by_page(file->page, REMOVE_LOG, CLOSE_FDS, ALLOW_GC);
-
}
find_file函数用于找到文件名name对应的file指针。若name对应的文件file还驻留在内存(即还在coffee_files[COFFEE_MAX_OPEN_FILES]数组里),并且对应的物理文件是有效的,则直接返回file指针,否则扫描整个FLASH,将name对应文件file(在FLASH中但没缓存)缓存到内存(这一步得确保coffee_files数组有可用的项,否则返回空NULL,参见load_file函数)。详情见博文《Contiki学习笔记:Coffee文件系统打开文件cfs_open》二。这个有点纳闷了,删除文件,事先得把file_header缓存。
二、remove_by_page
remove_by_page,删除微日志文件(如果有的话),将文件头file_header的flags中的O位(isolated,孤立)置1,更新file_header,将该文件关联的file_desc的flags设为COFFEE_FD_FREE和初始化file结构体,必要时(COFFEE_EXTENDED_WEAR_LEVELLING为0且gc_allowed为1)进行垃圾回收。
值得一提的是,通过将文件头file_header的flags中的O位置1,虽表示文件已删除,但此时,文件占用的空间还不能被使用(还没擦写),只有垃圾回收处理后才能使用,而垃圾回收只有当存储空间不足时才执行。源码如下:
- //return remove_by_page(file->page, REMOVE_LOG, CLOSE_FDS, ALLOW_GC);
-
static int remove_by_page(coffee_page_t page, int remove_log, int close_fds, int gc_allowed) //2.1
-
{
-
struct file_header hdr;
-
int i;
-
-
read_header(&hdr, page);//read_header用于读取物理文件的元数据(即file_header)
-
if (!HDR_ACTIVE(hdr)) //若A为1,O为0,I为0,则HDR_ACTIVE返回真
-
{
-
return - 1;
-
}
-
-
/***删除微日志文件***/
-
if (remove_log && HDR_MODIFIED(hdr))
-
{
-
if (remove_by_page(hdr.log_page, !REMOVE_LOG, !CLOSE_FDS, !ALLOW_GC) < 0)
-
{
-
return - 1;
-
}
-
}
-
-
hdr.flags |= HDR_FLAG_OBSOLETE; //标志为失效页
-
write_header(&hdr, page); //更新物理的file_header
-
*gc_wait = 0;
-
-
/***将待删除文件相关联的file_desc中flags设为COFFEE_FD_FREE(一个文件可能被多次打开,如多线程)***/
-
if (close_fds)
-
{
-
for (i = 0; i < COFFEE_FD_SET_SIZE; i++)
-
{
-
if (coffee_fd_set[i].file != NULL && coffee_fd_set[i].file->page == page)
-
{
-
coffee_fd_set[i].flags = COFFEE_FD_FREE;
-
}
-
}
-
}
-
-
/***将待删除文件相关联的file初始化,变为可用***/
-
for (i = 0; i < COFFEE_MAX_OPEN_FILES; i++)
-
{
-
if (coffee_files[i].page == page)
-
{
-
coffee_files[i].page = INVALID_PAGE;
-
coffee_files[i].references = 0;
-
coffee_files[i].max_pages = 0;
-
}
-
}
-
-
/***没有配置COFFEE_EXTENDED_WEAR_LEVELLING且gc_allowed为1,则进行垃圾回收,见2.2***/
-
#if !COFFEE_EXTENDED_WEAR_LEVELLING
-
if (gc_allowed)
-
{
-
collect_garbage(GC_RELUCTANT);
-
}
-
#endif
-
-
return 0; //邮件成功返回0
-
}
2.1 remove_by_page参数
删除文件cfs_remove传给remove_by_page参数分别是file->page、REMOVE_LOG、CLOSE_FDS、ALLOW_GC,如下:
- //return remove_by_page(file->page, REMOVE_LOG, CLOSE_FDS, ALLOW_GC);
-
-
#define REMOVE_LOG 1 //删除微日志文件
-
#define CLOSE_FDS 1 //关闭FD,事实上是将file_desc的flags设为COFFEE_FD_FREE
-
#define ALLOW_GC 1 //允许垃圾回收,得确保COFFEE_EXTENDED_WEAR_LEVELLING为0,才会进行垃圾回收
2.2 COFFEE_EXTENDED_WEAR_LEVELLING
Coffee文件系统默认是配置了COFFEE_EXTENDED_WEAR_LEVELLING,源码如下。在本例,文件删除并没有立即进行垃圾回收,而是待到没有空间可用的时候再回收(可理解成批处理),显然这样做有一个明显的缺点,垃圾回收会占用比较长的时间。
- #ifndef COFFEE_EXTENDED_WEAR_LEVELLING
-
#define COFFEE_EXTENDED_WEAR_LEVELLING 1
-
#endif
系统提供了两种垃圾回收机制:GC_GREEDY和GC_RELUCTANT,前者垃圾回收过程中,擦除尽可能多的区(即贪心回收),后者擦除一个区后就停止,删除文件采用的是后一种。两种回收机制源代码如下:
- /* "Greedy" garbage collection erases as many sectors as possible. */
-
#define GC_GREEDY 0
-
/* "Reluctant" garbage collection stops after erasing one sector. */
-
#define GC_RELUCTANT 1
参考资料:
[1] Tsiftes Nicolas,Dunkels Adam,He Zhitao.Enabling large-scale storage in sensor networks with the coffee file system[J].International Conference on Information Processing in Sensor Networks.2009,349-360
[2]
[3] Contiki源代码
阅读(2691) | 评论(0) | 转发(1) |