Skip to content

Commit

Permalink
Merge branch 'kb/checkout-optim'
Browse files Browse the repository at this point in the history
* kb/checkout-optim:
  Revert "lstat_cache(): print a warning if doing ping-pong between cache types"
  checkout bugfix: use stat.mtime instead of stat.ctime in two places
  Makefile: Set compiler switch for USE_NSEC
  Create USE_ST_TIMESPEC and turn it on for Darwin
  Not all systems use st_[cm]tim field for ns resolution file timestamp
  Record ns-timestamps if possible, but do not use it without USE_NSEC
  write_index(): update index_state->timestamp after flushing to disk
  verify_uptodate(): add ce_uptodate(ce) test
  make USE_NSEC work as expected
  fix compile error when USE_NSEC is defined
  check_updates(): effective removal of cache entries marked CE_REMOVE
  lstat_cache(): print a warning if doing ping-pong between cache types
  show_patch_diff(): remove a call to fstat()
  write_entry(): use fstat() instead of lstat() when file is open
  write_entry(): cleanup of some duplicated code
  create_directories(): remove some memcpy() and strchr() calls
  unlink_entry(): introduce schedule_dir_for_removal()
  lstat_cache(): swap func(length, string) into func(string, length)
  lstat_cache(): generalise longest_match_lstat_cache()
  lstat_cache(): small cleanup and optimisation
  • Loading branch information
Junio C Hamano committed Mar 18, 2009
2 parents 642d084 + 381b920 commit a9bfe81
Show file tree
Hide file tree
Showing 15 changed files with 296 additions and 170 deletions.
3 changes: 3 additions & 0 deletions Documentation/CodingGuidelines
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,6 @@ For C programs:
used in the git core command set (unless your command is clearly
separate from it, such as an importer to convert random-scm-X
repositories to git).

