Merge branch 'kb/lstat-cache'
authorJunio C Hamano <gitster@pobox.com>
Mon, 26 Jan 2009 01:13:34 +0000 (17:13 -0800)
committerJunio C Hamano <gitster@pobox.com>
Mon, 26 Jan 2009 01:13:34 +0000 (17:13 -0800)
* kb/lstat-cache:
lstat_cache(): introduce clear_lstat_cache() function
lstat_cache(): introduce invalidate_lstat_cache() function
lstat_cache(): introduce has_dirs_only_path() function
lstat_cache(): introduce has_symlink_or_noent_leading_path() function
lstat_cache(): more cache effective symlink/directory detection

1  2 
cache.h
entry.c
unpack-trees.c
diff --combined cache.h
index c96854a0d67a84bde5d139a3d6d7ba058a10181e,468daf6a43672139ea39a02245fd12f652ad12c2..c17fbf58a764e0c96cc4f23d2804ab16e6df7aea
+++ b/cache.h
  #define deflateBound(c,s)  ((s) + (((s) + 7) >> 3) + (((s) + 63) >> 6) + 11)
  #endif
  
 +void git_inflate_init(z_streamp strm);
 +void git_inflate_end(z_streamp strm);
 +int git_inflate(z_streamp strm, int flush);
 +
  #if defined(DT_UNKNOWN) && !defined(NO_D_TYPE_IN_DIRENT)
  #define DTYPE(de)     ((de)->d_type)
  #else
@@@ -635,6 -631,9 +635,6 @@@ extern int write_sha1_file(void *buf, u
  extern int pretend_sha1_file(void *, unsigned long, enum object_type, unsigned char *);
  extern int force_object_loose(const unsigned char *sha1, time_t mtime);
  
 -/* just like read_sha1_file(), but non fatal in presence of bad objects */
 -extern void *read_object(const unsigned char *sha1, enum object_type *type, unsigned long *size);
 -
  /* global flag to enable extra checks when accessing packed objects */
  extern int do_check_packed_object_crc;
  
@@@ -721,6 -720,10 +721,10 @@@ struct checkout 
  
  extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath);
  extern int has_symlink_leading_path(int len, const char *name);
