summaryrefslogtreecommitdiff
path: root/unpack-trees.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-05-09 09:21:07 -0700
committerJunio C Hamano <gitster@pobox.com>2008-05-10 18:16:31 -0700
commitc40641b77b0274186fd1b327d5dc3246f814aaaf (patch)
tree9d455fe976c1d08a3ea0cab763bb45c312e0aaec /unpack-trees.c
parentd177cab0480f9fa172103071203fed1bff95f5c2 (diff)
downloadgit-c40641b77b0274186fd1b327d5dc3246f814aaaf.tar.gz
Optimize symlink/directory detection
This is the base for making symlink detection in the middle fo a pathname saner and (much) more efficient. Under various loads, we want to verify that the full path leading up to a filename is a real directory tree, and that when we successfully do an 'lstat()' on a filename, we don't get a false positive due to a symlink in the middle of the path that git should have seen as a symlink, not as a normal path component. The 'has_symlink_leading_path()' function already did this, and cached a single level of symlink information, but didn't cache the _lack_ of a symlink, so the normal behaviour was actually the wrong way around, and we ended up doing an 'lstat()' on each path component to check that it was a real directory. This caches the last detected full directory and symlink entries, and speeds up especially deep directory structures a lot by avoiding to lstat() all the directories leading up to each entry in the index. [ This can - and should - probably be extended upon so that we eventually never do a bare 'lstat()' on any path entries at *all* when checking the index, but always check the full path carefully. Right now we do not generally check the whole path for all our normal quick index revalidation. We should also make sure that we're careful about all the invalidation, ie when we remove a link and replace it by a directory we should invalidate the symlink cache if it matches (and vice versa for the directory cache). But regardless, the basic function needs to be sane to do that. The old 'has_symlink_leading_path()' was not capable enough - or indeed the code readable enough - to really do that sanely. So I'm pushing this as not just an optimization, but as a base for further work. ] Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'unpack-trees.c')
-rw-r--r--unpack-trees.c12
1 files changed, 5 insertions, 7 deletions
diff --git a/unpack-trees.c b/unpack-trees.c
index feae846226..1ab28fda45 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -26,11 +26,12 @@ static void add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
* directories, in case this unlink is the removal of the
* last entry in the directory -- empty directories are removed.
*/
-static void unlink_entry(char *name, char *last_symlink)
+static void unlink_entry(struct cache_entry *ce)
{
char *cp, *prev;
+ char *name = ce->name;
- if (has_symlink_leading_path(name, last_symlink))
+ if (has_symlink_leading_path(ce_namelen(ce), ce->name))
return;
if (unlink(name))
return;
@@ -58,7 +59,6 @@ static int check_updates(struct unpack_trees_options *o)
{
unsigned cnt = 0, total = 0;
struct progress *progress = NULL;
- char last_symlink[PATH_MAX];
struct index_state *index = &o->result;
int i;
int errs = 0;
@@ -75,14 +75,13 @@ static int check_updates(struct unpack_trees_options *o)
cnt = 0;
}
- *last_symlink = '\0';
for (i = 0; i < index->cache_nr; i++) {
struct cache_entry *ce = index->cache[i];
if (ce->ce_flags & CE_REMOVE) {
display_progress(progress, ++cnt);
if (o->update)
- unlink_entry(ce->name, last_symlink);
+ unlink_entry(ce);
remove_index_entry_at(&o->result, i);
i--;
continue;
@@ -97,7 +96,6 @@ static int check_updates(struct unpack_trees_options *o)
ce->ce_flags &= ~CE_UPDATE;
if (o->update) {
errs |= checkout_entry(ce, &state, NULL);
- *last_symlink = '\0';
}
}
}
@@ -553,7 +551,7 @@ static int verify_absent(struct cache_entry *ce, const char *action,
if (o->index_only || o->reset || !o->update)
return 0;
- if (has_symlink_leading_path(ce->name, NULL))
+ if (has_symlink_leading_path(ce_namelen(ce), ce->name))
return 0;
if (!lstat(ce->name, &st)) {