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:
Junio C Hamano
2017-03-17 13:50:23 -07:00
11 changed files with 540 additions and 131 deletions

View File

@ -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;
}
/*