+ extern int has_symlink_or_noent_leading_path(int len, const char *name);
+ extern int has_dirs_only_path(int len, const char *name, int prefix_len);
+ extern void invalidate_lstat_cache(int len, const char *name);
+ extern void clear_lstat_cache(void);
  
  extern struct alternate_object_database {
        struct alternate_object_database *next;
@@@ -937,6 -940,7 +941,6 @@@ extern int ws_fix_copy(char *, const ch
  extern int ws_blank_line(const char *line, int len, unsigned ws_rule);
  
  /* ls-files */
 -int pathspec_match(const char **spec, char *matched, const char *filename, int skiplen);
  int report_path_error(const char *ps_matched, const char **pathspec, int prefix_offset);
  void overlay_tree_on_cache(const char *tree_name, const char *prefix);
  
diff --combined entry.c
index 5f24816eb9fe9fa934889336f2dbcdc7bf006635,01a683ee5dedb6c191faa5c42d694ea8cbcf08a3..05aa58d34823258789ec9e32abc897b8e6777412
+++ b/entry.c
@@@ -1,6 -1,5 +1,6 @@@
  #include "cache.h"
  #include "blob.h"
 +#include "dir.h"
  
  static void create_directories(const char *path, const struct checkout *state)
  {
@@@ -9,35 -8,25 +9,25 @@@
        const char *slash = path;
  
        while ((slash = strchr(slash+1, '/')) != NULL) {
-               struct stat st;
-               int stat_status;
                len = slash - path;
                memcpy(buf, path, len);
                buf[len] = 0;
  
-               if (len <= state->base_dir_len)
-                       /*
-                        * checkout-index --prefix=<dir>; <dir> is
-                        * allowed to be a symlink to an existing
-                        * directory.
-                        */
-                       stat_status = stat(buf, &st);
-               else
-                       /*
-                        * if there currently is a symlink, we would
-                        * want to replace it with a real directory.
-                        */
-                       stat_status = lstat(buf, &st);
-               if (!stat_status && S_ISDIR(st.st_mode))
+               /*
+                * For 'checkout-index --prefix=<dir>', <dir> is
+                * allowed to be a symlink to an existing directory,
+                * and we set 'state->base_dir_len' below, such that
+                * we test the path components of the prefix with the
+                * stat() function instead of the lstat() function.
+                */
+               if (has_dirs_only_path(len, buf, state->base_dir_len))
                        continue; /* ok, it is already a directory. */
  
                /*
-                * We know stat_status == 0 means something exists
-                * there and this mkdir would fail, but that is an
-                * error codepath; we do not care, as we unlink and
-                * mkdir again in such a case.
+                * If this mkdir() would fail, it could be that there
+                * is already a symlink or something else exists
+                * there, therefore we then try to unlink it and try
+                * one more time to create the directory.
                 */
                if (mkdir(buf, 0777)) {
                        if (errno == EEXIST && state->force &&
@@@ -63,7 -52,9 +53,7 @@@ static void remove_subtree(const char *
        *name++ = '/';
        while ((de = readdir(dir)) != NULL) {
                struct stat st;
 -              if ((de->d_name[0] == '.') &&
 -                  ((de->d_name[1] == 0) ||
 -                   ((de->d_name[1] == '.') && de->d_name[2] == 0)))
 +              if (is_dot_or_dotdot(de->d_name))
                        continue;
                strcpy(name, de->d_name);
                if (lstat(pathbuf, &st))
diff --combined unpack-trees.c
index 15c9ef592b393410354496c577a6e8c2dfb39940,a3fd383afbe951fea8dbe4378cbe489657843c4a..16bc2ca9eb0fe46b90969ba4855d9b4d89369f42
@@@ -61,7 -61,7 +61,7 @@@ static void unlink_entry(struct cache_e
        char *cp, *prev;
        char *name = ce->name;
  
-       if (has_symlink_leading_path(ce_namelen(ce), ce->name))
+       if (has_symlink_or_noent_leading_path(ce_namelen(ce), ce->name))
                return;
        if (unlink(name))
                return;
@@@ -494,7 -494,7 +494,7 @@@ static int verify_clean_subdirectory(st
         * anything in the existing directory there.
         */
        int namelen;
 -      int pos, i;
 +      int i;
        struct dir_struct d;
        char *pathbuf;
        int cnt = 0;
         * in that directory.
         */
        namelen = strlen(ce->name);
 -      pos = index_name_pos(o->src_index, ce->name, namelen);
 -      if (0 <= pos)
 -              return cnt; /* we have it as nondirectory */
 -      pos = -pos - 1;
 -      for (i = pos; i < o->src_index->cache_nr; i++) {
 -              struct cache_entry *ce = o->src_index->cache[i];
 -              int len = ce_namelen(ce);
 +      for (i = o->pos; i < o->src_index->cache_nr; i++) {
 +              struct cache_entry *ce2 = o->src_index->cache[i];
 +              int len = ce_namelen(ce2);
                if (len < namelen ||
 -                  strncmp(ce->name, ce->name, namelen) ||
 -                  ce->name[namelen] != '/')
 +                  strncmp(ce->name, ce2->name, namelen) ||
 +                  ce2->name[namelen] != '/')
                        break;
                /*
 -               * ce->name is an entry in the subdirectory.
 +               * ce2->name is an entry in the subdirectory.
                 */
 -              if (!ce_stage(ce)) {
 -                      if (verify_uptodate(ce, o))
 +              if (!ce_stage(ce2)) {
 +                      if (verify_uptodate(ce2, o))
                                return -1;
 -                      add_entry(o, ce, CE_REMOVE, 0);
 +                      add_entry(o, ce2, CE_REMOVE, 0);
                }
                cnt++;
        }
@@@ -580,11 -584,11 +580,11 @@@ static int verify_absent(struct cache_e
        if (o->index_only || o->reset || !o->update)
                return 0;
  
-       if (has_symlink_leading_path(ce_namelen(ce), ce->name))
+       if (has_symlink_or_noent_leading_path(ce_namelen(ce), ce->name))
                return 0;
  
        if (!lstat(ce->name, &st)) {
 -              int cnt;
 +              int ret;
                int dtype = ce_to_dtype(ce);
                struct cache_entry *result;
  
                         * files that are in "foo/" we would lose
                         * it.
                         */
 -                      cnt = verify_clean_subdirectory(ce, action, o);
 +                      ret = verify_clean_subdirectory(ce, action, o);
 +                      if (ret < 0)
 +                              return ret;
  
                        /*
                         * If this removed entries from the index,
                         * what that means is:
                         *
 -                       * (1) the caller unpack_trees_rec() saw path/foo
 +                       * (1) the caller unpack_callback() saw path/foo
                         * in the index, and it has not removed it because
                         * it thinks it is handling 'path' as blob with
                         * D/F conflict;
                         * We need to increment it by the number of
                         * deleted entries here.
                         */
 -                      o->pos += cnt;
 +                      o->pos += ret;
                        return 0;
                }