- When we pass <string, length> pair to functions, we should try to
pass them in that order.
18 changes: 18 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,12 @@ all::
# randomly break unless your underlying filesystem supports those sub-second
# times (my ext3 doesn't).
#
# Define USE_ST_TIMESPEC if your "struct stat" uses "st_ctimespec" instead of
# "st_ctim"
#
# Define NO_NSEC if your "struct stat" does not have "st_ctim.tv_nsec"
# available. This automatically turns USE_NSEC off.
#
# Define USE_STDEV below if you want git to care about the underlying device
# change being considered an inode change from the update-index perspective.
#
Expand Down Expand Up @@ -657,6 +663,7 @@ ifeq ($(uname_S),Darwin)
endif
NO_MEMMEM = YesPlease
THREADED_DELTA_SEARCH = YesPlease
USE_ST_TIMESPEC = YesPlease
endif
ifeq ($(uname_S),SunOS)
NEEDS_SOCKET = YesPlease
Expand Down Expand Up @@ -734,6 +741,7 @@ ifeq ($(uname_S),AIX)
NO_MEMMEM = YesPlease
NO_MKDTEMP = YesPlease
NO_STRLCPY = YesPlease
NO_NSEC = YesPlease
FREAD_READS_DIRECTORIES = UnfortunatelyYes
INTERNAL_QSORT = UnfortunatelyYes
NEEDS_LIBICONV=YesPlease
Expand Down Expand Up @@ -799,6 +807,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
RUNTIME_PREFIX = YesPlease
NO_POSIX_ONLY_PROGRAMS = YesPlease
NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
NO_NSEC = YesPlease
COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/regex -Icompat/fnmatch
COMPAT_CFLAGS += -DSNPRINTF_SIZE_CORR=1
COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
Expand Down Expand Up @@ -920,6 +929,15 @@ endif
ifdef NO_ST_BLOCKS_IN_STRUCT_STAT
BASIC_CFLAGS += -DNO_ST_BLOCKS_IN_STRUCT_STAT
endif
ifdef USE_NSEC
BASIC_CFLAGS += -DUSE_NSEC
endif
ifdef USE_ST_TIMESPEC
BASIC_CFLAGS += -DUSE_ST_TIMESPEC
endif
ifdef NO_NSEC
BASIC_CFLAGS += -DNO_NSEC
endif
ifdef NO_C99_FORMAT
BASIC_CFLAGS += -DNO_C99_FORMAT
endif
Expand Down
2 changes: 1 addition & 1 deletion builtin-add.c
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ static const char **validate_pathspec(int argc, const char **argv, const char *p
if (pathspec) {
const char **p;
for (p = pathspec; *p; p++) {
if (has_symlink_leading_path(strlen(*p), *p)) {
if (has_symlink_leading_path(*p, strlen(*p))) {
int len = prefix ? strlen(prefix) : 0;
die("'%s' is beyond a symbolic link", *p + len);
}
Expand Down
2 changes: 1 addition & 1 deletion builtin-apply.c
Original file line number Diff line number Diff line change
Expand Up @@ -2360,7 +2360,7 @@ static int check_to_create_blob(const char *new_name, int ok_if_exists)
* In such a case, path "new_name" does not exist as
* far as git is concerned.
*/
if (has_symlink_leading_path(strlen(new_name), new_name))
if (has_symlink_leading_path(new_name, strlen(new_name)))
return 0;

return error("%s: already exists in working directory", new_name);
Expand Down
6 changes: 2 additions & 4 deletions builtin-fetch-pack.c
Original file line number Diff line number Diff line change
Expand Up @@ -800,15 +800,13 @@ struct ref *fetch_pack(struct fetch_pack_args *my_args,
int fd;

mtime.sec = st.st_mtime;
#ifdef USE_NSEC
mtime.usec = st.st_mtim.usec;
#endif
mtime.nsec = ST_MTIME_NSEC(st);
if (stat(shallow, &st)) {
if (mtime.sec)
die("shallow file was removed during fetch");
} else if (st.st_mtime != mtime.sec
#ifdef USE_NSEC
|| st.st_mtim.usec != mtime.usec
|| ST_MTIME_NSEC(st) != mtime.nsec
#endif
)
die("shallow file was changed during fetch");
Expand Down
2 changes: 1 addition & 1 deletion builtin-update-index.c
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ static int process_path(const char *path)
struct stat st;

len = strlen(path);
if (has_symlink_leading_path(len, path))
if (has_symlink_leading_path(path, len))
return error("'%s' is beyond a symbolic link", path);

/*
Expand Down
19 changes: 11 additions & 8 deletions cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,8 @@ struct ondisk_cache_entry_extended {
};

struct cache_entry {
unsigned int ce_ctime;
unsigned int ce_mtime;
struct cache_time ce_ctime;
struct cache_time ce_mtime;
unsigned int ce_dev;
unsigned int ce_ino;
unsigned int ce_mode;
Expand Down Expand Up @@ -282,7 +282,7 @@ struct index_state {
struct cache_entry **cache;
unsigned int cache_nr, cache_alloc, cache_changed;
struct cache_tree *cache_tree;
time_t timestamp;
struct cache_time timestamp;
void *alloc;
unsigned name_hash_initialized : 1,
initialized : 1;
Expand Down Expand Up @@ -428,7 +428,7 @@ extern int read_index_preload(struct index_state *, const char **pathspec);
extern int read_index_from(struct index_state *, const char *path);
extern int is_index_unborn(struct index_state *);
extern int read_index_unmerged(struct index_state *);
extern int write_index(const struct index_state *, int newfd);
extern int write_index(struct index_state *, int newfd);
extern int discard_index(struct index_state *);
extern int unmerged_index(const struct index_state *);
extern int verify_path(const char *path);
Expand All @@ -443,6 +443,7 @@ extern int add_index_entry(struct index_state *, struct cache_entry *ce, int opt
extern struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really);
extern void rename_index_entry_at(struct index_state *, int pos, const char *new_name);
extern int remove_index_entry_at(struct index_state *, int pos);
extern void remove_marked_cache_entries(struct index_state *istate);
extern int remove_file_from_index(struct index_state *, const char *path);
#define ADD_CACHE_VERBOSE 1
#define ADD_CACHE_PRETEND 2
Expand Down Expand Up @@ -725,11 +726,13 @@ 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 int has_symlink_leading_path(const char *name, int len);
extern int has_symlink_or_noent_leading_path(const char *name, int len);
extern int has_dirs_only_path(const char *name, int len, int prefix_len);
extern void invalidate_lstat_cache(const char *name, int len);
extern void clear_lstat_cache(void);
extern void schedule_dir_for_removal(const char *name, int len);
extern void remove_scheduled_dirs(void);

extern struct alternate_object_database {
struct alternate_object_database *next;
Expand Down
4 changes: 1 addition & 3 deletions combine-diff.c
Original file line number Diff line number Diff line change
Expand Up @@ -712,9 +712,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
result_size = buf.len;
result = strbuf_detach(&buf, NULL);
elem->mode = canon_mode(st.st_mode);
}
else if (0 <= (fd = open(elem->path, O_RDONLY)) &&
!fstat(fd, &st)) {
} else if (0 <= (fd = open(elem->path, O_RDONLY))) {
size_t len = xsize_t(st.st_size);
ssize_t done;
int is_file, i;
Expand Down
2 changes: 1 addition & 1 deletion diff-lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ static int check_removed(const struct cache_entry *ce, struct stat *st)
return -1;
return 1;
}
if (has_symlink_leading_path(ce_namelen(ce), ce->name))
if (has_symlink_leading_path(ce->name, ce_namelen(ce)))
return 1;
if (S_ISDIR(st->st_mode)) {
unsigned char sub[20];
Expand Down
2 changes: 1 addition & 1 deletion dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -720,7 +720,7 @@ int read_directory(struct dir_struct *dir, const char *path, const char *base, i
{
struct path_simplify *simplify;

if (has_symlink_leading_path(strlen(path), path))
if (has_symlink_leading_path(path, strlen(path)))
return dir->nr;

simplify = create_simplify(pathspec);
Expand Down
108 changes: 52 additions & 56 deletions entry.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,19 @@
#include "blob.h"
#include "dir.h"

static void create_directories(const char *path, const struct checkout *state)
static void create_directories(const char *path, int path_len,
const struct checkout *state)
{
int len = strlen(path);
char *buf = xmalloc(len + 1);
const char *slash = path;

while ((slash = strchr(slash+1, '/')) != NULL) {
len = slash - path;
memcpy(buf, path, len);
char *buf = xmalloc(path_len + 1);
int len = 0;

while (len < path_len) {
do {
buf[len] = path[len];
len++;
} while (len < path_len && path[len] != '/');
if (len >= path_len)
break;
buf[len] = 0;

/*
Expand All @@ -20,7 +24,7 @@ static void create_directories(const char *path, const struct checkout *state)
* 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))
if (has_dirs_only_path(buf, len, state->base_dir_len))
continue; /* ok, it is already a directory. */

/*
Expand Down Expand Up @@ -74,7 +78,7 @@ static int create_file(const char *path, unsigned int mode)
return open(path, O_WRONLY | O_CREAT | O_EXCL, mode);
}

static void *read_blob_entry(struct cache_entry *ce, const char *path, unsigned long *size)
static void *read_blob_entry(struct cache_entry *ce, unsigned long *size)
{
enum object_type type;
void *new = read_sha1_file(ce->sha1, &type, size);
Expand All @@ -89,78 +93,69 @@ static void *read_blob_entry(struct cache_entry *ce, const char *path, unsigned

static int write_entry(struct cache_entry *ce, char *path, const struct checkout *state, int to_tempfile)
{
int fd;
long wrote;

switch (ce->ce_mode & S_IFMT) {
char *new;
struct strbuf buf;
unsigned long size;
unsigned int ce_mode_s_ifmt = ce->ce_mode & S_IFMT;
int fd, ret, fstat_done = 0;
char *new;
struct strbuf buf = STRBUF_INIT;
unsigned long size;
size_t wrote, newsize = 0;
struct stat st;

switch (ce_mode_s_ifmt) {
case S_IFREG:
new = read_blob_entry(ce, path, &size);
case S_IFLNK:
new = read_blob_entry(ce, &size);
if (!new)
return error("git checkout-index: unable to read sha1 file of %s (%s)",
path, sha1_to_hex(ce->sha1));

if (ce_mode_s_ifmt == S_IFLNK && has_symlinks && !to_tempfile) {
ret = symlink(new, path);
free(new);
if (ret)
return error("git checkout-index: unable to create symlink %s (%s)",
path, strerror(errno));
break;
}

/*
* Convert from git internal format to working tree format
*/
strbuf_init(&buf, 0);
if (convert_to_working_tree(ce->name, new, size, &buf)) {
size_t newsize = 0;
if (ce_mode_s_ifmt == S_IFREG &&
convert_to_working_tree(ce->name, new, size, &buf)) {
free(new);
new = strbuf_detach(&buf, &newsize);
size = newsize;
}

if (to_tempfile) {
strcpy(path, ".merge_file_XXXXXX");
if (ce_mode_s_ifmt == S_IFREG)
strcpy(path, ".merge_file_XXXXXX");
else
strcpy(path, ".merge_link_XXXXXX");
fd = mkstemp(path);
} else
} else if (ce_mode_s_ifmt == S_IFREG) {
fd = create_file(path, ce->ce_mode);
} else {
fd = create_file(path, 0666);
}
if (fd < 0) {
free(new);
return error("git checkout-index: unable to create file %s (%s)",
path, strerror(errno));
}

wrote = write_in_full(fd, new, size);
/* use fstat() only when path == ce->name */
if (state->refresh_cache && !to_tempfile && !state->base_dir_len) {
fstat(fd, &st);
fstat_done = 1;
}
close(fd);
free(new);
if (wrote != size)
return error("git checkout-index: unable to write file %s", path);
break;
case S_IFLNK:
new = read_blob_entry(ce, path, &size);
if (!new)
return error("git checkout-index: unable to read sha1 file of %s (%s)",
path, sha1_to_hex(ce->sha1));
if (to_tempfile || !has_symlinks) {
if (to_tempfile) {
strcpy(path, ".merge_link_XXXXXX");
fd = mkstemp(path);
} else
fd = create_file(path, 0666);
if (fd < 0) {
free(new);
return error("git checkout-index: unable to create "
"file %s (%s)", path, strerror(errno));
}
wrote = write_in_full(fd, new, size);
close(fd);
free(new);
if (wrote != size)
return error("git checkout-index: unable to write file %s",
path);
} else {
wrote = symlink(new, path);
free(new);
if (wrote)
return error("git checkout-index: unable to create "
"symlink %s (%s)", path, strerror(errno));
}
break;
case S_IFGITLINK:
if (to_tempfile)
return error("git checkout-index: cannot create temporary subproject %s", path);
Expand All @@ -172,8 +167,8 @@ static int write_entry(struct cache_entry *ce, char *path, const struct checkout
}

if (state->refresh_cache) {
struct stat st;
lstat(ce->name, &st);
if (!fstat_done)
lstat(ce->name, &st);
fill_stat_cache_info(ce, &st);
}
return 0;
Expand All @@ -190,6 +185,7 @@ int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *t

memcpy(path, state->base_dir, len);
strcpy(path + len, ce->name);
len += ce_namelen(ce);

if (!lstat(path, &st)) {
unsigned changed = ce_match_stat(ce, &st, CE_MATCH_IGNORE_VALID);
Expand Down Expand Up @@ -218,6 +214,6 @@ int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *t
return error("unable to unlink old '%s' (%s)", path, strerror(errno));
} else if (state->not_new)
return 0;
create_directories(path, state);
create_directories(path, len, state);
return write_entry(ce, path, state, 0);
}
14 changes: 14 additions & 0 deletions git-compat-util.h
Original file line number Diff line number Diff line change
Expand Up @@ -388,4 +388,18 @@ void git_qsort(void *base, size_t nmemb, size_t size,
# define FORCE_DIR_SET_GID 0
#endif

#ifdef NO_NSEC
#undef USE_NSEC
#define ST_CTIME_NSEC(st) 0
#define ST_MTIME_NSEC(st) 0
#else
#ifdef USE_ST_TIMESPEC
#define ST_CTIME_NSEC(st) ((unsigned int)((st).st_ctimespec.tv_nsec))
#define ST_MTIME_NSEC(st) ((unsigned int)((st).st_mtimespec.tv_nsec))
#else
#define ST_CTIME_NSEC(st) ((unsigned int)((st).st_ctim.tv_nsec))
#define ST_MTIME_NSEC(st) ((unsigned int)((st).st_mtim.tv_nsec))
#endif
#endif

#endif
Loading

0 comments on commit a9bfe81

Please sign in to comment.