Merge branch 'db/diff-to-fp'
[git/jnareb-git.git] / Documentation / technical / racy-git.txt
blob6bdf034b3af55c8d881fee9153d5cd1824660692
1 Use of index and Racy git problem
2 =================================
4 Background
5 ----------
7 The index is one of the most important data structures in git.
8 It represents a virtual working tree state by recording list of
9 paths and their object names and serves as a staging area to
10 write out the next tree object to be committed.  The state is
11 "virtual" in the sense that it does not necessarily have to, and
12 often does not, match the files in the working tree.
14 There are cases git needs to examine the differences between the
15 virtual working tree state in the index and the files in the
16 working tree.  The most obvious case is when the user asks `git
17 diff` (or its low level implementation, `git diff-files`) or
18 `git-ls-files --modified`.  In addition, git internally checks
19 if the files in the working tree are different from what are
20 recorded in the index to avoid stomping on local changes in them
21 during patch application, switching branches, and merging.
23 In order to speed up this comparison between the files in the
24 working tree and the index entries, the index entries record the
25 information obtained from the filesystem via `lstat(2)` system
26 call when they were last updated.  When checking if they differ,
27 git first runs `lstat(2)` on the files and compares the result
28 with this information (this is what was originally done by the
29 `ce_match_stat()` function, but the current code does it in
30 `ce_match_stat_basic()` function).  If some of these "cached
31 stat information" fields do not match, git can tell that the
32 files are modified without even looking at their contents.
34 Note: not all members in `struct stat` obtained via `lstat(2)`
35 are used for this comparison.  For example, `st_atime` obviously
36 is not useful.  Currently, git compares the file type (regular
37 files vs symbolic links) and executable bits (only for regular
38 files) from `st_mode` member, `st_mtime` and `st_ctime`
39 timestamps, `st_uid`, `st_gid`, `st_ino`, and `st_size` members.
40 With a `USE_STDEV` compile-time option, `st_dev` is also
41 compared, but this is not enabled by default because this member
42 is not stable on network filesystems.  With `USE_NSEC`
43 compile-time option, `st_mtim.tv_nsec` and `st_ctim.tv_nsec`
44 members are also compared, but this is not enabled by default
45 because the value of this member becomes meaningless once the
46 inode is evicted from the inode cache on filesystems that do not
47 store it on disk.
50 Racy git
51 --------
53 There is one slight problem with the optimization based on the
54 cached stat information.  Consider this sequence:
56   : modify 'foo'
57   $ git update-index 'foo'
58   : modify 'foo' again, in-place, without changing its size
60 The first `update-index` computes the object name of the
61 contents of file `foo` and updates the index entry for `foo`
62 along with the `struct stat` information.  If the modification
63 that follows it happens very fast so that the file's `st_mtime`
64 timestamp does not change, after this sequence, the cached stat
65 information the index entry records still exactly match what you
66 would see in the filesystem, even though the file `foo` is now
67 different.
68 This way, git can incorrectly think files in the working tree
69 are unmodified even though they actually are.  This is called
70 the "racy git" problem (discovered by Pasky), and the entries
71 that appear clean when they may not be because of this problem
72 are called "racily clean".
74 To avoid this problem, git does two things:
76 . When the cached stat information says the file has not been
77   modified, and the `st_mtime` is the same as (or newer than)
78   the timestamp of the index file itself (which is the time `git
79   update-index foo` finished running in the above example), it
80   also compares the contents with the object registered in the
81   index entry to make sure they match.
83 . When the index file is updated that contains racily clean
84   entries, cached `st_size` information is truncated to zero
85   before writing a new version of the index file.
87 Because the index file itself is written after collecting all
88 the stat information from updated paths, `st_mtime` timestamp of
89 it is usually the same as or newer than any of the paths the
90 index contains.  And no matter how quick the modification that
91 follows `git update-index foo` finishes, the resulting
92 `st_mtime` timestamp on `foo` cannot get a value earlier
93 than the index file.  Therefore, index entries that can be
94 racily clean are limited to the ones that have the same
95 timestamp as the index file itself.
97 The callers that want to check if an index entry matches the
98 corresponding file in the working tree continue to call
99 `ce_match_stat()`, but with this change, `ce_match_stat()` uses
100 `ce_modified_check_fs()` to see if racily clean ones are
101 actually clean after comparing the cached stat information using
102 `ce_match_stat_basic()`.
104 The problem the latter solves is this sequence:
106   $ git update-index 'foo'
107   : modify 'foo' in-place without changing its size
108   : wait for enough time
109   $ git update-index 'bar'
111 Without the latter, the timestamp of the index file gets a newer
112 value, and falsely clean entry `foo` would not be caught by the
113 timestamp comparison check done with the former logic anymore.
114 The latter makes sure that the cached stat information for `foo`
115 would never match with the file in the working tree, so later
116 checks by `ce_match_stat_basic()` would report that the index entry
117 does not match the file and git does not have to fall back on more
118 expensive `ce_modified_check_fs()`.
121 Runtime penalty
122 ---------------
124 The runtime penalty of falling back to `ce_modified_check_fs()`
125 from `ce_match_stat()` can be very expensive when there are many
126 racily clean entries.  An obvious way to artificially create
127 this situation is to give the same timestamp to all the files in
128 the working tree in a large project, run `git update-index` on
129 them, and give the same timestamp to the index file:
131   $ date >.datestamp
132   $ git ls-files | xargs touch -r .datestamp
133   $ git ls-files | git update-index --stdin
134   $ touch -r .datestamp .git/index
136 This will make all index entries racily clean.  The linux-2.6
137 project, for example, there are over 20,000 files in the working
138 tree.  On my Athron 64X2 3800+, after the above:
140   $ /usr/bin/time git diff-files
141   1.68user 0.54system 0:02.22elapsed 100%CPU (0avgtext+0avgdata 0maxresident)k
142   0inputs+0outputs (0major+67111minor)pagefaults 0swaps
143   $ git update-index MAINTAINERS
144   $ /usr/bin/time git diff-files
145   0.02user 0.12system 0:00.14elapsed 100%CPU (0avgtext+0avgdata 0maxresident)k
146   0inputs+0outputs (0major+935minor)pagefaults 0swaps
148 Running `git update-index` in the middle checked the racily
149 clean entries, and left the cached `st_mtime` for all the paths
150 intact because they were actually clean (so this step took about
151 the same amount of time as the first `git diff-files`).  After
152 that, they are not racily clean anymore but are truly clean, so
153 the second invocation of `git diff-files` fully took advantage
154 of the cached stat information.
157 Avoiding runtime penalty
158 ------------------------
160 In order to avoid the above runtime penalty, post 1.4.2 git used
161 to have a code that made sure the index file
162 got timestamp newer than the youngest files in the index when
163 there are many young files with the same timestamp as the
164 resulting index file would otherwise would have by waiting
165 before finishing writing the index file out.
167 I suspected that in practice the situation where many paths in the
168 index are all racily clean was quite rare.  The only code paths
169 that can record recent timestamp for large number of paths are:
171 . Initial `git add .` of a large project.
173 . `git checkout` of a large project from an empty index into an
174   unpopulated working tree.
176 Note: switching branches with `git checkout` keeps the cached
177 stat information of existing working tree files that are the
178 same between the current branch and the new branch, which are
179 all older than the resulting index file, and they will not
180 become racily clean.  Only the files that are actually checked
181 out can become racily clean.
183 In a large project where raciness avoidance cost really matters,
184 however, the initial computation of all object names in the
185 index takes more than one second, and the index file is written
186 out after all that happens.  Therefore the timestamp of the
187 index file will be more than one seconds later than the
188 youngest file in the working tree.  This means that in these
189 cases there actually will not be any racily clean entry in
190 the resulting index.
192 Based on this discussion, the current code does not use the
193 "workaround" to avoid the runtime penalty that does not exist in
194 practice anymore.  This was done with commit 0fc82cff on Aug 15,
195 2006.