コード読経会報告書
Upcoming SlideShare
Loading in...5
×
 

コード読経会報告書

on

  • 50 views

 

Statistics

Views

Total Views
50
Views on SlideShare
50
Embed Views
0

Actions

Likes
1
Downloads
1
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

コード読経会報告書 コード読経会報告書 Presentation Transcript

  • ソースコード読経会 報告書 2014/09/23 参加者:熊渕健二、豊吉政彦、西田泰大 企画:豊吉
  • 今回の目的 • コーディング能力の向上 • 凄い人のコードを読めば能力向上するのでは? • 凄い人って誰だ?
  • お題
  • 会の流れ 1. コンパイル(参考資料参照の事) 2. まずは動かす 3. それぞれのファイルについて読経 4. 読経した結果はパワポでまとめ
  • 各プログラム解説 • 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)
  • まずは動かす • % ./init-db • % ./update-cache README • % ./write-tree • % ./commit-tree • READMEを編集 • % ./show_diff • % ./update-cache README • % ./write-tree • % ./commit-tree • % ./show_diff
  • Let’s 読経
  • 1. データ構造
  • 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を持つ
  • 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なのは長さを自由に設定するため。こんな使い方初めて見た!すごいぞ!トーパルズ!
  • 作業メモ:cache.h • データ構造 • cache_header • キャッシュの種類等を示す? • cache_time • キャッシュが保存された時間 • cache_entry • データそのもの? • 不明点 • 58: unsigned char name[0];
  • 2. 関数の流れ
  • init-db.c (1) • キャッシュを格納するフォルダを決定する • 環境変数にSHA1のフォルダがあればそれを使う • フォルダ環境変数を使ってひとまとめにするかどうか決められる • 環境変数でまとめることで、PCに固有なキャッシュフォルダができる ! • 作業メモ:知らなかった関数達 • getenv : 環境変数を取得 • stat : ファイル、ディレクトリの状態を取得 • errno : マクロ、エラーが起きると0以外になる
  • init-db.c(2) • 指定されたpathに、256個のフォルダを作って、00からffに ネーミングする ! ! • これが、キャッシュを格納するフォルダとなる • ちなみにフォルダ名がSHA1の頭2文字になる • init-dbは以上
  • update-cache.c 関数の流れ • main() • read_cache() : 最新キャッシュを読む • indexをロック • verify_path() : 入力されたファイルを確認する • add_file_to_cache() : ファイルをキャッシュに変換 • write_cache() : キャッシュを書き込む
  • 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) : ちょっと多めにメモリ確保、わかりづれぇよ、トーパルズ
  • read_cache() • gotoさんと遭遇
  • 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と合っているかチェック
  • 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でセグフォる
  • 作業メモ: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 (正常終了)
  • 作業メモ:read-cache.c • エントリの数からメモリを確保 • エントリをメモリ上(active_cache)に保存
  • 作業メモ:update-cache.c • 関数のstatic宣言 : ファイル外から参照不可 • read-cacheで、最新のコミットを読み込み • 全ての引数を正しいパスかチェック • verify_pathで正しいPATHが指定されているかチェック • add_cache_entry • もし、指定されたPATHにファイルがなく、さらにキャッシュ上に ファイルが存在するならそのファイルをキャッシュ上から削除する • PATHからキャッシュエントリを生成
  • 作業メモ:update-cache.c • #define cache_entry_size(len) ((offsetof(struct cache_entry,name) + (len) + 8) & ~7) • 下位3ビットを000にする • メモリ上のentryの区切りを示す。
  • 作業メモ:update-cache.c • index_fd • Zlibを使ったファイルの圧縮 • z-stream • inにファイルをmmap • zlibで圧縮 : deflate
  • 作業メモ: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に入れるために後ろをずらす
  • 読経終わり • 今回積んだ功徳 • cache.h(93) • init-db.c (51) • update-cache.c (254) • read-cache.c (266) • 664行
  • まとめ • プログラム自体について • メモリの使い方が神がかっている • データ保存のアイディアがすごい • SHA1をファイルにして保存、こうすると高速化できる?? • 読経会について • モチベーションが高まる、楽しい! • 関数の細かいところに時間をかけすぎた、次回はもっと大雑把に読みたい • なぜこういう設計にしたのか?という考察をしたい • 開発された経緯、設計の理由を知りたい • プログラムで何を、どのように抽象化しているのかということをもっと意識して読みたい
  • 資料:コンパイル関連 • git clone https://github.com/git/git • git checkout e83c5163 • zlibとcryptoをリンク(LIBS += -lz -lcrypto) • st_mtimでエラー→st_mtimespec • st_ctimでエラー→st_ctimespec