GIT 源码阅读之 update-cache
来源:互联网 发布:python中文乱码解决sys 编辑:程序博客网 时间:2024/05/16 14:08
说明
本文所有代码基于 GIT COMMIT e83c5163316f89bfbde7d9ab23ca2e25604af290 版本的源码,在 Ubuntu 16.04 上编译运行,部分代码有所改动。
update-cache
update-cache 是 GIT 最初版本中用于向缓存目录增加追踪文件的命令,该命令不能用于将目录添加至缓存,其使用方法为 update-cache <filename ...>
。主函数如下所示:
int main(int argc, char **argv){ int i, newfd, entries; entries = read_cache(); if (entries < 0) { perror("cache corrupted"); return -1; } newfd = open(".dircache/index.lock", O_RDWR | O_CREAT | O_EXCL, 0600); if (newfd < 0) { perror("unable to create new cachefile"); return -1; } for (i = 1; i < argc; i++) { char *path = argv[i]; if (!verify_path(path)) { fprintf(stderr, "Ignoring path %s\n", argv[i]); continue; } if (add_file_to_cache(path)) { fprintf(stderr, "Unable to add %s to database\n", path); goto out; } } if (!write_cache(newfd, active_cache, active_nr) && !rename(".dircache/index.lock", ".dircache/index")) return 0; out: unlink(".dircache/index.lock");}
程序运行时,首先会通过 read_cache()
函数加载存储在 .dircache/index 中的文件信息。接着程序会在 .dircache 目录下新建 index.lock 文件用于保存当前文件的缓存信息。然后通过 add_file_to_cache()
函数将命令行中指定的文件添加到缓存对象中。最后通过 write_cache()
函数将缓存信息写入到 .dircache/index.lock 文件中,并重命名为 .dircache/index 完成添加文件到缓存中的功能。
接下来我们看看 read_cache()
函数,该函数负责将存储在 .dircache/index 中的文件信息载入内存并保存至全局变量 active_cache
数组中。因此,我们需要先了解 .dircache/index 的文件结果。 .dircache/index 在文件头部会存放文件实例的信息 cache_header
,其定义如下:
struct cache_header { unsigned int signature; unsigned int version; unsigned int entries; unsigned char sha1[20];};
- signature 签名标识,固定为 0x44495243 ,即 DIRC 的十六进制形式。
- version 版本标识。
- entries 文件总个数。
- sha1 校验信息,index 文件中去除 sha1 自身的所有数据的 SHA1 值。
read_cache()
函数源码如下所示:
int read_cache(void){ int fd, i; struct stat st; unsigned long size, offset; void *map; struct cache_header *hdr; errno = EBUSY; /* 有什么用?*/ if (active_cache) return error("more than on cachefile"); errno = ENOENT; sha1_file_directory = getenv(DB_ENVIRONMENT); if (!sha1_file_directory) sha1_file_directory = DEFAULT_DB_ENVIRONMENT; if (access(sha1_file_directory, X_OK) < 0) return error("no access to SHA1 file directory"); fd = open(".dircache/index", O_RDONLY); if (fd < 0) return (errno == ENOENT) ? 0 : error("open failed"); map = (void *)-1; if (!fstat(fd, &st)) { map = NULL; size = st.st_size; errno = EINVAL; if (size > sizeof(struct cache_header)) map = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); } close(fd); if (-1 == (int)(long)map) return error("mmap failed"); hdr = map; if (verify_hdr(hdr, size) < 0) goto unmap; active_nr = hdr->entries; active_alloc = alloc_nr(active_nr); active_cache = calloc(active_alloc, sizeof(struct cache_entry *)); offset = sizeof(*hdr); for (i = 0; i < hdr->entries; i++) { struct cache_entry *ce = map + offset; offset = offset + ce_size(ce); active_cache[i] = ce; } return active_nr; unmap: munmap(map, size); errno = EINVAL; return error("verify header failed");}
该函数中需要设置 errno 的值,关于这些值有什么作用我个人并不是很清楚。 read_cache()
函数首先会检测是否已经载入过 .dircache/index 到 active_cache
中,同时需要判断能否访问 .dircache/objects 目录。接着,该函数通过 mmap()
函数将 .dircache/index 映射到内存中并通过 verify_hdr()
校验信息的正确性。最后将 .dircache/index 文件实例依次载入到 active_cache
数组中。 add_file_to_cache()
函数负责将文件添加到缓存 active_cache
数组中,其函数定义如下:
static int add_file_to_cache(char *path){ int size, namelen; struct cache_entry *ce; struct stat st; int fd; fd = open(path, O_RDONLY); if (fd < 0) { if (errno == ENOENT) return remove_file_from_cache(path); return -1; } if (fstat(fd, &st) < 0) { close(fd); return -1; } namelen = strlen(path); size = cache_entry_size(namelen); ce = malloc(size); memset(ce, 0, size); memcpy(ce->name, path, namelen); ce->ctime.sec = st.st_ctime; ce->ctime.nsec = st.st_ctim.tv_nsec; ce->mtime.sec = st.st_mtime; ce->mtime.nsec = st.st_mtim.tv_nsec; ce->st_dev = st.st_dev; ce->st_ino = st.st_ino; ce->st_mode = st.st_mode; ce->st_uid = st.st_uid; ce->st_gid = st.st_gid; ce->st_size = st.st_size; ce->namelen = namelen; if (index_fd(path, namelen, ce, fd, &st) < 0) return -1; return add_cache_entry(ce);}
该函数接收一个文件路径参数,若该文件不存在,它会试图将 active_cache
中相同路径的文件信息移除。否则它将创建并填充 cache_entry
结构,同时将文件进行压缩并存储到压缩后的 SHA1 值对应的文件中(备注:在压缩前加入了 blob 字符串,size 为文件大小)。最后,通过将新建的 cache_entry
信息加入到 active_cache
中(根据路径名进行快速排序)。
write_cache()
函数负责将内存中 active_cache
的内容写入到磁盘文件中,其定义如下:
static int write_cache(int newfd, struct cache_entry **cache, int entries){ SHA_CTX c; struct cache_header hdr; int i; hdr.signature = CACHE_SIGNATURE; hdr.version = 1; hdr.entries = entries; SHA1_Init(&c); SHA1_Update(&c, &hdr, offsetof(struct cache_header, sha1)); for (i = 0; i < entries; i++) { struct cache_entry *ce = cache[i]; int size = ce_size(ce); SHA1_Update(&c, ce, size); } SHA1_Final(hdr.sha1, &c); if (write(newfd, &hdr, sizeof(hdr)) != sizeof(hdr)) return -1; for (i = 0; i < entries; i++) { struct cache_entry *ce = cache[i]; int size = ce_size(ce); if (write(newfd, ce, size) != size) return -1; } return 0;}
该函数对 cache_header
中除 sha1
字段以及 active_cache
所有的 cache_entry
计算 SHA1 值并保存至 cache_header
的 sha1
字段中。接着将头信息写入文件,最后遍历 active_cache
并写入所有的 cache_entry
信息。
- GIT 源码阅读之 update-cache
- Bucket Cache源码阅读
- GIT 源码阅读之 init-db
- GIT 源码阅读之 cat-file
- GPGPU-Sim 源码阅读笔记 之 cache option默认策略
- LRU Cache 暨LinkedHashMap源码阅读
- Spark源码阅读笔记:Spark的数据系统之cache篇
- 源码阅读之ArrayList
- 源码阅读之Vector
- Universal-Image-Loader源码阅读(12)-cache/BaseMemoryCache
- Universal-Image-Loader源码阅读(13)-cache/LimitedMemoryCache
- nginx源码阅读(四).创建子进程(worker和cache)
- OBS源码阅读笔记--取出licence和update
- Spring 源码阅读之BeanFactory
- Azkaban源码阅读之AzkabanApplication
- Azkaban源码阅读之CachingFlowManager
- 源码阅读之函数指针
- JDK源码阅读之ArrayList
- namenode工作模式
- hdu 5706 GirlCat
- TCP/IP 详解卷一学习笔记(一):TCP/IP 协议基本概念
- HDU 4614Vases and Flowers(线段树)
- 29.两个整数相除
- GIT 源码阅读之 update-cache
- mysql 命令安装zip版本总结
- 网页加载速度提升——大总结(未完待续)
- Androidstudio查不出具体哪行报错解决办法
- http://blog.csdn.net/erfucun/article/details/52269610
- Python3爬虫--阶段性成果
- Spring3.1.0实现原理分析(十九).MVC异常处理
- Android异常捕获篇(下)---retrofit实现文件的上传
- Extern C {}