From: Junio C Hamano Date: Tue, 12 Feb 2008 00:46:20 +0000 (-0800) Subject: Merge branch 'lt/in-core-index' X-Git-Tag: v1.5.5-rc0~232 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/e0197c9aae39b0f1ba6c21d1f6d0bae5de03a44d?ds=inline;hp=-c Merge branch 'lt/in-core-index' * lt/in-core-index: lazy index hashing Create pathname-based hash-table lookup into index read-cache.c: introduce is_racy_timestamp() helper read-cache.c: fix a couple more CE_REMOVE conversion Also use unpack_trees() in do_diff_cache() Make run_diff_index() use unpack_trees(), not read_tree() Avoid running lstat(2) on the same cache entry. index: be careful when handling long names Make on-disk index representation separate from in-core one --- e0197c9aae39b0f1ba6c21d1f6d0bae5de03a44d diff --combined builtin-apply.c index a11b1bbeee,30d86f2197..46dad5b2a1 --- a/builtin-apply.c +++ b/builtin-apply.c @@@ -1946,7 -1946,7 +1946,7 @@@ static int read_file_or_gitlink(struct if (!ce) return 0; - if (S_ISGITLINK(ntohl(ce->ce_mode))) { + if (S_ISGITLINK(ce->ce_mode)) { strbuf_grow(buf, 100); strbuf_addf(buf, "Subproject commit %s\n", sha1_to_hex(ce->sha1)); } else { @@@ -2023,7 -2023,7 +2023,7 @@@ static int check_to_create_blob(const c static int verify_index_match(struct cache_entry *ce, struct stat *st) { - if (S_ISGITLINK(ntohl(ce->ce_mode))) { + if (S_ISGITLINK(ce->ce_mode)) { if (!S_ISDIR(st->st_mode)) return -1; return 0; @@@ -2082,12 -2082,12 +2082,12 @@@ static int check_patch(struct patch *pa return error("%s: does not match index", old_name); if (cached) - st_mode = ntohl(ce->ce_mode); + st_mode = ce->ce_mode; } else if (stat_ret < 0) return error("%s: %s", old_name, strerror(errno)); if (!cached) - st_mode = ntohl(ce_mode_from_stat(ce, st.st_mode)); + st_mode = ce_mode_from_stat(ce, st.st_mode); if (patch->is_new < 0) patch->is_new = 0; @@@ -2388,7 -2388,7 +2388,7 @@@ static void add_index_file(const char * ce = xcalloc(1, ce_size); memcpy(ce->name, path, namelen); ce->ce_mode = create_ce_mode(mode); - ce->ce_flags = htons(namelen); + ce->ce_flags = namelen; if (S_ISGITLINK(mode)) { const char *s = buf; @@@ -2746,8 -2746,6 +2746,8 @@@ static int apply_patch(int fd, const ch static int git_apply_config(const char *var, const char *value) { if (!strcmp(var, "apply.whitespace")) { + if (!value) + return config_error_nonbool(var); apply_default_whitespace = xstrdup(value); return 0; } diff --combined builtin-commit.c index a43f201995,c63ff826fc..717eb18da0 --- a/builtin-commit.c +++ b/builtin-commit.c @@@ -122,23 -122,19 +122,23 @@@ static void rollback_index_files(void } } -static void commit_index_files(void) +static int commit_index_files(void) { + int err = 0; + switch (commit_style) { case COMMIT_AS_IS: break; /* nothing to do */ case COMMIT_NORMAL: - commit_lock_file(&index_lock); + err = commit_lock_file(&index_lock); break; case COMMIT_PARTIAL: - commit_lock_file(&index_lock); + err = commit_lock_file(&index_lock); rollback_lock_file(&false_lock); break; } + + return err; } /* @@@ -160,7 -156,7 +160,7 @@@ static int list_paths(struct path_list for (i = 0; i < active_nr; i++) { struct cache_entry *ce = active_cache[i]; - if (ce->ce_flags & htons(CE_UPDATE)) + if (ce->ce_flags & CE_UPDATE) continue; if (!pathspec_match(pattern, m, ce->name, 0)) continue; @@@ -601,7 -597,7 +601,7 @@@ static int parse_and_validate_options(i if (get_sha1(use_message, sha1)) die("could not lookup commit %s", use_message); - commit = lookup_commit(sha1); + commit = lookup_commit_reference(sha1); if (!commit || parse_commit(commit)) die("could not parse commit %s", use_message); @@@ -743,8 -739,6 +743,8 @@@ static void print_summary(const char *p int git_commit_config(const char *k, const char *v) { if (!strcmp(k, "commit.template")) { + if (!v) + return config_error_nonbool(v); template_file = xstrdup(v); return 0; } @@@ -931,12 -925,8 +931,12 @@@ int cmd_commit(int argc, const char **a unlink(git_path("MERGE_HEAD")); unlink(git_path("MERGE_MSG")); + unlink(git_path("SQUASH_MSG")); - commit_index_files(); + if (commit_index_files()) + die ("Repository has been updated, but unable to write\n" + "new_index file. Check that disk is not full or quota is\n" + "not exceeded, and then \"git reset HEAD\" to recover."); rerere(); run_hook(get_index_file(), "post-commit", NULL); diff --combined builtin-fsck.c index 8c564345f4,6fc9525e04..cc7524be80 --- a/builtin-fsck.c +++ b/builtin-fsck.c @@@ -360,9 -360,6 +360,9 @@@ static int fsck_commit(struct commit *c fprintf(stderr, "Checking commit %s\n", sha1_to_hex(commit->object.sha1)); + if (!commit->date) + return objerror(&commit->object, "invalid author/committer line"); + if (memcmp(buffer, "tree ", 5)) return objerror(&commit->object, "invalid format - expected 'tree' line"); if (get_sha1_hex(buffer+5, tree_sha1) || buffer[45] != '\n') @@@ -381,6 -378,9 +381,6 @@@ return objerror(&commit->object, "could not load commit's tree %s", tree_sha1); if (!commit->parents && show_root) printf("root %s\n", sha1_to_hex(commit->object.sha1)); - if (!commit->date) - printf("bad commit date in %s\n", - sha1_to_hex(commit->object.sha1)); return 0; } @@@ -765,7 -765,7 +765,7 @@@ int cmd_fsck(int argc, const char **arg struct blob *blob; struct object *obj; - mode = ntohl(active_cache[i]->ce_mode); + mode = active_cache[i]->ce_mode; if (S_ISGITLINK(mode)) continue; blob = lookup_blob(active_cache[i]->sha1); diff --combined cache.h index 6abcee4372,e4aeff07d1..3867ba7ff5 --- a/cache.h +++ b/cache.h @@@ -3,6 -3,7 +3,7 @@@ #include "git-compat-util.h" #include "strbuf.h" + #include "hash.h" #include SHA1_HEADER #include @@@ -94,48 -95,84 +95,84 @@@ struct cache_time * We save the fields in big-endian order to allow using the * index file over NFS transparently. */ + struct ondisk_cache_entry { + struct cache_time ctime; + struct cache_time mtime; + unsigned int dev; + unsigned int ino; + unsigned int mode; + unsigned int uid; + unsigned int gid; + unsigned int size; + unsigned char sha1[20]; + unsigned short flags; + char name[FLEX_ARRAY]; /* more */ + }; + struct cache_entry { - struct cache_time ce_ctime; - struct cache_time ce_mtime; + struct cache_entry *next; + unsigned int ce_ctime; + unsigned int ce_mtime; unsigned int ce_dev; unsigned int ce_ino; unsigned int ce_mode; unsigned int ce_uid; unsigned int ce_gid; unsigned int ce_size; + unsigned int ce_flags; unsigned char sha1[20]; - unsigned short ce_flags; char name[FLEX_ARRAY]; /* more */ }; #define CE_NAMEMASK (0x0fff) #define CE_STAGEMASK (0x3000) - #define CE_UPDATE (0x4000) #define CE_VALID (0x8000) #define CE_STAGESHIFT 12 - #define create_ce_flags(len, stage) htons((len) | ((stage) << CE_STAGESHIFT)) - #define ce_namelen(ce) (CE_NAMEMASK & ntohs((ce)->ce_flags)) + /* In-memory only */ + #define CE_UPDATE (0x10000) + #define CE_REMOVE (0x20000) + #define CE_UPTODATE (0x40000) + #define CE_UNHASHED (0x80000) + + static inline unsigned create_ce_flags(size_t len, unsigned stage) + { + if (len >= CE_NAMEMASK) + len = CE_NAMEMASK; + return (len | (stage << CE_STAGESHIFT)); + } + + static inline size_t ce_namelen(const struct cache_entry *ce) + { + size_t len = ce->ce_flags & CE_NAMEMASK; + if (len < CE_NAMEMASK) + return len; + return strlen(ce->name + CE_NAMEMASK) + CE_NAMEMASK; + } + #define ce_size(ce) cache_entry_size(ce_namelen(ce)) - #define ce_stage(ce) ((CE_STAGEMASK & ntohs((ce)->ce_flags)) >> CE_STAGESHIFT) + #define ondisk_ce_size(ce) ondisk_cache_entry_size(ce_namelen(ce)) + #define ce_stage(ce) ((CE_STAGEMASK & (ce)->ce_flags) >> CE_STAGESHIFT) + #define ce_uptodate(ce) ((ce)->ce_flags & CE_UPTODATE) + #define ce_mark_uptodate(ce) ((ce)->ce_flags |= CE_UPTODATE) #define ce_permissions(mode) (((mode) & 0100) ? 0755 : 0644) static inline unsigned int create_ce_mode(unsigned int mode) { if (S_ISLNK(mode)) - return htonl(S_IFLNK); + return S_IFLNK; if (S_ISDIR(mode) || S_ISGITLINK(mode)) - return htonl(S_IFGITLINK); - return htonl(S_IFREG | ce_permissions(mode)); + return S_IFGITLINK; + return S_IFREG | ce_permissions(mode); } static inline unsigned int ce_mode_from_stat(struct cache_entry *ce, unsigned int mode) { extern int trust_executable_bit, has_symlinks; if (!has_symlinks && S_ISREG(mode) && - ce && S_ISLNK(ntohl(ce->ce_mode))) + ce && S_ISLNK(ce->ce_mode)) return ce->ce_mode; if (!trust_executable_bit && S_ISREG(mode)) { - if (ce && S_ISREG(ntohl(ce->ce_mode))) + if (ce && S_ISREG(ce->ce_mode)) return ce->ce_mode; return create_ce_mode(0666); } @@@ -146,14 -183,16 +183,16 @@@ S_ISLNK(mode) ? S_IFLNK : S_ISDIR(mode) ? S_IFDIR : S_IFGITLINK) #define cache_entry_size(len) ((offsetof(struct cache_entry,name) + (len) + 8) & ~7) + #define ondisk_cache_entry_size(len) ((offsetof(struct ondisk_cache_entry,name) + (len) + 8) & ~7) struct index_state { struct cache_entry **cache; unsigned int cache_nr, cache_alloc, cache_changed; struct cache_tree *cache_tree; time_t timestamp; - void *mmap; - size_t mmap_size; + void *alloc; + unsigned name_hash_initialized : 1; + struct hash_table name_hash; }; extern struct index_state the_index; @@@ -177,6 -216,7 +216,7 @@@ #define refresh_cache(flags) refresh_index(&the_index, (flags), NULL, NULL) #define ce_match_stat(ce, st, options) ie_match_stat(&the_index, (ce), (st), (options)) #define ce_modified(ce, st, options) ie_modified(&the_index, (ce), (st), (options)) + #define cache_name_exists(name, namelen) index_name_exists(&the_index, (name), (namelen)) #endif enum object_type { @@@ -263,6 -303,7 +303,7 @@@ extern int read_index_from(struct index extern int write_index(struct index_state *, int newfd); extern int discard_index(struct index_state *); extern int verify_path(const char *path); + extern int index_name_exists(struct index_state *istate, const char *name, int namelen); extern int index_name_pos(struct index_state *, const char *name, int namelen); #define ADD_CACHE_OK_TO_ADD 1 /* Ok to add */ #define ADD_CACHE_OK_TO_REPLACE 2 /* Ok to replace file/directory */ @@@ -589,7 -630,6 +630,7 @@@ extern int git_config_set_multivar(cons extern int git_config_rename_section(const char *, const char *); extern const char *git_etc_gitconfig(void); extern int check_repository_format_version(const char *var, const char *value); +extern int config_error_nonbool(const char *); #define MAX_GITNAME (1000) extern char git_default_email[MAX_GITNAME]; diff --combined diff.c index 4d2e23ae1b,d464fe3b20..cd8bc4dcc3 --- a/diff.c +++ b/diff.c @@@ -158,8 -158,6 +158,8 @@@ int git_diff_ui_config(const char *var return 0; } if (!strcmp(var, "diff.external")) { + if (!value) + return config_error_nonbool(var); external_diff_cmd_cfg = xstrdup(value); return 0; } @@@ -167,11 -165,8 +167,11 @@@ const char *ep = strrchr(var, '.'); if (ep != var + 4) { - if (!strcmp(ep, ".command")) + if (!strcmp(ep, ".command")) { + if (!value) + return config_error_nonbool(var); return parse_lldiff_command(var, ep, value); + } } } @@@ -182,8 -177,6 +182,8 @@@ int git_diff_basic_config(const char *v { if (!prefixcmp(var, "diff.color.") || !prefixcmp(var, "color.diff.")) { int slot = parse_diff_color_slot(var, 11); + if (!value) + return config_error_nonbool(var); color_parse(value, var, diff_colors[slot]); return 0; } @@@ -191,11 -184,8 +191,11 @@@ if (!prefixcmp(var, "diff.")) { const char *ep = strrchr(var, '.'); if (ep != var + 4) { - if (!strcmp(ep, ".funcname")) + if (!strcmp(ep, ".funcname")) { + if (!value) + return config_error_nonbool(var); return parse_funcname_pattern(var, ep, value); + } } } @@@ -1520,17 -1510,22 +1520,22 @@@ static int reuse_worktree_file(const ch if (pos < 0) return 0; ce = active_cache[pos]; - if ((lstat(name, &st) < 0) || - !S_ISREG(st.st_mode) || /* careful! */ - ce_match_stat(ce, &st, 0) || - hashcmp(sha1, ce->sha1)) + + /* + * This is not the sha1 we are looking for, or + * unreusable because it is not a regular file. + */ + if (hashcmp(sha1, ce->sha1) || !S_ISREG(ce->ce_mode)) return 0; - /* we return 1 only when we can stat, it is a regular file, - * stat information matches, and sha1 recorded in the cache - * matches. I.e. we know the file in the work tree really is - * the same as the pair. + + /* + * If ce matches the file in the work tree, we can reuse it. */ - return 1; + if (ce_uptodate(ce) || + (!lstat(name, &st) && !ce_match_stat(ce, &st, 0))) + return 1; + + return 0; } static int populate_from_stdin(struct diff_filespec *s) diff --combined merge-recursive.c index 34e3167caf,bdf03b1f1f..dd52342539 --- a/merge-recursive.c +++ b/merge-recursive.c @@@ -333,7 -333,7 +333,7 @@@ static struct path_list *get_unmerged(v item->util = xcalloc(1, sizeof(struct stage_data)); } e = item->util; - e->stages[ce_stage(ce)].mode = ntohl(ce->ce_mode); + e->stages[ce_stage(ce)].mode = ce->ce_mode; hashcpy(e->stages[ce_stage(ce)].sha, ce->sha1); } @@@ -844,9 -844,8 +844,9 @@@ static int read_merge_config(const cha int namelen; if (!strcmp(var, "merge.default")) { - if (value) - default_ll_merge = strdup(value); + if (!value) + return config_error_nonbool(var); + default_ll_merge = strdup(value); return 0; } @@@ -879,14 -878,14 +879,14 @@@ if (!strcmp("name", ep)) { if (!value) - return error("%s: lacks value", var); + return config_error_nonbool(var); fn->description = strdup(value); return 0; } if (!strcmp("driver", ep)) { if (!value) - return error("%s: lacks value", var); + return config_error_nonbool(var); /* * merge..driver specifies the command line: * @@@ -909,7 -908,7 +909,7 @@@ if (!strcmp("recursive", ep)) { if (!value) - return error("%s: lacks value", var); + return config_error_nonbool(var); fn->recursive = strdup(value); return 0; } diff --combined t/t0000-basic.sh index cd0de506d2,9f84b8d3ac..92de088227 --- a/t/t0000-basic.sh +++ b/t/t0000-basic.sh @@@ -46,25 -46,13 +46,25 @@@ test_expect_success '.git/objects should have 3 subdirectories.' \ 'test $(wc -l < full-of-directories) = 3' +################################################################ +# Test harness +test_expect_success 'success is reported like this' ' + : +' +test_expect_failure 'pretend we have a known breakage' ' + false +' +test_expect_failure 'pretend we have fixed a known breakage' ' + : +' + ################################################################ # Basics of the basics # updating a new file without --add should fail. -test_expect_failure \ - 'git update-index without --add should fail adding.' \ - 'git update-index should-be-empty' +test_expect_success 'git update-index without --add should fail adding.' ' + ! git update-index should-be-empty +' # and with --add it should succeed, even if it is empty (it used to fail). test_expect_success \ @@@ -82,9 -70,9 +82,9 @@@ test_expect_success # Removing paths. rm -f should-be-empty full-of-directories -test_expect_failure \ - 'git update-index without --remove should fail removing.' \ - 'git update-index should-be-empty' +test_expect_success 'git update-index without --remove should fail removing.' ' + ! git update-index should-be-empty +' test_expect_success \ 'git update-index with --remove should be able to remove.' \ @@@ -216,9 -204,9 +216,9 @@@ test_expect_success 'put invalid objects into the index.' \ 'git update-index --index-info < badobjects' -test_expect_failure \ - 'writing this tree without --missing-ok.' \ - 'git write-tree' +test_expect_success 'writing this tree without --missing-ok.' ' + ! git write-tree +' test_expect_success \ 'writing this tree with --missing-ok.' \ @@@ -309,4 -297,24 +309,24 @@@ test_expect_success 'absolute path work test "$sym" = "$(test-absolute-path $dir2/syml)" ' + test_expect_success 'very long name in the index handled sanely' ' + + a=a && # 1 + a=$a$a$a$a$a$a$a$a$a$a$a$a$a$a$a$a && # 16 + a=$a$a$a$a$a$a$a$a$a$a$a$a$a$a$a$a && # 256 + a=$a$a$a$a$a$a$a$a$a$a$a$a$a$a$a$a && # 4096 + a=${a}q && + + >path4 && + git update-index --add path4 && + ( + git ls-files -s path4 | + sed -e "s/ .*/ /" | + tr -d "\012" + echo "$a" + ) | git update-index --index-info && + len=$(git ls-files "a*" | wc -c) && + test $len = 4098 + ' + test_done diff --combined wt-status.c index bfd1b0fcc6,27b946d552..f14022f2a9 --- a/wt-status.c +++ b/wt-status.c @@@ -217,19 -217,12 +217,12 @@@ static void wt_status_print_changed_cb( wt_status_print_trailer(s); } - static void wt_read_cache(struct wt_status *s) - { - discard_cache(); - read_cache_from(s->index_file); - } - static void wt_status_print_initial(struct wt_status *s) { int i; struct strbuf buf; strbuf_init(&buf, 0); - wt_read_cache(s); if (active_nr) { s->commitable = 1; wt_status_print_cached_header(s); @@@ -256,7 -249,6 +249,6 @@@ static void wt_status_print_updated(str rev.diffopt.detect_rename = 1; rev.diffopt.rename_limit = 100; rev.diffopt.break_opt = 0; - wt_read_cache(s); run_diff_index(&rev, 1); } @@@ -268,7 -260,6 +260,6 @@@ static void wt_status_print_changed(str rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK; rev.diffopt.format_callback = wt_status_print_changed_cb; rev.diffopt.format_callback_data = s; - wt_read_cache(s); run_diff_files(&rev, 0); } @@@ -335,7 -326,6 +326,6 @@@ static void wt_status_print_verbose(str setup_revisions(0, NULL, &rev, s->reference); rev.diffopt.output_format |= DIFF_FORMAT_PATCH; rev.diffopt.detect_rename = 1; - wt_read_cache(s); run_diff_index(&rev, 1); fflush(stdout); @@@ -402,8 -392,6 +392,8 @@@ int git_status_config(const char *k, co } if (!prefixcmp(k, "status.color.") || !prefixcmp(k, "color.status.")) { int slot = parse_status_slot(k, 13); + if (!v) + return config_error_nonbool(k); color_parse(v, k, wt_status_colors[slot]); return 0; }