@matheusbsbs / matheus-bagliano / commits / fba2f38a2c
Fork 0

make USE_NSEC work as expected

Since the filesystem ext4 is now defined as stable in Linux v2.6.28, and ext4 supports nanonsecond resolution timestamps natively, it is time to make USE_NSEC work as expected. This will make racy git situations less likely to happen. For 'git checkout' this means it will be less likely that we have to open, read the contents of the file into RAM, and check if file is really modified or not. The result sould be a litle less used CPU time, less pagefaults and a litle faster program, at least for 'git checkout'. Since the number of possible racy git situations would increase when disks gets faster, this patch would be more and more helpfull as times go by. For a fast Solid State Disk, this patch should be helpfull. Note that, when file operations starts to take less than 1 nanosecond, one would again start to get more racy git situations. For more info on racy git, see Documentation/technical/racy-git.txt For more info on ext4, see http://kernelnewbies.org/Ext4 Signed-off-by: Kjetil Barvik <barvik@broadpark.no> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Kjetil Barvik committed Feb 19, 2009 at 21:08 UTC fba2f38a2c2cda458e490c18e0afbb12cbd37969
3 files changed +65 -19
cache.h
+3 -3
@@ -140,8 +140,8 @@ struct ondisk_cache_entry_extended {
140 };
141
142 struct cache_entry {
143 - unsigned int ce_ctime;
144 - unsigned int ce_mtime;
143 + struct cache_time ce_ctime;
144 + struct cache_time ce_mtime;
145 unsigned int ce_dev;
146 unsigned int ce_ino;
147 unsigned int ce_mode;
@@ -282,7 +282,7 @@ struct index_state {
282 struct cache_entry **cache;
283 unsigned int cache_nr, cache_alloc, cache_changed;
284 struct cache_tree *cache_tree;
285 - time_t timestamp;
285 + struct cache_time timestamp;
286 void *alloc;
287 unsigned name_hash_initialized : 1,
288 initialized : 1;
read-cache.c
+56 -14
@@ -67,8 +67,15 @@ void rename_index_entry_at(struct index_state *istate, int nr, const char *new_n
67 */
68 void fill_stat_cache_info(struct cache_entry *ce, struct stat *st)
69 {
70 - ce->ce_ctime = st->st_ctime;
71 - ce->ce_mtime = st->st_mtime;
70 + ce->ce_ctime.sec = (unsigned int)st->st_ctime;
71 + ce->ce_mtime.sec = (unsigned int)st->st_mtime;
72 +#ifdef USE_NSEC
73 + ce->ce_ctime.nsec = (unsigned int)st->st_ctim.tv_nsec;
74 + ce->ce_mtime.nsec = (unsigned int)st->st_mtim.tv_nsec;
75 +#else
76 + ce->ce_ctime.nsec = 0;
77 + ce->ce_mtime.nsec = 0;
78 +#endif
79 ce->ce_dev = st->st_dev;
80 ce->ce_ino = st->st_ino;
81 ce->ce_uid = st->st_uid;
@@ -196,11 +203,18 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st)
203 default:
204 die("internal error: ce_mode is %o", ce->ce_mode);
205 }
199 - if (ce->ce_mtime != (unsigned int) st->st_mtime)
206 + if (ce->ce_mtime.sec != (unsigned int)st->st_mtime)
207 changed |= MTIME_CHANGED;
201 - if (trust_ctime && ce->ce_ctime != (unsigned int) st->st_ctime)
208 + if (trust_ctime && ce->ce_ctime.sec != (unsigned int)st->st_ctime)
209 changed |= CTIME_CHANGED;
210
211 +#ifdef USE_NSEC
212 + if (ce->ce_mtime.nsec != (unsigned int)st->st_mtim.tv_nsec)
213 + changed |= MTIME_CHANGED;
214 + if (trust_ctime && ce->ce_ctime.nsec != (unsigned int)st->st_ctim.tv_nsec)
215 + changed |= CTIME_CHANGED;
216 +#endif
217 +
218 if (ce->ce_uid != (unsigned int) st->st_uid ||
219 ce->ce_gid != (unsigned int) st->st_gid)
220 changed |= OWNER_CHANGED;
@@ -232,8 +246,16 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st)
246 static int is_racy_timestamp(const struct index_state *istate, struct cache_entry *ce)
247 {
248 return (!S_ISGITLINK(ce->ce_mode) &&
235 - istate->timestamp &&
236 - ((unsigned int)istate->timestamp) <= ce->ce_mtime);
249 + istate->timestamp.sec &&
250 +#ifdef USE_NSEC
251 + /* nanosecond timestamped files can also be racy! */
252 + (istate->timestamp.sec < ce->ce_mtime.sec ||
253 + (istate->timestamp.sec == ce->ce_mtime.sec &&
254 + istate->timestamp.nsec <= ce->ce_mtime.nsec))
255 +#else
256 + istate->timestamp.sec <= ce->ce_mtime.sec
257 +#endif
258 + );
259 }
260
261 int ie_match_stat(const struct index_state *istate,
@@ -1159,8 +1181,15 @@ static void convert_from_disk(struct ondisk_cache_entry *ondisk, struct cache_en
1181 size_t len;
1182 const char *name;
1183
1162 - ce->ce_ctime = ntohl(ondisk->ctime.sec);
1163 - ce->ce_mtime = ntohl(ondisk->mtime.sec);
1184 + ce->ce_ctime.sec = ntohl(ondisk->ctime.sec);
1185 + ce->ce_mtime.sec = ntohl(ondisk->mtime.sec);
1186 +#ifdef USE_NSEC
1187 + ce->ce_ctime.nsec = ntohl(ondisk->ctime.nsec);
1188 + ce->ce_mtime.nsec = ntohl(ondisk->mtime.nsec);
1189 +#else
1190 + ce->ce_ctime.nsec = 0;
1191 + ce->ce_mtime.nsec = 0;
1192 +#endif
1193 ce->ce_dev = ntohl(ondisk->dev);
1194 ce->ce_ino = ntohl(ondisk->ino);
1195 ce->ce_mode = ntohl(ondisk->mode);
@@ -1226,7 +1255,8 @@ int read_index_from(struct index_state *istate, const char *path)
1255 return istate->cache_nr;
1256
1257 errno = ENOENT;
1229 - istate->timestamp = 0;
1258 + istate->timestamp.sec = 0;
1259 + istate->timestamp.nsec = 0;
1260 fd = open(path, O_RDONLY);
1261 if (fd < 0) {
1262 if (errno == ENOENT)
@@ -1278,7 +1308,13 @@ int read_index_from(struct index_state *istate, const char *path)
1308 src_offset += ondisk_ce_size(ce);
1309 dst_offset += ce_size(ce);
1310 }
1281 - istate->timestamp = st.st_mtime;
1311 + istate->timestamp.sec = st.st_mtime;
1312 +#ifdef USE_NSEC
1313 + istate->timestamp.nsec = (unsigned int)st.st_mtim.tv_nsec;
1314 +#else
1315 + istate->timestamp.nsec = 0;
1316 +#endif
1317 +
1318 while (src_offset <= mmap_size - 20 - 8) {
1319 /* After an array of active_nr index entries,
1320 * there can be arbitrary number of extended
@@ -1308,14 +1344,15 @@ unmap:
1344
1345 int is_index_unborn(struct index_state *istate)
1346 {
1311 - return (!istate->cache_nr && !istate->alloc && !istate->timestamp);
1347 + return (!istate->cache_nr && !istate->alloc && !istate->timestamp.sec);
1348 }
1349
1350 int discard_index(struct index_state *istate)
1351 {
1352 istate->cache_nr = 0;
1353 istate->cache_changed = 0;
1318 - istate->timestamp = 0;
1354 + istate->timestamp.sec = 0;
1355 + istate->timestamp.nsec = 0;
1356 istate->name_hash_initialized = 0;
1357 free_hash(&istate->name_hash);
1358 cache_tree_free(&(istate->cache_tree));
@@ -1461,10 +1498,15 @@ static int ce_write_entry(git_SHA_CTX *c, int fd, struct cache_entry *ce)
1498 struct ondisk_cache_entry *ondisk = xcalloc(1, size);
1499 char *name;
1500
1464 - ondisk->ctime.sec = htonl(ce->ce_ctime);
1501 + ondisk->ctime.sec = htonl(ce->ce_ctime.sec);
1502 + ondisk->mtime.sec = htonl(ce->ce_mtime.sec);
1503 +#ifdef USE_NSEC
1504 + ondisk->ctime.nsec = htonl(ce->ce_ctime.nsec);
1505 + ondisk->mtime.nsec = htonl(ce->ce_mtime.nsec);
1506 +#else
1507 ondisk->ctime.nsec = 0;
1466 - ondisk->mtime.sec = htonl(ce->ce_mtime);
1508 ondisk->mtime.nsec = 0;
1509 +#endif
1510 ondisk->dev = htonl(ce->ce_dev);
1511 ondisk->ino = htonl(ce->ce_ino);
1512 ondisk->mode = htonl(ce->ce_mode);
unpack-trees.c
+6 -2
@@ -360,8 +360,12 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
360
361 memset(&o->result, 0, sizeof(o->result));
362 o->result.initialized = 1;
363 - if (o->src_index)
364 - o->result.timestamp = o->src_index->timestamp;
363 + if (o->src_index) {
364 + o->result.timestamp.sec = o->src_index->timestamp.sec;
365 +#ifdef USE_NSEC
366 + o->result.timestamp.nsec = o->src_index->timestamp.nsec;
367 +#endif
368 + }
369 o->merge_size = len;
370
371 if (!dfc)