#include "thread-utils.h"
#include "progress.h"
#include "sparse-index.h"
+#include "csum-file.h"
+#include "promisor-remote.h"
/* Mask for the name length in ce_flags in the on-disk index */
return mem_pool__ce_calloc(find_mem_pool(istate), len);
}
-struct cache_entry *make_empty_transient_cache_entry(size_t len)
+struct cache_entry *make_empty_transient_cache_entry(size_t len,
+ struct mem_pool *ce_mem_pool)
{
+ if (ce_mem_pool)
+ return mem_pool__ce_calloc(ce_mem_pool, len);
return xcalloc(1, cache_entry_size(len));
}
return ret;
}
-struct cache_entry *make_transient_cache_entry(unsigned int mode, const struct object_id *oid,
- const char *path, int stage)
+struct cache_entry *make_transient_cache_entry(unsigned int mode,
+ const struct object_id *oid,
+ const char *path,
+ int stage,
+ struct mem_pool *ce_mem_pool)
{
struct cache_entry *ce;
int len;
}
len = strlen(path);
- ce = make_empty_transient_cache_entry(len);
+ ce = make_empty_transient_cache_entry(len, ce_mem_pool);
oidcpy(&ce->oid, oid);
memcpy(ce->name, path, len);
}
}
if (protect_ntfs) {
-#ifdef GIT_WINDOWS_NATIVE
+#if defined GIT_WINDOWS_NATIVE || defined __CYGWIN__
if (c == '\\')
return PATH_INVALID;
#endif
int quiet = (flags & REFRESH_QUIET) != 0;
int not_new = (flags & REFRESH_IGNORE_MISSING) != 0;
int ignore_submodules = (flags & REFRESH_IGNORE_SUBMODULES) != 0;
+ int ignore_skip_worktree = (flags & REFRESH_IGNORE_SKIP_WORKTREE) != 0;
int first = 1;
int in_porcelain = (flags & REFRESH_IN_PORCELAIN);
unsigned int options = (CE_MATCH_REFRESH |
*/
preload_index(istate, pathspec, 0);
trace2_region_enter("index", "refresh", NULL);
- /* TODO: audit for interaction with sparse-index. */
- ensure_full_index(istate);
+
for (i = 0; i < istate->cache_nr; i++) {
struct cache_entry *ce, *new_entry;
int cache_errno = 0;
ce = istate->cache[i];
if (ignore_submodules && S_ISGITLINK(ce->ce_mode))
continue;
+ if (ignore_skip_worktree && ce_skip_worktree(ce))
+ continue;
+
+ /*
+ * If this entry is a sparse directory, then there isn't
+ * any stat() information to update. Ignore the entry.
+ */
+ if (S_ISSPARSEDIR(ce->ce_mode))
+ continue;
if (pathspec && !ce_path_match(istate, ce, pathspec, seen))
filtered = 1;
t2_sum_scan += t2_did_scan;
if (new_entry == ce)
continue;
- if (progress)
- display_progress(progress, i);
+ display_progress(progress, i);
if (!new_entry) {
const char *fmt;
trace2_data_intmax("index", NULL, "refresh/sum_lstat", t2_sum_lstat);
trace2_data_intmax("index", NULL, "refresh/sum_scan", t2_sum_scan);
trace2_region_leave("index", "refresh", NULL);
- if (progress) {
- display_progress(progress, istate->cache_nr);
- stop_progress(&progress);
- }
+ display_progress(progress, istate->cache_nr);
+ stop_progress(&progress);
trace_performance_leave("refresh index");
return has_errors;
}
ce->ce_flags = flags & ~CE_NAMEMASK;
ce->ce_namelen = len;
ce->index = 0;
- hashcpy(ce->oid.hash, ondisk->data);
+ oidread(&ce->oid, ondisk->data);
memcpy(ce->name, name, len);
ce->name[len] = '\0';
prepare_repo_settings(r);
- if (r->settings.core_untracked_cache == UNTRACKED_CACHE_REMOVE) {
+ switch (r->settings.core_untracked_cache) {
+ case UNTRACKED_CACHE_REMOVE:
remove_untracked_cache(istate);
- return;
- }
-
- if (r->settings.core_untracked_cache == UNTRACKED_CACHE_WRITE)
+ break;
+ case UNTRACKED_CACHE_WRITE:
add_untracked_cache(istate);
+ break;
+ case UNTRACKED_CACHE_KEEP:
+ /*
+ * Either an explicit "core.untrackedCache=keep", the
+ * default if "core.untrackedCache" isn't configured,
+ * or a fallback on an unknown "core.untrackedCache"
+ * value.
+ */
+ break;
+ }
}
static void tweak_split_index(struct index_state *istate)
mmap = xmmap_gently(NULL, mmap_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (mmap == MAP_FAILED)
- die_errno(_("%s: unable to map index file"), path);
+ die_errno(_("%s: unable to map index file%s"), path,
+ mmap_os_err());
close(fd);
hdr = (const struct cache_header *)mmap;
if (verify_hdr(hdr, mmap_size) < 0)
goto unmap;
- hashcpy(istate->oid.hash, (const unsigned char *)hdr + mmap_size - the_hash_algo->rawsz);
+ oidread(&istate->oid, (const unsigned char *)hdr + mmap_size - the_hash_algo->rawsz);
istate->version = ntohl(hdr->hdr_version);
istate->cache_nr = ntohl(hdr->hdr_entries);
istate->cache_alloc = alloc_nr(istate->cache_nr);
base_path = xstrfmt("%s/sharedindex.%s", gitdir, base_oid_hex);
trace2_region_enter_printf("index", "shared/do_read_index",
the_repository, "%s", base_path);
- ret = do_read_index(split_index->base, base_path, 1);
+ ret = do_read_index(split_index->base, base_path, 0);
trace2_region_leave_printf("index", "shared/do_read_index",
the_repository, "%s", base_path);
+ if (!ret) {
+ char *path_copy = xstrdup(path);
+ const char *base_path2 = xstrfmt("%s/sharedindex.%s",
+ dirname(path_copy),
+ base_oid_hex);
+ free(path_copy);
+ trace2_region_enter_printf("index", "shared/do_read_index",
+ the_repository, "%s", base_path2);
+ ret = do_read_index(split_index->base, base_path2, 1);
+ trace2_region_leave_printf("index", "shared/do_read_index",
+ the_repository, "%s", base_path2);
+ }
if (!oideq(&split_index->base_oid, &split_index->base->oid))
die(_("broken index, expect %s in %s, got %s"),
base_oid_hex, base_path,
opt.flags.exit_with_status = 1;
if (!sb)
opt.flags.quick = 1;
+ diff_setup_done(&opt);
do_diff_cache(&cmp, &opt);
diffcore_std(&opt);
for (i = 0; sb && i < diff_queued_diff.nr; i++) {
}
}
-#define WRITE_BUFFER_SIZE (128 * 1024)
-static unsigned char write_buffer[WRITE_BUFFER_SIZE];
-static unsigned long write_buffer_len;
-
-static int ce_write_flush(git_hash_ctx *context, int fd)
+static int write_index_ext_header(struct hashfile *f,
+ git_hash_ctx *eoie_f,
+ unsigned int ext,
+ unsigned int sz)
{
- unsigned int buffered = write_buffer_len;
- if (buffered) {
- the_hash_algo->update_fn(context, write_buffer, buffered);
- if (write_in_full(fd, write_buffer, buffered) < 0)
- return -1;
- write_buffer_len = 0;
- }
- return 0;
-}
+ hashwrite_be32(f, ext);
+ hashwrite_be32(f, sz);
-static int ce_write(git_hash_ctx *context, int fd, void *data, unsigned int len)
-{
- while (len) {
- unsigned int buffered = write_buffer_len;
- unsigned int partial = WRITE_BUFFER_SIZE - buffered;
- if (partial > len)
- partial = len;
- memcpy(write_buffer + buffered, data, partial);
- buffered += partial;
- if (buffered == WRITE_BUFFER_SIZE) {
- write_buffer_len = buffered;
- if (ce_write_flush(context, fd))
- return -1;
- buffered = 0;
- }
- write_buffer_len = buffered;
- len -= partial;
- data = (char *) data + partial;
+ if (eoie_f) {
+ ext = htonl(ext);
+ sz = htonl(sz);
+ the_hash_algo->update_fn(eoie_f, &ext, sizeof(ext));
+ the_hash_algo->update_fn(eoie_f, &sz, sizeof(sz));
}
return 0;
}
-static int write_index_ext_header(git_hash_ctx *context, git_hash_ctx *eoie_context,
- int fd, unsigned int ext, unsigned int sz)
-{
- ext = htonl(ext);
- sz = htonl(sz);
- if (eoie_context) {
- the_hash_algo->update_fn(eoie_context, &ext, 4);
- the_hash_algo->update_fn(eoie_context, &sz, 4);
- }
- return ((ce_write(context, fd, &ext, 4) < 0) ||
- (ce_write(context, fd, &sz, 4) < 0)) ? -1 : 0;
-}
-
-static int ce_flush(git_hash_ctx *context, int fd, unsigned char *hash)
-{
- unsigned int left = write_buffer_len;
-
- if (left) {
- write_buffer_len = 0;
- the_hash_algo->update_fn(context, write_buffer, left);
- }
-
- /* Flush first if not enough space for hash signature */
- if (left + the_hash_algo->rawsz > WRITE_BUFFER_SIZE) {
- if (write_in_full(fd, write_buffer, left) < 0)
- return -1;
- left = 0;
- }
-
- /* Append the hash signature at the end */
- the_hash_algo->final_fn(write_buffer + left, context);
- hashcpy(hash, write_buffer + left);
- left += the_hash_algo->rawsz;
- return (write_in_full(fd, write_buffer, left) < 0) ? -1 : 0;
-}
-
static void ce_smudge_racily_clean_entry(struct index_state *istate,
struct cache_entry *ce)
{
}
}
-static int ce_write_entry(git_hash_ctx *c, int fd, struct cache_entry *ce,
+static int ce_write_entry(struct hashfile *f, struct cache_entry *ce,
struct strbuf *previous_name, struct ondisk_cache_entry *ondisk)
{
int size;
- int result;
unsigned int saved_namelen;
int stripped_name = 0;
static unsigned char padding[8] = { 0x00 };
if (!previous_name) {
int len = ce_namelen(ce);
copy_cache_entry_to_ondisk(ondisk, ce);
- result = ce_write(c, fd, ondisk, size);
- if (!result)
- result = ce_write(c, fd, ce->name, len);
- if (!result)
- result = ce_write(c, fd, padding, align_padding_size(size, len));
+ hashwrite(f, ondisk, size);
+ hashwrite(f, ce->name, len);
+ hashwrite(f, padding, align_padding_size(size, len));
} else {
int common, to_remove, prefix_size;
unsigned char to_remove_vi[16];
prefix_size = encode_varint(to_remove, to_remove_vi);
copy_cache_entry_to_ondisk(ondisk, ce);
- result = ce_write(c, fd, ondisk, size);
- if (!result)
- result = ce_write(c, fd, to_remove_vi, prefix_size);
- if (!result)
- result = ce_write(c, fd, ce->name + common, ce_namelen(ce) - common);
- if (!result)
- result = ce_write(c, fd, padding, 1);
+ hashwrite(f, ondisk, size);
+ hashwrite(f, to_remove_vi, prefix_size);
+ hashwrite(f, ce->name + common, ce_namelen(ce) - common);
+ hashwrite(f, padding, 1);
strbuf_splice(previous_name, common, to_remove,
ce->name + common, ce_namelen(ce) - common);
ce->ce_flags &= ~CE_STRIP_NAME;
}
- return result;
+ return 0;
}
/*
int strip_extensions)
{
uint64_t start = getnanotime();
- int newfd = tempfile->fd;
- git_hash_ctx c, eoie_c;
+ struct hashfile *f;
+ git_hash_ctx *eoie_c = NULL;
struct cache_header hdr;
int i, err = 0, removed, extended, hdr_version;
struct cache_entry **cache = istate->cache;
struct index_entry_offset_table *ieot = NULL;
int nr, nr_threads;
+ f = hashfd(tempfile->fd, tempfile->filename.buf);
+
for (i = removed = extended = 0; i < entries; i++) {
if (cache[i]->ce_flags & CE_REMOVE)
removed++;
}
}
- if (!istate->version) {
+ if (!istate->version)
istate->version = get_index_format_default(the_repository);
- if (git_env_bool("GIT_TEST_SPLIT_INDEX", 0))
- init_split_index(istate);
- }
/* demote version 3 to version 2 when the latter suffices */
if (istate->version == 3 || istate->version == 2)
hdr.hdr_version = htonl(hdr_version);
hdr.hdr_entries = htonl(entries - removed);
- the_hash_algo->init_fn(&c);
- if (ce_write(&c, newfd, &hdr, sizeof(hdr)) < 0)
- return -1;
+ hashwrite(f, &hdr, sizeof(hdr));
if (!HAVE_THREADS || git_config_get_index_threads(&nr_threads))
nr_threads = 1;
}
}
- offset = lseek(newfd, 0, SEEK_CUR);
- if (offset < 0) {
- free(ieot);
- return -1;
- }
- offset += write_buffer_len;
+ offset = hashfile_total(f);
+
nr = 0;
previous_name = (hdr_version == 4) ? &previous_name_buf : NULL;
if (previous_name)
previous_name->buf[0] = 0;
nr = 0;
- offset = lseek(newfd, 0, SEEK_CUR);
- if (offset < 0) {
- free(ieot);
- return -1;
- }
- offset += write_buffer_len;
+
+ offset = hashfile_total(f);
}
- if (ce_write_entry(&c, newfd, ce, previous_name, (struct ondisk_cache_entry *)&ondisk) < 0)
+ if (ce_write_entry(f, ce, previous_name, (struct ondisk_cache_entry *)&ondisk) < 0)
err = -1;
if (err)
return err;
}
- /* Write extension data here */
- offset = lseek(newfd, 0, SEEK_CUR);
- if (offset < 0) {
- free(ieot);
- return -1;
+ offset = hashfile_total(f);
+
+ /*
+ * The extension headers must be hashed on their own for the
+ * EOIE extension. Create a hashfile here to compute that hash.
+ */
+ if (offset && record_eoie()) {
+ CALLOC_ARRAY(eoie_c, 1);
+ the_hash_algo->init_fn(eoie_c);
}
- offset += write_buffer_len;
- the_hash_algo->init_fn(&eoie_c);
/*
* Lets write out CACHE_EXT_INDEXENTRYOFFSETTABLE first so that we
struct strbuf sb = STRBUF_INIT;
write_ieot_extension(&sb, ieot);
- err = write_index_ext_header(&c, &eoie_c, newfd, CACHE_EXT_INDEXENTRYOFFSETTABLE, sb.len) < 0
- || ce_write(&c, newfd, sb.buf, sb.len) < 0;
+ err = write_index_ext_header(f, eoie_c, CACHE_EXT_INDEXENTRYOFFSETTABLE, sb.len) < 0;
+ hashwrite(f, sb.buf, sb.len);
strbuf_release(&sb);
free(ieot);
if (err)
struct strbuf sb = STRBUF_INIT;
err = write_link_extension(&sb, istate) < 0 ||
- write_index_ext_header(&c, &eoie_c, newfd, CACHE_EXT_LINK,
- sb.len) < 0 ||
- ce_write(&c, newfd, sb.buf, sb.len) < 0;
+ write_index_ext_header(f, eoie_c, CACHE_EXT_LINK,
+ sb.len) < 0;
+ hashwrite(f, sb.buf, sb.len);
strbuf_release(&sb);
if (err)
return -1;
struct strbuf sb = STRBUF_INIT;
cache_tree_write(&sb, istate->cache_tree);
- err = write_index_ext_header(&c, &eoie_c, newfd, CACHE_EXT_TREE, sb.len) < 0
- || ce_write(&c, newfd, sb.buf, sb.len) < 0;
+ err = write_index_ext_header(f, eoie_c, CACHE_EXT_TREE, sb.len) < 0;
+ hashwrite(f, sb.buf, sb.len);
strbuf_release(&sb);
if (err)
return -1;
struct strbuf sb = STRBUF_INIT;
resolve_undo_write(&sb, istate->resolve_undo);
- err = write_index_ext_header(&c, &eoie_c, newfd, CACHE_EXT_RESOLVE_UNDO,
- sb.len) < 0
- || ce_write(&c, newfd, sb.buf, sb.len) < 0;
+ err = write_index_ext_header(f, eoie_c, CACHE_EXT_RESOLVE_UNDO,
+ sb.len) < 0;
+ hashwrite(f, sb.buf, sb.len);
strbuf_release(&sb);
if (err)
return -1;
struct strbuf sb = STRBUF_INIT;
write_untracked_extension(&sb, istate->untracked);
- err = write_index_ext_header(&c, &eoie_c, newfd, CACHE_EXT_UNTRACKED,
- sb.len) < 0 ||
- ce_write(&c, newfd, sb.buf, sb.len) < 0;
+ err = write_index_ext_header(f, eoie_c, CACHE_EXT_UNTRACKED,
+ sb.len) < 0;
+ hashwrite(f, sb.buf, sb.len);
strbuf_release(&sb);
if (err)
return -1;
struct strbuf sb = STRBUF_INIT;
write_fsmonitor_extension(&sb, istate);
- err = write_index_ext_header(&c, &eoie_c, newfd, CACHE_EXT_FSMONITOR, sb.len) < 0
- || ce_write(&c, newfd, sb.buf, sb.len) < 0;
+ err = write_index_ext_header(f, eoie_c, CACHE_EXT_FSMONITOR, sb.len) < 0;
+ hashwrite(f, sb.buf, sb.len);
strbuf_release(&sb);
if (err)
return -1;
}
if (istate->sparse_index) {
- if (write_index_ext_header(&c, &eoie_c, newfd, CACHE_EXT_SPARSE_DIRECTORIES, 0) < 0)
+ if (write_index_ext_header(f, eoie_c, CACHE_EXT_SPARSE_DIRECTORIES, 0) < 0)
return -1;
}
* read. Write it out regardless of the strip_extensions parameter as we need it
* when loading the shared index.
*/
- if (offset && record_eoie()) {
+ if (eoie_c) {
struct strbuf sb = STRBUF_INIT;
- write_eoie_extension(&sb, &eoie_c, offset);
- err = write_index_ext_header(&c, NULL, newfd, CACHE_EXT_ENDOFINDEXENTRIES, sb.len) < 0
- || ce_write(&c, newfd, sb.buf, sb.len) < 0;
+ write_eoie_extension(&sb, eoie_c, offset);
+ err = write_index_ext_header(f, NULL, CACHE_EXT_ENDOFINDEXENTRIES, sb.len) < 0;
+ hashwrite(f, sb.buf, sb.len);
strbuf_release(&sb);
if (err)
return -1;
}
- if (ce_flush(&c, newfd, istate->oid.hash))
- return -1;
+ finalize_hashfile(f, istate->oid.hash, CSUM_HASH_IN_STREAM);
if (close_tempfile_gently(tempfile)) {
error(_("could not close '%s'"), get_tempfile_path(tempfile));
return -1;
int ret;
int was_full = !istate->sparse_index;
- ret = convert_to_sparse(istate);
+ ret = convert_to_sparse(istate, 0);
if (ret) {
warning(_("failed to convert to a sparse-index"));
int ret, was_full = !istate->sparse_index;
move_cache_to_base_index(istate);
- convert_to_sparse(istate);
+ convert_to_sparse(istate, 0);
trace2_region_enter_printf("index", "shared/do_write_index",
the_repository, "%s", get_tempfile_path(*temp));
int write_locked_index(struct index_state *istate, struct lock_file *lock,
unsigned flags)
{
- int new_shared_index, ret;
+ int new_shared_index, ret, test_split_index_env;
struct split_index *si = istate->split_index;
if (git_env_bool("GIT_TEST_CHECK_CACHE_TREE", 0))
if (istate->fsmonitor_last_update)
fill_fsmonitor_bitmap(istate);
- if (!si || alternate_index_output ||
+ test_split_index_env = git_env_bool("GIT_TEST_SPLIT_INDEX", 0);
+
+ if ((!si && !test_split_index_env) ||
+ alternate_index_output ||
(istate->cache_changed & ~EXTMASK)) {
if (si)
oidclr(&si->base_oid);
goto out;
}
- if (git_env_bool("GIT_TEST_SPLIT_INDEX", 0)) {
- int v = si->base_oid.hash[0];
- if ((v & 15) < 6)
+ if (test_split_index_env) {
+ if (!si) {
+ si = init_split_index(istate);
istate->cache_changed |= SPLIT_INDEX_ORDERED;
+ } else {
+ int v = si->base_oid.hash[0];
+ if ((v & 15) < 6)
+ istate->cache_changed |= SPLIT_INDEX_ORDERED;
+ }
}
if (too_many_not_shared_entries(istate))
istate->cache_changed |= SPLIT_INDEX_ORDERED;
strbuf_add(sb, &buffer, sizeof(uint32_t));
}
}
+
+void prefetch_cache_entries(const struct index_state *istate,
+ must_prefetch_predicate must_prefetch)
+{
+ int i;
+ struct oid_array to_fetch = OID_ARRAY_INIT;
+
+ for (i = 0; i < istate->cache_nr; i++) {
+ struct cache_entry *ce = istate->cache[i];
+
+ if (S_ISGITLINK(ce->ce_mode) || !must_prefetch(ce))
+ continue;
+ if (!oid_object_info_extended(the_repository, &ce->oid,
+ NULL,
+ OBJECT_INFO_FOR_PREFETCH))
+ continue;
+ oid_array_append(&to_fetch, &ce->oid);
+ }
+ promisor_remote_get_direct(the_repository,
+ to_fetch.oid, to_fetch.nr);
+ oid_array_clear(&to_fetch);
+}