More Related Content
Similar to コード読経会報告書 (20)
コード読経会報告書
- 6. 各プログラム解説
• init-db : キャッシュフォルダの初期化(git initっぽいもの)
• update-cache : トレースファイルの追加、更新(git addっぽいもの)
• write-tree : treeの作成(git commitっぽいもの)
• commit-tree : データベースへ登録(git pushっぽいもの)
• cat-file : ファイル名の表示
• read-tree : tree内容の出力
• show-diff : 最新コミットとの差異(git diff)
- 7. まずは動かす
• % ./init-db
• % ./update-cache README
• % ./write-tree
• % ./commit-tree
• READMEを編集
• % ./show_diff
• % ./update-cache README
• % ./write-tree
• % ./commit-tree
• % ./show_diff
- 10. cache_header
•in cache.h
#define CACHE_SIGNATURE 0x44495243 /* "DIRC" */
struct cache_header {
unsigned int signature;
unsigned int version;
unsigned int entries;
unsigned char sha1[20];
};
!
• キャッシュ(ファイルの状態を一時保存する構造)のヘッダ
• バージョンとエントリ数を持ち、そこから一意に決まるsha1を持つ
- 11. cache_entry
• in cache.h
struct cache_entry {
struct cache_time ctime;
struct cache_time mtime;
unsigned int st_dev;
unsigned int st_ino;
unsigned int st_mode;
unsigned int st_uid;
unsigned int st_gid;
unsigned int st_size;
unsigned char sha1[20];
unsigned short namelen;
unsigned char name[0];
};
!
• キャッシュに含まれるファイルの場所を指し示すポインタのようなもの
• nameが0なのは長さを自由に設定するため。こんな使い方初めて見た!すごいぞ!トーパルズ!
- 12. 作業メモ:cache.h
• データ構造
• cache_header
• キャッシュの種類等を示す?
• cache_time
• キャッシュが保存された時間
• cache_entry
• データそのもの?
• 不明点
• 58: unsigned char name[0];
- 14. init-db.c (1)
• キャッシュを格納するフォルダを決定する
• 環境変数にSHA1のフォルダがあればそれを使う
• フォルダ環境変数を使ってひとまとめにするかどうか決められる
• 環境変数でまとめることで、PCに固有なキャッシュフォルダができる
!
• 作業メモ:知らなかった関数達
• getenv : 環境変数を取得
• stat : ファイル、ディレクトリの状態を取得
• errno : マクロ、エラーが起きると0以外になる
- 16. update-cache.c
関数の流れ
• main()
• read_cache() : 最新キャッシュを読む
• indexをロック
• verify_path() : 入力されたファイルを確認する
• add_file_to_cache() : ファイルをキャッシュに変換
• write_cache() : キャッシュを書き込む
- 17. read_cache()
• .dircache/indexには最新のキャッシュのインデックスが保存されている
• read_cacheでは、indexから、最新のキャッシュをメモリに読み込む
1. インデックスの読み込み
2. メモリにマップ
3. ヘッダのチェック
4. メモリの確保
5. エントリのロード
!
• 以下作業メモ
• void *型 あらゆるポインタ型に変換できる型
• if (-1 == (int)(long)map)
• return error("mmap failed");
• mapを、NULLか、なにか入っている場合はindexのアドレスに設定する
• #define alloc_nr(x) (((x)+16)*3/2) : ちょっと多めにメモリ確保、わかりづれぇよ、トーパルズ
- 19. verify_hdr()
• verify_hdr : 正しいcache_headerかチェック
!
SHA1_Init(&c);
SHA1_Update(&c, hdr, offsetof(struct cache_header, sha1));
SHA1_Update(&c, hdr+1, size - sizeof(*hdr));
SHA1_Final(sha1, &c);
if (memcmp(sha1, hdr->sha1, 20))
return error("bad header sha1");
!
• cache-headerからSHA1生成、cache-headerのSHA1と合っているかチェック
- 20. read_cache()
• バグを発見
!
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);
}
!
• mapがNULLだとその後のverify_hdrでセグフォる
- 21. 作業メモ:read-cache.c
• active_cache : cache_entry
!
• 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”);
!
• indexがなければreturn 0 (正常終了)
- 23. 作業メモ:update-cache.c
• 関数のstatic宣言 : ファイル外から参照不可
• read-cacheで、最新のコミットを読み込み
• 全ての引数を正しいパスかチェック
• verify_pathで正しいPATHが指定されているかチェック
• add_cache_entry
• もし、指定されたPATHにファイルがなく、さらにキャッシュ上に
ファイルが存在するならそのファイルをキャッシュ上から削除する
• PATHからキャッシュエントリを生成
- 24. 作業メモ:update-cache.c
• #define cache_entry_size(len) ((offsetof(struct
cache_entry,name) + (len) + 8) & ~7)
• 下位3ビットを000にする
• メモリ上のentryの区切りを示す。
- 26. 作業メモ:update-cache.c
• /* Add it in.. */
• active_nr++;
• if (active_nr > pos)
• memmove(active_cache + pos + 1, active_cache + pos,
(active_nr - pos - 1) * sizeof(ce));
• active_cache[pos] = ce;
• return 0;
• posに入れるために後ろをずらす
- 27. 読経終わり
• 今回積んだ功徳
• cache.h(93)
• init-db.c (51)
• update-cache.c (254)
• read-cache.c (266)
• 664行
- 28. まとめ
• プログラム自体について
• メモリの使い方が神がかっている
• データ保存のアイディアがすごい
• SHA1をファイルにして保存、こうすると高速化できる??
• 読経会について
• モチベーションが高まる、楽しい!
• 関数の細かいところに時間をかけすぎた、次回はもっと大雑把に読みたい
• なぜこういう設計にしたのか?という考察をしたい
• 開発された経緯、設計の理由を知りたい
• プログラムで何を、どのように抽象化しているのかということをもっと意識して読みたい
- 29. 資料:コンパイル関連
• git clone https://github.com/git/git
• git checkout e83c5163
• zlibとcryptoをリンク(LIBS += -lz -lcrypto)
• st_mtimでエラー→st_mtimespec
• st_ctimでエラー→st_ctimespec