{"thread":{"id":"17906","subject":"[PATCH/RFC v2 0/3] git checkout optimisation - part 3","startedAt":"2009-02-19T20:08:27Z","lastAt":"2009-02-21T05:42:25Z","messageCount":10,"participants":["Kjetil Barvik","Junio C Hamano","Sverre Rabbelier"],"isPatch":true,"patchVersion":2,"patchTotal":3},"messages":[{"id":"105502","messageId":"cover.1235071656.git.barvik@broadpark.no","threadId":"17906","inReplyTo":null,"subject":"[PATCH/RFC v2 0/3] git checkout optimisation - part 3","fromName":"Kjetil Barvik","fromEmail":"barvik@broadpark.no","sentAt":"2009-02-19T20:08:27Z","receivedAt":"2009-02-19T20:08:27Z","isPatch":true,"sender":{"key":"barvik@broadpark.no","avatar":null},"body":"Changes sine v1 \n(v1 was posted with subject \"The ext4 filesystem and racy git\")\n\n-- patch 2/3 --\n   Added missing timestamp => timestamp.(u)sec update for\n   unpack-trees.c\n\n-- patch 3/3 --\n   New patch which removes some 14300 lstat(2) calls, and the total is\n   now at 41677 calls, or 1.382 calls/unique string to lstat() for the\n   reference 'git checkout'-test to Linux tag v2.6.27.\n\n   Total reduction so far for all the lstat/git checkout optimisation\n   patches has been 120954 - 41677 = 79277 calls.  Some 14400 fstat(2)\n   calls is added, but those should be faster than simmilar lstat()\n   calls.\n\n(patch-series based on master)\n\n\nKjetil Barvik (3):\n  fix compile error when USE_NSEC is defined\n  make USE_NSEC work as expected\n  verify_uptodate(): add ce_uptodate(ce) test\n\n builtin-fetch-pack.c |    4 +-\n cache.h              |    6 ++--\n read-cache.c         |   70 ++++++++++++++++++++++++++++++++++++++++----------\n unpack-trees.c       |   10 +++++--\n 4 files changed, 68 insertions(+), 22 deletions(-)\n"},{"id":"105503","messageId":"42717dc50485756e6153fa07d0b5af2496927f00.1235071656.git.barvik@broadpark.no","threadId":"17906","inReplyTo":"cover.1235071656.git.barvik@broadpark.no","subject":"[PATCH/RFC v2 1/3] fix compile error when USE_NSEC is defined","fromName":"Kjetil Barvik","fromEmail":"barvik@broadpark.no","sentAt":"2009-02-19T20:08:28Z","receivedAt":"2009-02-19T20:08:28Z","isPatch":true,"sender":{"key":"barvik@broadpark.no","avatar":null},"body":"'struct cache' does not have a 'usec' member, but a 'unsigned int\nnsec' member.  Simmilar 'struct stat' does not have a 'st_mtim.usec'\nmember, and we should instead use 'st_mtim.tv_nsec'.\n\nSigned-off-by: Kjetil Barvik <barvik@broadpark.no>\n---\n builtin-fetch-pack.c |    4 ++--\n 1 files changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin-fetch-pack.c b/builtin-fetch-pack.c\nindex 67fb80e..3b210c7 100644\n--- a/builtin-fetch-pack.c\n+++ b/builtin-fetch-pack.c\n@@ -802,14 +802,14 @@ struct ref *fetch_pack(struct fetch_pack_args *my_args,\n \n \t\tmtime.sec = st.st_mtime;\n #ifdef USE_NSEC\n-\t\tmtime.usec = st.st_mtim.usec;\n+\t\tmtime.nsec = st.st_mtim.tv_nsec;\n #endif\n \t\tif (stat(shallow, &st)) {\n \t\t\tif (mtime.sec)\n \t\t\t\tdie(\"shallow file was removed during fetch\");\n \t\t} else if (st.st_mtime != mtime.sec\n #ifdef USE_NSEC\n-\t\t\t\t|| st.st_mtim.usec != mtime.usec\n+\t\t\t\t|| st.st_mtim.tv_nsec != mtime.nsec\n #endif\n \t\t\t  )\n \t\t\tdie(\"shallow file was changed during fetch\");\n-- \n1.6.1.349.g99fa5\n"},{"id":"105504","messageId":"24cefa55a62e2c898f9bd75ff7a6fe8e70836cf0.1235071656.git.barvik@broadpark.no","threadId":"17906","inReplyTo":"cover.1235071656.git.barvik@broadpark.no","subject":"[PATCH/RFC v2 2/3] make USE_NSEC work as expected","fromName":"Kjetil Barvik","fromEmail":"barvik@broadpark.no","sentAt":"2009-02-19T20:08:29Z","receivedAt":"2009-02-19T20:08:29Z","isPatch":true,"sender":{"key":"barvik@broadpark.no","avatar":null},"body":"Since the filesystem ext4 is now defined as stable in Linux v2.6.28,\nand ext4 supports nanonsecond resolution timestamps natively, it is\ntime to make USE_NSEC work as expected.\n\nThis will make racy git situations less likely to happen.  For 'git\ncheckout' this means it will be less likely that we have to open, read\nthe contents of the file into RAM, and check if file is really\nmodified or not.  The result sould be a litle less used CPU time, less\npagefaults and a litle faster program, at least for 'git checkout'.\n\nSince the number of possible racy git situations would increase when\ndisks gets faster, this patch would be more and more helpfull as times\ngo by.  For a fast Solid State Disk, this patch should be helpfull.\n\nNote that, when file operations starts to take less than 1 nanosecond,\none would again start to get more racy git situations.\n\nFor more info on racy git, see Documentation/technical/racy-git.txt\nFor more info on ext4, see http://kernelnewbies.org/Ext4\n\nSigned-off-by: Kjetil Barvik <barvik@broadpark.no>\n---\n cache.h        |    6 ++--\n read-cache.c   |   70 ++++++++++++++++++++++++++++++++++++++++++++-----------\n unpack-trees.c |    8 ++++-\n 3 files changed, 65 insertions(+), 19 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 37dfb1c..309053d 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -140,8 +140,8 @@ struct ondisk_cache_entry_extended {\n };\n \n struct cache_entry {\n-\tunsigned int ce_ctime;\n-\tunsigned int ce_mtime;\n+\tstruct cache_time ce_ctime;\n+\tstruct cache_time ce_mtime;\n \tunsigned int ce_dev;\n \tunsigned int ce_ino;\n \tunsigned int ce_mode;\n@@ -282,7 +282,7 @@ struct index_state {\n \tstruct cache_entry **cache;\n \tunsigned int cache_nr, cache_alloc, cache_changed;\n \tstruct cache_tree *cache_tree;\n-\ttime_t timestamp;\n+\tstruct cache_time timestamp;\n \tvoid *alloc;\n \tunsigned name_hash_initialized : 1,\n \t\t initialized : 1;\ndiff --git a/read-cache.c b/read-cache.c\nindex 940ec76..ca4bec2 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -67,8 +67,15 @@ void rename_index_entry_at(struct index_state *istate, int nr, const char *new_n\n  */\n void fill_stat_cache_info(struct cache_entry *ce, struct stat *st)\n {\n-\tce->ce_ctime = st->st_ctime;\n-\tce->ce_mtime = st->st_mtime;\n+\tce->ce_ctime.sec = (unsigned int)st->st_ctime;\n+\tce->ce_mtime.sec = (unsigned int)st->st_mtime;\n+#ifdef USE_NSEC\n+\tce->ce_ctime.nsec = (unsigned int)st->st_ctim.tv_nsec;\n+\tce->ce_mtime.nsec = (unsigned int)st->st_mtim.tv_nsec;\n+#else\n+\tce->ce_ctime.nsec = 0;\n+\tce->ce_mtime.nsec = 0;\n+#endif\n \tce->ce_dev = st->st_dev;\n \tce->ce_ino = st->st_ino;\n \tce->ce_uid = st->st_uid;\n@@ -196,11 +203,18 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st)\n \tdefault:\n \t\tdie(\"internal error: ce_mode is %o\", ce->ce_mode);\n \t}\n-\tif (ce->ce_mtime != (unsigned int) st->st_mtime)\n+\tif (ce->ce_mtime.sec != (unsigned int)st->st_mtime)\n \t\tchanged |= MTIME_CHANGED;\n-\tif (trust_ctime && ce->ce_ctime != (unsigned int) st->st_ctime)\n+\tif (trust_ctime && ce->ce_ctime.sec != (unsigned int)st->st_ctime)\n \t\tchanged |= CTIME_CHANGED;\n \n+#ifdef USE_NSEC\n+\tif (ce->ce_mtime.nsec != (unsigned int)st->st_mtim.tv_nsec)\n+\t\tchanged |= MTIME_CHANGED;\n+\tif (trust_ctime && ce->ce_ctime.nsec != (unsigned int)st->st_ctim.tv_nsec)\n+\t\tchanged |= CTIME_CHANGED;\n+#endif\n+\n \tif (ce->ce_uid != (unsigned int) st->st_uid ||\n \t    ce->ce_gid != (unsigned int) st->st_gid)\n \t\tchanged |= OWNER_CHANGED;\n@@ -232,8 +246,16 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st)\n static int is_racy_timestamp(const struct index_state *istate, struct cache_entry *ce)\n {\n \treturn (!S_ISGITLINK(ce->ce_mode) &&\n-\t\tistate->timestamp &&\n-\t\t((unsigned int)istate->timestamp) <= ce->ce_mtime);\n+\t\tistate->timestamp.sec &&\n+#ifdef USE_NSEC\n+\t\t /* nanosecond timestamped files can also be racy! */\n+\t\t(istate->timestamp.sec < ce->ce_mtime.sec ||\n+\t\t (istate->timestamp.sec == ce->ce_mtime.sec &&\n+\t\t  istate->timestamp.nsec <= ce->ce_mtime.nsec))\n+#else\n+\t\tistate->timestamp.sec <= ce->ce_mtime.sec\n+#endif\n+\t\t );\n }\n \n int ie_match_stat(const struct index_state *istate,\n@@ -1139,8 +1161,15 @@ static void convert_from_disk(struct ondisk_cache_entry *ondisk, struct cache_en\n \tsize_t len;\n \tconst char *name;\n \n-\tce->ce_ctime = ntohl(ondisk->ctime.sec);\n-\tce->ce_mtime = ntohl(ondisk->mtime.sec);\n+\tce->ce_ctime.sec = ntohl(ondisk->ctime.sec);\n+\tce->ce_mtime.sec = ntohl(ondisk->mtime.sec);\n+#ifdef USE_NSEC\n+\tce->ce_ctime.nsec = ntohl(ondisk->ctime.nsec);\n+\tce->ce_mtime.nsec = ntohl(ondisk->mtime.nsec);\n+#else\n+\tce->ce_ctime.nsec = 0;\n+\tce->ce_mtime.nsec = 0;\n+#endif\n \tce->ce_dev   = ntohl(ondisk->dev);\n \tce->ce_ino   = ntohl(ondisk->ino);\n \tce->ce_mode  = ntohl(ondisk->mode);\n@@ -1206,7 +1235,8 @@ int read_index_from(struct index_state *istate, const char *path)\n \t\treturn istate->cache_nr;\n \n \terrno = ENOENT;\n-\tistate->timestamp = 0;\n+\tistate->timestamp.sec = 0;\n+\tistate->timestamp.nsec = 0;\n \tfd = open(path, O_RDONLY);\n \tif (fd < 0) {\n \t\tif (errno == ENOENT)\n@@ -1258,7 +1288,13 @@ int read_index_from(struct index_state *istate, const char *path)\n \t\tsrc_offset += ondisk_ce_size(ce);\n \t\tdst_offset += ce_size(ce);\n \t}\n-\tistate->timestamp = st.st_mtime;\n+\tistate->timestamp.sec = st.st_mtime;\n+#ifdef USE_NSEC\n+\tistate->timestamp.nsec = (unsigned int)st.st_mtim.tv_nsec;\n+#else\n+\tistate->timestamp.nsec = 0;\n+#endif\n+\n \twhile (src_offset <= mmap_size - 20 - 8) {\n \t\t/* After an array of active_nr index entries,\n \t\t * there can be arbitrary number of extended\n@@ -1288,14 +1324,15 @@ unmap:\n \n int is_index_unborn(struct index_state *istate)\n {\n-\treturn (!istate->cache_nr && !istate->alloc && !istate->timestamp);\n+\treturn (!istate->cache_nr && !istate->alloc && !istate->timestamp.sec);\n }\n \n int discard_index(struct index_state *istate)\n {\n \tistate->cache_nr = 0;\n \tistate->cache_changed = 0;\n-\tistate->timestamp = 0;\n+\tistate->timestamp.sec = 0;\n+\tistate->timestamp.nsec = 0;\n \tistate->name_hash_initialized = 0;\n \tfree_hash(&istate->name_hash);\n \tcache_tree_free(&(istate->cache_tree));\n@@ -1441,10 +1478,15 @@ static int ce_write_entry(git_SHA_CTX *c, int fd, struct cache_entry *ce)\n \tstruct ondisk_cache_entry *ondisk = xcalloc(1, size);\n \tchar *name;\n \n-\tondisk->ctime.sec = htonl(ce->ce_ctime);\n+\tondisk->ctime.sec = htonl(ce->ce_ctime.sec);\n+\tondisk->mtime.sec = htonl(ce->ce_mtime.sec);\n+#ifdef USE_NSEC\n+\tondisk->ctime.nsec = htonl(ce->ce_ctime.nsec);\n+\tondisk->mtime.nsec = htonl(ce->ce_mtime.nsec);\n+#else\n \tondisk->ctime.nsec = 0;\n-\tondisk->mtime.sec = htonl(ce->ce_mtime);\n \tondisk->mtime.nsec = 0;\n+#endif\n \tondisk->dev  = htonl(ce->ce_dev);\n \tondisk->ino  = htonl(ce->ce_ino);\n \tondisk->mode = htonl(ce->ce_mode);\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex e547282..44714cc 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -380,8 +380,12 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options\n \n \tmemset(&o->result, 0, sizeof(o->result));\n \to->result.initialized = 1;\n-\tif (o->src_index)\n-\t\to->result.timestamp = o->src_index->timestamp;\n+\tif (o->src_index) {\n+\t\to->result.timestamp.sec = o->src_index->timestamp.sec;\n+#ifdef USE_NSEC\n+\t\to->result.timestamp.nsec = o->src_index->timestamp.nsec;\n+#endif\n+\t}\n \to->merge_size = len;\n \n \tif (!dfc)\n-- \n1.6.1.349.g99fa5\n"},{"id":"105505","messageId":"e00cfda6e7d884680f0d20ad714465672bb9a232.1235071656.git.barvik@broadpark.no","threadId":"17906","inReplyTo":"cover.1235071656.git.barvik@broadpark.no","subject":"[PATCH/RFC v2 3/3] verify_uptodate(): add ce_uptodate(ce) test","fromName":"Kjetil Barvik","fromEmail":"barvik@broadpark.no","sentAt":"2009-02-19T20:08:30Z","receivedAt":"2009-02-19T20:08:30Z","isPatch":true,"sender":{"key":"barvik@broadpark.no","avatar":null},"body":"If we inside verify_uptodate() can already tell from the ce entry that\nit is already uptodate by testing it with ce_uptodate(ce), there is no\nneed to call lstat(2) and ie_match_stat() afterwards.\n\nAnd, reading from the commit log message from:\n\n    commit eadb5831342bb2e756fa05c03642c4aa1929d4f5\n    Author: Junio C Hamano <gitster@pobox.com>\n    Date:   Fri Jan 18 23:45:24 2008 -0800\n\n    Avoid running lstat(2) on the same cache entry.\n\nthis also seems to be correct usage of the ce_uptodate() macro\nintroduced by that patch.\n\nThis will avoid lots of lstat(2) calls in some cases, for example\nby running the 'git checkout' command.\n\nSigned-off-by: Kjetil Barvik <barvik@broadpark.no>\n---\n unpack-trees.c |    2 +-\n 1 files changed, 1 insertions(+), 1 deletions(-)\n\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 44714cc..1687aee 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -450,7 +450,7 @@ static int verify_uptodate(struct cache_entry *ce,\n {\n \tstruct stat st;\n \n-\tif (o->index_only || o->reset)\n+\tif (o->index_only || o->reset || ce_uptodate(ce))\n \t\treturn 0;\n \n \tif (!lstat(ce->name, &st)) {\n-- \n1.6.1.349.g99fa5\n"},{"id":"105581","messageId":"7vfxi9fqup.fsf@gitster.siamese.dyndns.org","threadId":"17906","inReplyTo":"cover.1235071656.git.barvik@broadpark.no","subject":"Re: [PATCH/RFC v2 0/3] git checkout optimisation - part 3","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-02-20T08:35:26Z","receivedAt":"2009-02-20T08:35:26Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Kjetil Barvik <barvik@broadpark.no> writes:\n\n> Changes sine v1 \n> (v1 was posted with subject \"The ext4 filesystem and racy git\")\n>\n>\n> -- patch 2/3 --\n>    Added missing timestamp => timestamp.(u)sec update for\n>    unpack-trees.c\n>\n> -- patch 3/3 --\n>    New patch which removes some 14300 lstat(2) calls, and the total is\n>    now at 41677 calls, or 1.382 calls/unique string to lstat() for the\n>    reference 'git checkout'-test to Linux tag v2.6.27.\n>\n>    Total reduction so far for all the lstat/git checkout optimisation\n>    patches has been 120954 - 41677 = 79277 calls.  Some 14400 fstat(2)\n>    calls is added, but those should be faster than simmilar lstat()\n>    calls.\n>\n> (patch-series based on master)\n\nHmm, have you noticed that the rest of the stuff are queued on 'next'?\nNot that it matters in this case...\n"},{"id":"105582","messageId":"7vab8hfqug.fsf@gitster.siamese.dyndns.org","threadId":"17906","inReplyTo":"24cefa55a62e2c898f9bd75ff7a6fe8e70836cf0.1235071656.git.barvik@broadpark.no","subject":"Re: [PATCH/RFC v2 2/3] make USE_NSEC work as expected","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-02-20T08:35:35Z","receivedAt":"2009-02-20T08:35:35Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Kjetil Barvik <barvik@broadpark.no> writes:\n\n> diff --git a/read-cache.c b/read-cache.c\n> index 940ec76..ca4bec2 100644\n> --- a/read-cache.c\n> +++ b/read-cache.c\n> @@ -67,8 +67,15 @@ void rename_index_entry_at(struct index_state *istate, int nr, const char *new_n\n>   */\n>  void fill_stat_cache_info(struct cache_entry *ce, struct stat *st)\n>  {\n> -\tce->ce_ctime = st->st_ctime;\n> -\tce->ce_mtime = st->st_mtime;\n> +\tce->ce_ctime.sec = (unsigned int)st->st_ctime;\n> +\tce->ce_mtime.sec = (unsigned int)st->st_mtime;\n> +#ifdef USE_NSEC\n> +\tce->ce_ctime.nsec = (unsigned int)st->st_ctim.tv_nsec;\n> +\tce->ce_mtime.nsec = (unsigned int)st->st_mtim.tv_nsec;\n> +#else\n> +\tce->ce_ctime.nsec = 0;\n> +\tce->ce_mtime.nsec = 0;\n> +#endif\n\nHow does this affect a use case where the same index file used with two \ninstances of git (one compiled with and another without USE_NSEC)?\n\n> @@ -232,8 +246,16 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st)\n>  static int is_racy_timestamp(const struct index_state *istate, struct cache_entry *ce)\n>  {\n>  \treturn (!S_ISGITLINK(ce->ce_mode) &&\n> -\t\tistate->timestamp &&\n> -\t\t((unsigned int)istate->timestamp) <= ce->ce_mtime);\n> +\t\tistate->timestamp.sec &&\n> +#ifdef USE_NSEC\n> +\t\t /* nanosecond timestamped files can also be racy! */\n\nAmusing ;-)\n\n> diff --git a/unpack-trees.c b/unpack-trees.c\n> index e547282..44714cc 100644\n> --- a/unpack-trees.c\n> +++ b/unpack-trees.c\n> @@ -380,8 +380,12 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options\n>  \n>  \tmemset(&o->result, 0, sizeof(o->result));\n>  \to->result.initialized = 1;\n> -\tif (o->src_index)\n> -\t\to->result.timestamp = o->src_index->timestamp;\n> +\tif (o->src_index) {\n> +\t\to->result.timestamp.sec = o->src_index->timestamp.sec;\n> +#ifdef USE_NSEC\n> +\t\to->result.timestamp.nsec = o->src_index->timestamp.nsec;\n> +#endif\n> +\t}\n\nDo we need this hunk?\n"},{"id":"105587","messageId":"86r61tiio2.fsf@broadpark.no","threadId":"17906","inReplyTo":"7vfxi9fqup.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH/RFC v2 0/3] git checkout optimisation - part 3","fromName":"Kjetil Barvik","fromEmail":"barvik@broadpark.no","sentAt":"2009-02-20T09:03:57Z","receivedAt":"2009-02-20T09:03:57Z","isPatch":true,"sender":{"key":"barvik@broadpark.no","avatar":null},"body":"Junio C Hamano <gitster@pobox.com> writes:\n> Hmm, have you noticed that the rest of the stuff are queued on 'next'?\n\n  Yes, I have!  I was also glad to receive my first acked-by git-tag!!\n  :-)\n"},{"id":"105592","messageId":"bd6139dc0902200126j51177504hfeb23b4ec07dfea0@mail.gmail.com","threadId":"17906","inReplyTo":"86r61tiio2.fsf@broadpark.no","subject":"Re: [PATCH/RFC v2 0/3] git checkout optimisation - part 3","fromName":"Sverre Rabbelier","fromEmail":"srabbelier@gmail.com","sentAt":"2009-02-20T09:26:04Z","receivedAt":"2009-02-20T09:26:04Z","isPatch":true,"sender":{"key":"srabbelier@gmail.com","avatar":"https://avatars.githubusercontent.com/u/3098?v=4"},"body":"Heya,\n\nOn Fri, Feb 20, 2009 at 10:03, Kjetil Barvik <barvik@broadpark.no> wrote:\n> Junio C Hamano <gitster@pobox.com> writes:\n>> Hmm, have you noticed that the rest of the stuff are queued on 'next'?\n>\n>  Yes, I have!  I was also glad to receive my first acked-by git-tag!!\n\nIn that case, it wouldof been appopriate to base your further patches\non next rather than master ;).\n\n-- \nCheers,\n\nSverre Rabbelier\n"},{"id":"105595","messageId":"86mychifqj.fsf@broadpark.no","threadId":"17906","inReplyTo":"7vab8hfqug.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH/RFC v2 2/3] make USE_NSEC work as expected","fromName":"Kjetil Barvik","fromEmail":"barvik@broadpark.no","sentAt":"2009-02-20T10:07:16Z","receivedAt":"2009-02-20T10:07:16Z","isPatch":true,"sender":{"key":"barvik@broadpark.no","avatar":null},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Kjetil Barvik <barvik@broadpark.no> writes:\n>\n>> diff --git a/read-cache.c b/read-cache.c\n>> index 940ec76..ca4bec2 100644\n>> --- a/read-cache.c\n>> +++ b/read-cache.c\n>> @@ -67,8 +67,15 @@ void rename_index_entry_at(struct index_state *istate, int nr, const char *new_n\n>>   */\n>>  void fill_stat_cache_info(struct cache_entry *ce, struct stat *st)\n>>  {\n>> -\tce->ce_ctime = st->st_ctime;\n>> -\tce->ce_mtime = st->st_mtime;\n>> +\tce->ce_ctime.sec = (unsigned int)st->st_ctime;\n>> +\tce->ce_mtime.sec = (unsigned int)st->st_mtime;\n>> +#ifdef USE_NSEC\n>> +\tce->ce_ctime.nsec = (unsigned int)st->st_ctim.tv_nsec;\n>> +\tce->ce_mtime.nsec = (unsigned int)st->st_mtim.tv_nsec;\n>> +#else\n>> +\tce->ce_ctime.nsec = 0;\n>> +\tce->ce_mtime.nsec = 0;\n>> +#endif\n>\n> How does this affect a use case where the same index file used with two \n> instances of git (one compiled with and another without USE_NSEC)?\n\n  OK, I admit that I was thinking safe here, so the one using the git\n  compiled with USE_NSEC will see a slow down.\n\n  If we for the use case can assume that both is using an git program\n  compiled from the same source, and the index file is placed on a\n  filesystem which supports nanoseconds timestamp, I guess that the use\n  case for the one using USE_NSEC could be better.\n\n  I will make a new patch to this one (since it is already placed in\n  next), and then you can see if you like the updated one.\n\n\n>> diff --git a/unpack-trees.c b/unpack-trees.c\n>> index e547282..44714cc 100644\n>> --- a/unpack-trees.c\n>> +++ b/unpack-trees.c\n>> @@ -380,8 +380,12 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options\n>>  \n>>  \tmemset(&o->result, 0, sizeof(o->result));\n>>  \to->result.initialized = 1;\n>> -\tif (o->src_index)\n>> -\t\to->result.timestamp = o->src_index->timestamp;\n>> +\tif (o->src_index) {\n>> +\t\to->result.timestamp.sec = o->src_index->timestamp.sec;\n>> +#ifdef USE_NSEC\n>> +\t\to->result.timestamp.nsec = o->src_index->timestamp.nsec;\n>> +#endif\n>> +\t}\n>\n> Do we need this hunk?\n\n  Since timestamp is now a 'struct cache_time' member, I converted the\n  usage of this if-test to be in line with the USE_NSEC usage.\n\n  -- kjetil\n"},{"id":"105690","messageId":"7vhc2os5vi.fsf@gitster.siamese.dyndns.org","threadId":"17906","inReplyTo":"86mychifqj.fsf@broadpark.no","subject":"Re: [PATCH/RFC v2 2/3] make USE_NSEC work as expected","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-02-21T05:42:25Z","receivedAt":"2009-02-21T05:42:25Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Kjetil Barvik <barvik@broadpark.no> writes:\n\n> Junio C Hamano <gitster@pobox.com> writes:\n>\n>>> +\tce->ce_ctime.sec = (unsigned int)st->st_ctime;\n>>> +\tce->ce_mtime.sec = (unsigned int)st->st_mtime;\n>>> +#ifdef USE_NSEC\n>>> +\tce->ce_ctime.nsec = (unsigned int)st->st_ctim.tv_nsec;\n>>> +\tce->ce_mtime.nsec = (unsigned int)st->st_mtim.tv_nsec;\n>>> +#else\n>>> +\tce->ce_ctime.nsec = 0;\n>>> +\tce->ce_mtime.nsec = 0;\n>>> +#endif\n>>\n>> How does this affect a use case where the same index file used with two \n>> instances of git (one compiled with and another without USE_NSEC)?\n>\n>   OK, I admit that I was thinking safe here,...\n\nIt was not a veiled objection in the guise of a rhetoric question.  I just\nwanted to know what happens, when you have \"/usr/bin/git\" compiled without\nNSEC and \"/usr/local/bin/git\" compiled with NSEC, and tried to use the two\ninterchangeably.  A NSEC enabled one will leave nsec in the index entry,\nand the normal one reads from the index file (truncating the nsec from\nboth file timestamp and on-disk index entries), and it is unclear what it\ndoes to the racy-git algorithm.  If there is no adverse effect, that is\ngreat.  Otherwise, even though the on-disk format might be compatible, we\nneed to somehow tell people not to use two gits on the same index file.\n\n>>> diff --git a/unpack-trees.c b/unpack-trees.c\n>>> index e547282..44714cc 100644\n>>> --- a/unpack-trees.c\n>>> +++ b/unpack-trees.c\n>>> @@ -380,8 +380,12 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options\n>>>  \n>>>  \tmemset(&o->result, 0, sizeof(o->result));\n>>>  \to->result.initialized = 1;\n>>> -\tif (o->src_index)\n>>> -\t\to->result.timestamp = o->src_index->timestamp;\n>>> +\tif (o->src_index) {\n>>> +\t\to->result.timestamp.sec = o->src_index->timestamp.sec;\n>>> +#ifdef USE_NSEC\n>>> +\t\to->result.timestamp.nsec = o->src_index->timestamp.nsec;\n>>> +#endif\n>>> +\t}\n>>\n>> Do we need this hunk?\n>\n>   Since timestamp is now a 'struct cache_time' member, I converted the\n>   usage of this if-test to be in line with the USE_NSEC usage.\n\nMy question was if it is wrong to leave this as \"a->timestamp = b->timestamp\"\nwhich now becomes structure assignment.  You would need to move extra 4\n(or 8) bytes if you are not using NSEC, but this is not per index entry\nbut one assignment for the whole index file, so...\n"}]}