Merge branch 'cc/split-index-config'
The experimental "split index" feature has gained a few configuration variables to make it easier to use. * cc/split-index-config: (22 commits) Documentation/git-update-index: explain splitIndex.* Documentation/config: add splitIndex.sharedIndexExpire read-cache: use freshen_shared_index() in read_index_from() read-cache: refactor read_index_from() t1700: test shared index file expiration read-cache: unlink old sharedindex files config: add git_config_get_expiry() from gc.c read-cache: touch shared index files when used sha1_file: make check_and_freshen_file() non static Documentation/config: add splitIndex.maxPercentChange t1700: add tests for splitIndex.maxPercentChange read-cache: regenerate shared index if necessary config: add git_config_get_max_percent_split_change() Documentation/git-update-index: talk about core.splitIndex config var Documentation/config: add information for core.splitIndex t1700: add tests for core.splitIndex update-index: warn in case of split-index incoherency read-cache: add and then use tweak_split_index() split-index: add {add,remove}_split_index() functions config: add git_config_get_split_index() ...
This commit is contained in:
157
read-cache.c
157
read-cache.c
@ -1558,10 +1558,27 @@ static void tweak_untracked_cache(struct index_state *istate)
|
||||
}
|
||||
}
|
||||
|
||||
static void tweak_split_index(struct index_state *istate)
|
||||
{
|
||||
switch (git_config_get_split_index()) {
|
||||
case -1: /* unset: do nothing */
|
||||
break;
|
||||
case 0: /* false */
|
||||
remove_split_index(istate);
|
||||
break;
|
||||
case 1: /* true */
|
||||
add_split_index(istate);
|
||||
break;
|
||||
default: /* unknown value: do nothing */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void post_read_index_from(struct index_state *istate)
|
||||
{
|
||||
check_ce_order(istate);
|
||||
tweak_untracked_cache(istate);
|
||||
tweak_split_index(istate);
|
||||
}
|
||||
|
||||
/* remember to discard_cache() before reading a different cache! */
|
||||
@ -1657,10 +1674,25 @@ unmap:
|
||||
die("index file corrupt");
|
||||
}
|
||||
|
||||
/*
|
||||
* Signal that the shared index is used by updating its mtime.
|
||||
*
|
||||
* This way, shared index can be removed if they have not been used
|
||||
* for some time.
|
||||
*/
|
||||
static void freshen_shared_index(char *base_sha1_hex, int warn)
|
||||
{
|
||||
const char *shared_index = git_path("sharedindex.%s", base_sha1_hex);
|
||||
if (!check_and_freshen_file(shared_index, 1) && warn)
|
||||
warning("could not freshen shared index '%s'", shared_index);
|
||||
}
|
||||
|
||||
int read_index_from(struct index_state *istate, const char *path)
|
||||
{
|
||||
struct split_index *split_index;
|
||||
int ret;
|
||||
char *base_sha1_hex;
|
||||
const char *base_path;
|
||||
|
||||
/* istate->initialized covers both .git/index and .git/sharedindex.xxx */
|
||||
if (istate->initialized)
|
||||
@ -1678,15 +1710,16 @@ int read_index_from(struct index_state *istate, const char *path)
|
||||
discard_index(split_index->base);
|
||||
else
|
||||
split_index->base = xcalloc(1, sizeof(*split_index->base));
|
||||
ret = do_read_index(split_index->base,
|
||||
git_path("sharedindex.%s",
|
||||
sha1_to_hex(split_index->base_sha1)), 1);
|
||||
|
||||
base_sha1_hex = sha1_to_hex(split_index->base_sha1);
|
||||
base_path = git_path("sharedindex.%s", base_sha1_hex);
|
||||
ret = do_read_index(split_index->base, base_path, 1);
|
||||
if (hashcmp(split_index->base_sha1, split_index->base->sha1))
|
||||
die("broken index, expect %s in %s, got %s",
|
||||
sha1_to_hex(split_index->base_sha1),
|
||||
git_path("sharedindex.%s",
|
||||
sha1_to_hex(split_index->base_sha1)),
|
||||
base_sha1_hex, base_path,
|
||||
sha1_to_hex(split_index->base->sha1));
|
||||
|
||||
freshen_shared_index(base_sha1_hex, 0);
|
||||
merge_base_index(istate);
|
||||
post_read_index_from(istate);
|
||||
return ret;
|
||||
@ -2169,6 +2202,65 @@ static int write_split_index(struct index_state *istate,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const char *shared_index_expire = "2.weeks.ago";
|
||||
|
||||
static unsigned long get_shared_index_expire_date(void)
|
||||
{
|
||||
static unsigned long shared_index_expire_date;
|
||||
static int shared_index_expire_date_prepared;
|
||||
|
||||
if (!shared_index_expire_date_prepared) {
|
||||
git_config_get_expiry("splitindex.sharedindexexpire",
|
||||
&shared_index_expire);
|
||||
shared_index_expire_date = approxidate(shared_index_expire);
|
||||
shared_index_expire_date_prepared = 1;
|
||||
}
|
||||
|
||||
return shared_index_expire_date;
|
||||
}
|
||||
|
||||
static int should_delete_shared_index(const char *shared_index_path)
|
||||
{
|
||||
struct stat st;
|
||||
unsigned long expiration;
|
||||
|
||||
/* Check timestamp */
|
||||
expiration = get_shared_index_expire_date();
|
||||
if (!expiration)
|
||||
return 0;
|
||||
if (stat(shared_index_path, &st))
|
||||
return error_errno(_("could not stat '%s"), shared_index_path);
|
||||
if (st.st_mtime > expiration)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int clean_shared_index_files(const char *current_hex)
|
||||
{
|
||||
struct dirent *de;
|
||||
DIR *dir = opendir(get_git_dir());
|
||||
|
||||
if (!dir)
|
||||
return error_errno(_("unable to open git dir: %s"), get_git_dir());
|
||||
|
||||
while ((de = readdir(dir)) != NULL) {
|
||||
const char *sha1_hex;
|
||||
const char *shared_index_path;
|
||||
if (!skip_prefix(de->d_name, "sharedindex.", &sha1_hex))
|
||||
continue;
|
||||
if (!strcmp(sha1_hex, current_hex))
|
||||
continue;
|
||||
shared_index_path = git_path("%s", de->d_name);
|
||||
if (should_delete_shared_index(shared_index_path) > 0 &&
|
||||
unlink(shared_index_path))
|
||||
warning_errno(_("unable to unlink: %s"), shared_index_path);
|
||||
}
|
||||
closedir(dir);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct tempfile temporary_sharedindex;
|
||||
|
||||
static int write_shared_index(struct index_state *istate,
|
||||
@ -2190,14 +2282,48 @@ static int write_shared_index(struct index_state *istate,
|
||||
}
|
||||
ret = rename_tempfile(&temporary_sharedindex,
|
||||
git_path("sharedindex.%s", sha1_to_hex(si->base->sha1)));
|
||||
if (!ret)
|
||||
if (!ret) {
|
||||
hashcpy(si->base_sha1, si->base->sha1);
|
||||
clean_shared_index_files(sha1_to_hex(si->base->sha1));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const int default_max_percent_split_change = 20;
|
||||
|
||||
static int too_many_not_shared_entries(struct index_state *istate)
|
||||
{
|
||||
int i, not_shared = 0;
|
||||
int max_split = git_config_get_max_percent_split_change();
|
||||
|
||||
switch (max_split) {
|
||||
case -1:
|
||||
/* not or badly configured: use the default value */
|
||||
max_split = default_max_percent_split_change;
|
||||
break;
|
||||
case 0:
|
||||
return 1; /* 0% means always write a new shared index */
|
||||
case 100:
|
||||
return 0; /* 100% means never write a new shared index */
|
||||
default:
|
||||
break; /* just use the configured value */
|
||||
}
|
||||
|
||||
/* Count not shared entries */
|
||||
for (i = 0; i < istate->cache_nr; i++) {
|
||||
struct cache_entry *ce = istate->cache[i];
|
||||
if (!ce->index)
|
||||
not_shared++;
|
||||
}
|
||||
|
||||
return (int64_t)istate->cache_nr * max_split < (int64_t)not_shared * 100;
|
||||
}
|
||||
|
||||
int write_locked_index(struct index_state *istate, struct lock_file *lock,
|
||||
unsigned flags)
|
||||
{
|
||||
int new_shared_index, ret;
|
||||
struct split_index *si = istate->split_index;
|
||||
|
||||
if (!si || alternate_index_output ||
|
||||
@ -2212,13 +2338,24 @@ int write_locked_index(struct index_state *istate, struct lock_file *lock,
|
||||
if ((v & 15) < 6)
|
||||
istate->cache_changed |= SPLIT_INDEX_ORDERED;
|
||||
}
|
||||
if (istate->cache_changed & SPLIT_INDEX_ORDERED) {
|
||||
int ret = write_shared_index(istate, lock, flags);
|
||||
if (too_many_not_shared_entries(istate))
|
||||
istate->cache_changed |= SPLIT_INDEX_ORDERED;
|
||||
|
||||
new_shared_index = istate->cache_changed & SPLIT_INDEX_ORDERED;
|
||||
|
||||
if (new_shared_index) {
|
||||
ret = write_shared_index(istate, lock, flags);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return write_split_index(istate, lock, flags);
|
||||
ret = write_split_index(istate, lock, flags);
|
||||
|
||||
/* Freshen the shared index only if the split-index was written */
|
||||
if (!ret && !new_shared_index)
|
||||
freshen_shared_index(sha1_to_hex(si->base_sha1), 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user